refactor: Move all commands to their own files (#4946)

This commit is contained in:
pajlada
2023-11-08 18:57:09 +01:00
committed by GitHub
parent d40b0a6c1d
commit f89642ec66
41 changed files with 3405 additions and 2605 deletions
@@ -0,0 +1,258 @@
#include "controllers/commands/builtin/twitch/SendWhisper.hpp"
#include "Application.hpp"
#include "common/LinkParser.hpp"
#include "controllers/accounts/AccountController.hpp"
#include "controllers/commands/CommandContext.hpp"
#include "messages/Message.hpp"
#include "messages/MessageBuilder.hpp"
#include "messages/MessageElement.hpp"
#include "providers/irc/IrcChannel2.hpp"
#include "providers/irc/IrcServer.hpp"
#include "providers/twitch/api/Helix.hpp"
#include "providers/twitch/TwitchAccount.hpp"
#include "providers/twitch/TwitchIrcServer.hpp"
#include "singletons/Emotes.hpp"
#include "singletons/Settings.hpp"
#include "singletons/Theme.hpp"
#include "util/Twitch.hpp"
namespace {
using namespace chatterino;
QString formatWhisperError(HelixWhisperError error, const QString &message)
{
using Error = HelixWhisperError;
QString errorMessage = "Failed to send whisper - ";
switch (error)
{
case Error::NoVerifiedPhone: {
errorMessage += "Due to Twitch restrictions, you are now "
"required to have a verified phone number "
"to send whispers. You can add a phone "
"number in Twitch settings. "
"https://www.twitch.tv/settings/security";
};
break;
case Error::RecipientBlockedUser: {
errorMessage += "The recipient doesn't allow whispers "
"from strangers or you directly.";
};
break;
case Error::WhisperSelf: {
errorMessage += "You cannot whisper yourself.";
};
break;
case Error::Forwarded: {
errorMessage += message;
}
break;
case Error::Ratelimited: {
errorMessage += "You may only whisper a maximum of 40 "
"unique recipients per day. Within the "
"per day limit, you may whisper a "
"maximum of 3 whispers per second and "
"a maximum of 100 whispers per minute.";
}
break;
case Error::UserMissingScope: {
// TODO(pajlada): Phrase MISSING_REQUIRED_SCOPE
errorMessage += "Missing required scope. "
"Re-login with your "
"account and try again.";
}
break;
case Error::UserNotAuthorized: {
// TODO(pajlada): Phrase MISSING_PERMISSION
errorMessage += "You don't have permission to "
"perform that action.";
}
break;
case Error::Unknown: {
errorMessage += "An unknown error has occurred.";
}
break;
}
return errorMessage;
}
bool appendWhisperMessageWordsLocally(const QStringList &words)
{
auto *app = getApp();
MessageBuilder b;
b.emplace<TimestampElement>();
b.emplace<TextElement>(app->accounts->twitch.getCurrent()->getUserName(),
MessageElementFlag::Text, MessageColor::Text,
FontStyle::ChatMediumBold);
b.emplace<TextElement>("->", MessageElementFlag::Text,
getApp()->themes->messages.textColors.system);
b.emplace<TextElement>(words[1] + ":", MessageElementFlag::Text,
MessageColor::Text, FontStyle::ChatMediumBold);
const auto &acc = app->accounts->twitch.getCurrent();
const auto &accemotes = *acc->accessEmotes();
const auto &bttvemotes = app->twitch->getBttvEmotes();
const auto &ffzemotes = app->twitch->getFfzEmotes();
auto flags = MessageElementFlags();
auto emote = std::optional<EmotePtr>{};
for (int i = 2; i < words.length(); i++)
{
{ // Twitch emote
auto it = accemotes.emotes.find({words[i]});
if (it != accemotes.emotes.end())
{
b.emplace<EmoteElement>(it->second,
MessageElementFlag::TwitchEmote);
continue;
}
} // Twitch emote
{ // bttv/ffz emote
if ((emote = bttvemotes.emote({words[i]})))
{
flags = MessageElementFlag::BttvEmote;
}
else if ((emote = ffzemotes.emote({words[i]})))
{
flags = MessageElementFlag::FfzEmote;
}
if (emote)
{
b.emplace<EmoteElement>(*emote, flags);
continue;
}
} // bttv/ffz emote
{ // emoji/text
for (auto &variant : app->emotes->emojis.parse(words[i]))
{
constexpr const static struct {
void operator()(EmotePtr emote, MessageBuilder &b) const
{
b.emplace<EmoteElement>(emote,
MessageElementFlag::EmojiAll);
}
void operator()(const QString &string,
MessageBuilder &b) const
{
LinkParser parser(string);
if (parser.result())
{
b.addLink(*parser.result());
}
else
{
b.emplace<TextElement>(string,
MessageElementFlag::Text);
}
}
} visitor;
boost::apply_visitor(
[&b](auto &&arg) {
visitor(arg, b);
},
variant);
} // emoji/text
}
}
b->flags.set(MessageFlag::DoNotTriggerNotification);
b->flags.set(MessageFlag::Whisper);
auto messagexD = b.release();
app->twitch->whispersChannel->addMessage(messagexD);
auto overrideFlags = std::optional<MessageFlags>(messagexD->flags);
overrideFlags->set(MessageFlag::DoNotLog);
if (getSettings()->inlineWhispers &&
!(getSettings()->streamerModeSuppressInlineWhispers &&
isInStreamerMode()))
{
app->twitch->forEachChannel(
[&messagexD, overrideFlags](ChannelPtr _channel) {
_channel->addMessage(messagexD, overrideFlags);
});
}
return true;
}
} // namespace
namespace chatterino::commands {
QString sendWhisper(const CommandContext &ctx)
{
if (ctx.channel == nullptr)
{
return "";
}
if (ctx.words.size() < 3)
{
ctx.channel->addMessage(
makeSystemMessage("Usage: /w <username> <message>"));
return "";
}
auto currentUser = getApp()->accounts->twitch.getCurrent();
if (currentUser->isAnon())
{
ctx.channel->addMessage(
makeSystemMessage("You must be logged in to send a whisper!"));
return "";
}
auto target = ctx.words.at(1);
stripChannelName(target);
auto message = ctx.words.mid(2).join(' ');
if (ctx.channel->isTwitchChannel())
{
getHelix()->getUserByName(
target,
[channel{ctx.channel}, currentUser, target, message,
words{ctx.words}](const auto &targetUser) {
getHelix()->sendWhisper(
currentUser->getUserId(), targetUser.id, message,
[words] {
appendWhisperMessageWordsLocally(words);
},
[channel, target, targetUser](auto error, auto message) {
auto errorMessage = formatWhisperError(error, message);
channel->addMessage(makeSystemMessage(errorMessage));
});
},
[channel{ctx.channel}] {
channel->addMessage(
makeSystemMessage("No user matching that username."));
});
return "";
}
// we must be on IRC
auto *ircChannel = dynamic_cast<IrcChannel *>(ctx.channel.get());
if (ircChannel == nullptr)
{
// give up
return "";
}
auto *server = ircChannel->server();
server->sendWhisper(target, message);
return "";
}
} // namespace chatterino::commands