feat(eventsub): Add support for channel.moderate Warn (#5932)
* fix(eventsub): Be less strict with strings & vectors
String foo from `{"foo":null}` is now accepted, and returns an empty string
std::vector<String> foo from `{"foo":null}` is now accepted, and returns an empty array
This commit is contained in:
+1
-1
@@ -22,7 +22,7 @@
|
|||||||
- Bugfix: Fixed the reply button showing for inline whispers and announcements. (#5863)
|
- Bugfix: Fixed the reply button showing for inline whispers and announcements. (#5863)
|
||||||
- Bugfix: Fixed suspicious user treatment update messages not being searchable. (#5865)
|
- Bugfix: Fixed suspicious user treatment update messages not being searchable. (#5865)
|
||||||
- Bugfix: Ensure miniaudio backend exits even if it doesn't exit cleanly. (#5896)
|
- Bugfix: Ensure miniaudio backend exits even if it doesn't exit cleanly. (#5896)
|
||||||
- Dev: Add initial experimental EventSub support. (#5837, #5895, #5897, #5904, #5910, #5903, #5915, #5916, #5930, #5935)
|
- Dev: Add initial experimental EventSub support. (#5837, #5895, #5897, #5904, #5910, #5903, #5915, #5916, #5930, #5935, #5932)
|
||||||
- Dev: Highlight checks now use non-capturing groups for the boundaries. (#5784)
|
- Dev: Highlight checks now use non-capturing groups for the boundaries. (#5784)
|
||||||
- Dev: Removed unused PubSub whisper code. (#5898)
|
- Dev: Removed unused PubSub whisper code. (#5898)
|
||||||
- Dev: Updated Conan dependencies. (#5776)
|
- Dev: Updated Conan dependencies. (#5776)
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
{% if field.tag -%}
|
{% if field.tag -%}
|
||||||
static_assert(false && "JSON tag support is not implemented for vectors");
|
static_assert(false && "JSON tag support is not implemented for vectors");
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
std::vector<{{field.type_name}}> v{{field.name}};
|
||||||
const auto *jv{{field.name}} = root.if_contains("{{field.json_name}}");
|
const auto *jv{{field.name}} = root.if_contains("{{field.json_name}}");
|
||||||
if (jv{{field.name}} == nullptr)
|
if (jv{{field.name}} != nullptr && !jv{{field.name}}->is_null()) {
|
||||||
{
|
auto {{field.name}} = boost::json::try_value_to<std::vector<{{field.type_name}}>>(*jv{{field.name}});
|
||||||
{% include 'error-missing-field.tmpl' indent content %}
|
if ({{field.name}}.has_error())
|
||||||
|
{
|
||||||
|
{% include 'error-failed-to-deserialize.tmpl' indent content %}
|
||||||
|
} else {
|
||||||
|
v{{field.name}} = std::move({{field.name}}.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto {{field.name}} = boost::json::try_value_to<std::vector<{{field.type_name}}>>(*jv{{field.name}});
|
|
||||||
if ({{field.name}}.has_error())
|
|
||||||
{
|
|
||||||
{% include 'error-failed-to-deserialize.tmpl' indent content %}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
.{{field.name}} = std::move({{field.name}}.value()),
|
.{{field.name}} = std::move(v{{field.name}}),
|
||||||
|
|||||||
@@ -346,13 +346,13 @@ struct DenyUnbanRequest : public UnbanRequest {
|
|||||||
struct Warn {
|
struct Warn {
|
||||||
static constexpr std::string_view TAG = "warn";
|
static constexpr std::string_view TAG = "warn";
|
||||||
|
|
||||||
std::string userID;
|
String userID;
|
||||||
std::string userLogin;
|
String userLogin;
|
||||||
std::string userName;
|
String userName;
|
||||||
std::string reason;
|
String reason;
|
||||||
|
|
||||||
// TODO: Verify we handle null for this as an empty vector
|
// TODO: Verify we handle null for this as an empty vector
|
||||||
std::vector<std::string> chatRulesCited;
|
std::vector<String> chatRulesCited;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Clear {
|
struct Clear {
|
||||||
|
|||||||
@@ -175,23 +175,27 @@ boost::json::result_for<Emote, boost::json::value>::type tag_invoke(
|
|||||||
return ownerID.error();
|
return ownerID.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> vformat;
|
||||||
const auto *jvformat = root.if_contains("format");
|
const auto *jvformat = root.if_contains("format");
|
||||||
if (jvformat == nullptr)
|
if (jvformat != nullptr && !jvformat->is_null())
|
||||||
{
|
{
|
||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
auto format =
|
||||||
}
|
boost::json::try_value_to<std::vector<std::string>>(*jvformat);
|
||||||
auto format =
|
if (format.has_error())
|
||||||
boost::json::try_value_to<std::vector<std::string>>(*jvformat);
|
{
|
||||||
if (format.has_error())
|
return format.error();
|
||||||
{
|
}
|
||||||
return format.error();
|
else
|
||||||
|
{
|
||||||
|
vformat = std::move(format.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Emote{
|
return Emote{
|
||||||
.id = std::move(id.value()),
|
.id = std::move(id.value()),
|
||||||
.emoteSetID = std::move(emoteSetID.value()),
|
.emoteSetID = std::move(emoteSetID.value()),
|
||||||
.ownerID = std::move(ownerID.value()),
|
.ownerID = std::move(ownerID.value()),
|
||||||
.format = std::move(format.value()),
|
.format = std::move(vformat),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,21 +362,26 @@ boost::json::result_for<Message, boost::json::value>::type tag_invoke(
|
|||||||
return text.error();
|
return text.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<MessageFragment> vfragments;
|
||||||
const auto *jvfragments = root.if_contains("fragments");
|
const auto *jvfragments = root.if_contains("fragments");
|
||||||
if (jvfragments == nullptr)
|
if (jvfragments != nullptr && !jvfragments->is_null())
|
||||||
{
|
{
|
||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
auto fragments =
|
||||||
}
|
boost::json::try_value_to<std::vector<MessageFragment>>(
|
||||||
auto fragments =
|
*jvfragments);
|
||||||
boost::json::try_value_to<std::vector<MessageFragment>>(*jvfragments);
|
if (fragments.has_error())
|
||||||
if (fragments.has_error())
|
{
|
||||||
{
|
return fragments.error();
|
||||||
return fragments.error();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vfragments = std::move(fragments.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Message{
|
return Message{
|
||||||
.text = std::move(text.value()),
|
.text = std::move(text.value()),
|
||||||
.fragments = std::move(fragments.value()),
|
.fragments = std::move(vfragments),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,17 +672,20 @@ boost::json::result_for<Event, boost::json::value>::type tag_invoke(
|
|||||||
return color.error();
|
return color.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Badge> vbadges;
|
||||||
const auto *jvbadges = root.if_contains("badges");
|
const auto *jvbadges = root.if_contains("badges");
|
||||||
if (jvbadges == nullptr)
|
if (jvbadges != nullptr && !jvbadges->is_null())
|
||||||
{
|
{
|
||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
auto badges = boost::json::try_value_to<std::vector<Badge>>(*jvbadges);
|
||||||
|
if (badges.has_error())
|
||||||
|
{
|
||||||
|
return badges.error();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vbadges = std::move(badges.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto badges = boost::json::try_value_to<std::vector<Badge>>(*jvbadges);
|
|
||||||
if (badges.has_error())
|
|
||||||
{
|
|
||||||
return badges.error();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto *jvmessageID = root.if_contains("message_id");
|
const auto *jvmessageID = root.if_contains("message_id");
|
||||||
if (jvmessageID == nullptr)
|
if (jvmessageID == nullptr)
|
||||||
{
|
{
|
||||||
@@ -768,7 +780,7 @@ boost::json::result_for<Event, boost::json::value>::type tag_invoke(
|
|||||||
.chatterUserLogin = std::move(chatterUserLogin.value()),
|
.chatterUserLogin = std::move(chatterUserLogin.value()),
|
||||||
.chatterUserName = std::move(chatterUserName.value()),
|
.chatterUserName = std::move(chatterUserName.value()),
|
||||||
.color = std::move(color.value()),
|
.color = std::move(color.value()),
|
||||||
.badges = std::move(badges.value()),
|
.badges = std::move(vbadges),
|
||||||
.messageID = std::move(messageID.value()),
|
.messageID = std::move(messageID.value()),
|
||||||
.messageType = std::move(messageType.value()),
|
.messageType = std::move(messageType.value()),
|
||||||
.message = std::move(message.value()),
|
.message = std::move(message.value()),
|
||||||
|
|||||||
@@ -175,23 +175,27 @@ boost::json::result_for<Emote, boost::json::value>::type tag_invoke(
|
|||||||
return ownerID.error();
|
return ownerID.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> vformat;
|
||||||
const auto *jvformat = root.if_contains("format");
|
const auto *jvformat = root.if_contains("format");
|
||||||
if (jvformat == nullptr)
|
if (jvformat != nullptr && !jvformat->is_null())
|
||||||
{
|
{
|
||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
auto format =
|
||||||
}
|
boost::json::try_value_to<std::vector<std::string>>(*jvformat);
|
||||||
auto format =
|
if (format.has_error())
|
||||||
boost::json::try_value_to<std::vector<std::string>>(*jvformat);
|
{
|
||||||
if (format.has_error())
|
return format.error();
|
||||||
{
|
}
|
||||||
return format.error();
|
else
|
||||||
|
{
|
||||||
|
vformat = std::move(format.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Emote{
|
return Emote{
|
||||||
.id = std::move(id.value()),
|
.id = std::move(id.value()),
|
||||||
.emoteSetID = std::move(emoteSetID.value()),
|
.emoteSetID = std::move(emoteSetID.value()),
|
||||||
.ownerID = std::move(ownerID.value()),
|
.ownerID = std::move(ownerID.value()),
|
||||||
.format = std::move(format.value()),
|
.format = std::move(vformat),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1246,21 +1250,26 @@ boost::json::result_for<Message, boost::json::value>::type tag_invoke(
|
|||||||
return text.error();
|
return text.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<MessageFragment> vfragments;
|
||||||
const auto *jvfragments = root.if_contains("fragments");
|
const auto *jvfragments = root.if_contains("fragments");
|
||||||
if (jvfragments == nullptr)
|
if (jvfragments != nullptr && !jvfragments->is_null())
|
||||||
{
|
{
|
||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
auto fragments =
|
||||||
}
|
boost::json::try_value_to<std::vector<MessageFragment>>(
|
||||||
auto fragments =
|
*jvfragments);
|
||||||
boost::json::try_value_to<std::vector<MessageFragment>>(*jvfragments);
|
if (fragments.has_error())
|
||||||
if (fragments.has_error())
|
{
|
||||||
{
|
return fragments.error();
|
||||||
return fragments.error();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vfragments = std::move(fragments.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Message{
|
return Message{
|
||||||
.text = std::move(text.value()),
|
.text = std::move(text.value()),
|
||||||
.fragments = std::move(fragments.value()),
|
.fragments = std::move(vfragments),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1389,17 +1398,20 @@ boost::json::result_for<Event, boost::json::value>::type tag_invoke(
|
|||||||
return color.error();
|
return color.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Badge> vbadges;
|
||||||
const auto *jvbadges = root.if_contains("badges");
|
const auto *jvbadges = root.if_contains("badges");
|
||||||
if (jvbadges == nullptr)
|
if (jvbadges != nullptr && !jvbadges->is_null())
|
||||||
{
|
{
|
||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
auto badges = boost::json::try_value_to<std::vector<Badge>>(*jvbadges);
|
||||||
|
if (badges.has_error())
|
||||||
|
{
|
||||||
|
return badges.error();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vbadges = std::move(badges.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto badges = boost::json::try_value_to<std::vector<Badge>>(*jvbadges);
|
|
||||||
if (badges.has_error())
|
|
||||||
{
|
|
||||||
return badges.error();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto *jvsystemMessage = root.if_contains("system_message");
|
const auto *jvsystemMessage = root.if_contains("system_message");
|
||||||
if (jvsystemMessage == nullptr)
|
if (jvsystemMessage == nullptr)
|
||||||
{
|
{
|
||||||
@@ -1649,7 +1661,7 @@ boost::json::result_for<Event, boost::json::value>::type tag_invoke(
|
|||||||
.chatterUserName = std::move(chatterUserName.value()),
|
.chatterUserName = std::move(chatterUserName.value()),
|
||||||
.chatterIsAnonymous = chatterIsAnonymous.value(),
|
.chatterIsAnonymous = chatterIsAnonymous.value(),
|
||||||
.color = std::move(color.value()),
|
.color = std::move(color.value()),
|
||||||
.badges = std::move(badges.value()),
|
.badges = std::move(vbadges),
|
||||||
.systemMessage = std::move(systemMessage.value()),
|
.systemMessage = std::move(systemMessage.value()),
|
||||||
.messageID = std::move(messageID.value()),
|
.messageID = std::move(messageID.value()),
|
||||||
.message = std::move(message.value()),
|
.message = std::move(message.value()),
|
||||||
|
|||||||
@@ -858,17 +858,21 @@ boost::json::result_for<AutomodTerms, boost::json::value>::type tag_invoke(
|
|||||||
return list.error();
|
return list.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> vterms;
|
||||||
const auto *jvterms = root.if_contains("terms");
|
const auto *jvterms = root.if_contains("terms");
|
||||||
if (jvterms == nullptr)
|
if (jvterms != nullptr && !jvterms->is_null())
|
||||||
{
|
{
|
||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
auto terms =
|
||||||
|
boost::json::try_value_to<std::vector<std::string>>(*jvterms);
|
||||||
|
if (terms.has_error())
|
||||||
|
{
|
||||||
|
return terms.error();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vterms = std::move(terms.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto terms = boost::json::try_value_to<std::vector<std::string>>(*jvterms);
|
|
||||||
if (terms.has_error())
|
|
||||||
{
|
|
||||||
return terms.error();
|
|
||||||
}
|
|
||||||
|
|
||||||
static_assert(std::is_trivially_copyable_v<std::remove_reference_t<
|
static_assert(std::is_trivially_copyable_v<std::remove_reference_t<
|
||||||
decltype(std::declval<AutomodTerms>().fromAutomod)>>);
|
decltype(std::declval<AutomodTerms>().fromAutomod)>>);
|
||||||
const auto *jvfromAutomod = root.if_contains("from_automod");
|
const auto *jvfromAutomod = root.if_contains("from_automod");
|
||||||
@@ -887,7 +891,7 @@ boost::json::result_for<AutomodTerms, boost::json::value>::type tag_invoke(
|
|||||||
return AutomodTerms{
|
return AutomodTerms{
|
||||||
.action = std::move(action.value()),
|
.action = std::move(action.value()),
|
||||||
.list = std::move(list.value()),
|
.list = std::move(list.value()),
|
||||||
.terms = std::move(terms.value()),
|
.terms = std::move(vterms),
|
||||||
.fromAutomod = fromAutomod.value(),
|
.fromAutomod = fromAutomod.value(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1037,7 +1041,7 @@ boost::json::result_for<Warn, boost::json::value>::type tag_invoke(
|
|||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto userID = boost::json::try_value_to<std::string>(*jvuserID);
|
auto userID = boost::json::try_value_to<String>(*jvuserID);
|
||||||
|
|
||||||
if (userID.has_error())
|
if (userID.has_error())
|
||||||
{
|
{
|
||||||
@@ -1050,7 +1054,7 @@ boost::json::result_for<Warn, boost::json::value>::type tag_invoke(
|
|||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto userLogin = boost::json::try_value_to<std::string>(*jvuserLogin);
|
auto userLogin = boost::json::try_value_to<String>(*jvuserLogin);
|
||||||
|
|
||||||
if (userLogin.has_error())
|
if (userLogin.has_error())
|
||||||
{
|
{
|
||||||
@@ -1063,7 +1067,7 @@ boost::json::result_for<Warn, boost::json::value>::type tag_invoke(
|
|||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto userName = boost::json::try_value_to<std::string>(*jvuserName);
|
auto userName = boost::json::try_value_to<String>(*jvuserName);
|
||||||
|
|
||||||
if (userName.has_error())
|
if (userName.has_error())
|
||||||
{
|
{
|
||||||
@@ -1076,23 +1080,27 @@ boost::json::result_for<Warn, boost::json::value>::type tag_invoke(
|
|||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto reason = boost::json::try_value_to<std::string>(*jvreason);
|
auto reason = boost::json::try_value_to<String>(*jvreason);
|
||||||
|
|
||||||
if (reason.has_error())
|
if (reason.has_error())
|
||||||
{
|
{
|
||||||
return reason.error();
|
return reason.error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<chatterino::eventsub::lib::String> vchatRulesCited;
|
||||||
const auto *jvchatRulesCited = root.if_contains("chat_rules_cited");
|
const auto *jvchatRulesCited = root.if_contains("chat_rules_cited");
|
||||||
if (jvchatRulesCited == nullptr)
|
if (jvchatRulesCited != nullptr && !jvchatRulesCited->is_null())
|
||||||
{
|
{
|
||||||
EVENTSUB_BAIL_HERE(error::Kind::FieldMissing);
|
auto chatRulesCited = boost::json::try_value_to<
|
||||||
}
|
std::vector<chatterino::eventsub::lib::String>>(*jvchatRulesCited);
|
||||||
auto chatRulesCited =
|
if (chatRulesCited.has_error())
|
||||||
boost::json::try_value_to<std::vector<std::string>>(*jvchatRulesCited);
|
{
|
||||||
if (chatRulesCited.has_error())
|
return chatRulesCited.error();
|
||||||
{
|
}
|
||||||
return chatRulesCited.error();
|
else
|
||||||
|
{
|
||||||
|
vchatRulesCited = std::move(chatRulesCited.value());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Warn{
|
return Warn{
|
||||||
@@ -1100,7 +1108,7 @@ boost::json::result_for<Warn, boost::json::value>::type tag_invoke(
|
|||||||
.userLogin = std::move(userLogin.value()),
|
.userLogin = std::move(userLogin.value()),
|
||||||
.userName = std::move(userName.value()),
|
.userName = std::move(userName.value()),
|
||||||
.reason = std::move(reason.value()),
|
.reason = std::move(reason.value()),
|
||||||
.chatRulesCited = std::move(chatRulesCited.value()),
|
.chatRulesCited = std::move(vchatRulesCited),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ boost::json::result_for<String, boost::json::value>::type tag_invoke(
|
|||||||
boost::json::try_value_to_tag<String> /*tag*/,
|
boost::json::try_value_to_tag<String> /*tag*/,
|
||||||
const boost::json::value &jvRoot)
|
const boost::json::value &jvRoot)
|
||||||
{
|
{
|
||||||
|
if (jvRoot.is_null())
|
||||||
|
{
|
||||||
|
// We treat null "strings" as empty strings
|
||||||
|
return String("");
|
||||||
|
}
|
||||||
|
|
||||||
auto v = boost::json::try_value_to<std::string>(jvRoot);
|
auto v = boost::json::try_value_to<std::string>(jvRoot);
|
||||||
if (v.has_error())
|
if (v.has_error())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -164,12 +164,12 @@ void Connection::onChannelModerate(
|
|||||||
const auto now = QDateTime::currentDateTime();
|
const auto now = QDateTime::currentDateTime();
|
||||||
|
|
||||||
std::visit(
|
std::visit(
|
||||||
[&](auto &&oAction) {
|
[&](auto &&action) {
|
||||||
using Action = std::remove_cvref_t<decltype(oAction)>;
|
using Action = std::remove_cvref_t<decltype(action)>;
|
||||||
if constexpr (std::is_same_v<
|
if constexpr (std::is_same_v<
|
||||||
Action, lib::payload::channel_moderate::v2::Vip>)
|
Action, lib::payload::channel_moderate::v2::Vip>)
|
||||||
{
|
{
|
||||||
auto msg = makeVipMessage(channel, now, payload.event, oAction);
|
auto msg = makeVipMessage(channel, now, payload.event, action);
|
||||||
runInGuiThread([channel, msg] {
|
runInGuiThread([channel, msg] {
|
||||||
channel->addMessage(msg, MessageContext::Original);
|
channel->addMessage(msg, MessageContext::Original);
|
||||||
});
|
});
|
||||||
@@ -179,7 +179,16 @@ void Connection::onChannelModerate(
|
|||||||
lib::payload::channel_moderate::v2::Unvip>)
|
lib::payload::channel_moderate::v2::Unvip>)
|
||||||
{
|
{
|
||||||
auto msg =
|
auto msg =
|
||||||
makeUnvipMessage(channel, now, payload.event, oAction);
|
makeUnvipMessage(channel, now, payload.event, action);
|
||||||
|
runInGuiThread([channel, msg] {
|
||||||
|
channel->addMessage(msg, MessageContext::Original);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<
|
||||||
|
Action,
|
||||||
|
lib::payload::channel_moderate::v2::Warn>)
|
||||||
|
{
|
||||||
|
auto msg = makeWarnMessage(channel, now, payload.event, action);
|
||||||
runInGuiThread([channel, msg] {
|
runInGuiThread([channel, msg] {
|
||||||
channel->addMessage(msg, MessageContext::Original);
|
channel->addMessage(msg, MessageContext::Original);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -78,4 +78,66 @@ MessagePtr makeUnvipMessage(
|
|||||||
return builder.release();
|
return builder.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessagePtr makeWarnMessage(
|
||||||
|
TwitchChannel *channel, const QDateTime &time,
|
||||||
|
const lib::payload::channel_moderate::v2::Event &event,
|
||||||
|
const lib::payload::channel_moderate::v2::Warn &action)
|
||||||
|
{
|
||||||
|
MessageBuilder builder;
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
|
||||||
|
builder.emplace<TimestampElement>();
|
||||||
|
builder->flags.set(MessageFlag::System);
|
||||||
|
builder->flags.set(MessageFlag::Timeout);
|
||||||
|
builder->loginName = event.moderatorUserLogin.qt();
|
||||||
|
|
||||||
|
builder.emplace<MentionElement>(
|
||||||
|
event.moderatorUserName.qt(), event.moderatorUserLogin.qt(),
|
||||||
|
MessageColor::System,
|
||||||
|
channel->getUserColor(event.moderatorUserLogin.qt()));
|
||||||
|
text.append(event.moderatorUserLogin.qt() + " ");
|
||||||
|
|
||||||
|
builder.emplaceSystemTextAndUpdate("has warned", text);
|
||||||
|
|
||||||
|
builder
|
||||||
|
.emplace<MentionElement>(action.userName.qt(), action.userLogin.qt(),
|
||||||
|
MessageColor::System,
|
||||||
|
channel->getUserColor(action.userLogin.qt()))
|
||||||
|
->setTrailingSpace(false);
|
||||||
|
text.append(action.userLogin.qt());
|
||||||
|
|
||||||
|
QStringList reasons;
|
||||||
|
|
||||||
|
if (!action.reason.qt().isEmpty())
|
||||||
|
{
|
||||||
|
reasons.append(action.reason.qt());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &rule : action.chatRulesCited)
|
||||||
|
{
|
||||||
|
if (!rule.qt().isEmpty())
|
||||||
|
{
|
||||||
|
reasons.append(rule.qt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reasons.isEmpty())
|
||||||
|
{
|
||||||
|
builder.emplaceSystemTextAndUpdate(".", text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.emplaceSystemTextAndUpdate(":", text);
|
||||||
|
builder.emplaceSystemTextAndUpdate(reasons.join(", "), text);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.message().messageText = text;
|
||||||
|
builder.message().searchText = text;
|
||||||
|
|
||||||
|
builder.message().serverReceivedTime = time;
|
||||||
|
|
||||||
|
return builder.release();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace chatterino::eventsub
|
} // namespace chatterino::eventsub
|
||||||
|
|||||||
@@ -20,4 +20,10 @@ MessagePtr makeUnvipMessage(
|
|||||||
const lib::payload::channel_moderate::v2::Event &event,
|
const lib::payload::channel_moderate::v2::Event &event,
|
||||||
const lib::payload::channel_moderate::v2::Unvip &action);
|
const lib::payload::channel_moderate::v2::Unvip &action);
|
||||||
|
|
||||||
|
/// <MODERATOR> has warned <USER>: <REASON>
|
||||||
|
MessagePtr makeWarnMessage(
|
||||||
|
TwitchChannel *channel, const QDateTime &time,
|
||||||
|
const lib::payload::channel_moderate::v2::Event &event,
|
||||||
|
const lib::payload::channel_moderate::v2::Warn &action);
|
||||||
|
|
||||||
} // namespace chatterino::eventsub
|
} // namespace chatterino::eventsub
|
||||||
|
|||||||
Reference in New Issue
Block a user