#![doc(alias = "mod")]
#![doc(alias = "chat_moderator_actions")]
use crate::{pubsub, types};
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(into = "String", try_from = "String")]
pub struct ChatModeratorActions {
pub user_id: u32,
pub channel_id: u32,
}
impl_de_ser!(
ChatModeratorActions,
"chat_moderator_actions",
user_id,
channel_id
);
impl pubsub::Topic for ChatModeratorActions {
#[cfg(feature = "twitch_oauth2")]
const SCOPE: &'static [twitch_oauth2::Scope] = &[twitch_oauth2::Scope::ChannelModerate];
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "allow_unknown_fields"), serde(deny_unknown_fields))]
#[non_exhaustive]
pub struct ModerationAction {
#[serde(deserialize_with = "pubsub::deserialize_default_from_null")]
pub args: Vec<String>,
pub created_by: types::UserName,
pub created_by_user_id: types::UserId,
pub from_automod: bool,
pub moderation_action: ModerationActionCommand,
pub msg_id: Option<String>,
pub target_user_id: types::UserId,
#[serde(rename = "type")]
pub type_: ModerationType,
#[doc(hidden)]
pub target_user_login: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "allow_unknown_fields"), serde(deny_unknown_fields))]
#[non_exhaustive]
pub struct ModeratorAdded {
pub channel_id: types::UserId,
pub target_user_id: types::UserId,
pub moderation_action: ModerationActionCommand,
pub target_user_login: types::UserName,
pub created_by_user_id: types::UserId,
pub created_by: types::UserName,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "allow_unknown_fields"), serde(deny_unknown_fields))]
#[serde(tag = "type", content = "data")]
#[non_exhaustive]
pub enum ChatModeratorActionsReply {
#[serde(rename = "moderation_action")]
ModerationAction(ModerationAction),
#[serde(rename = "moderator_added")]
ModeratorAdded(ModeratorAdded),
#[serde(rename = "deny_unban_request")]
DenyUnbanRequest(UnbanRequest),
#[serde(rename = "approve_unban_request")]
ApproveUnbanRequest(UnbanRequest),
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(not(feature = "allow_unknown_fields"), serde(deny_unknown_fields))]
#[non_exhaustive]
pub struct UnbanRequest {
pub created_by_id: types::UserId,
pub created_by_login: types::UserName,
pub moderation_action: ModerationActionCommand,
pub moderator_message: String,
pub target_user_id: types::UserId,
pub target_user_login: types::UserName,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ModerationActionCommand {
Delete,
Timeout,
Untimeout,
Mod,
Unmod,
ModifiedAutomodProperties,
Ban,
Unban,
AutomodRejected,
AddPermittedTerm,
DeletePermittedTerm,
AddBlockedTerm,
DeleteBlockedTerm,
ApproveAutomodMessage,
DeniedAutomodMessage,
Raid,
Slow,
#[serde(rename = "slowoff")]
SlowOff,
Followers,
#[serde(rename = "followersoff")]
FollowersOff,
Subscribers,
#[serde(rename = "subscribersoff")]
SubscribersOff,
#[serde(rename = "emoteonly")]
EmoteOnly,
#[serde(rename = "emoteonlyoff")]
EmoteOnlyOff,
Clear,
#[serde(rename = "r9kbeta")]
R9KBeta,
#[serde(rename = "r9kbetaoff")]
R9KBetaOff,
Vip,
Unvip,
Host,
Unhost,
#[serde(rename = "APPROVE_UNBAN_REQUEST")]
ApproveUnbanRequest,
#[serde(rename = "DENY_UNBAN_REQUEST")]
DenyUnbanRequest,
}
impl std::fmt::Display for ModerationActionCommand {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { self.serialize(f) }
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ModerationType {
ChatLoginModeration,
ChatChannelModeration,
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use super::super::{Response, TopicData};
use super::*;
#[test]
fn mod_action_delete() {
let source = r#"
{
"type": "MESSAGE",
"data": {
"topic": "chat_moderator_actions.27620241.27620241",
"message": "{\"type\":\"moderation_action\",\"data\":{\"type\":\"chat_login_moderation\",\"moderation_action\":\"delete\",\"args\":[\"tmo\",\"bop\",\"e513c02d-dca5-4480-9af5-e6078d954e42\"],\"created_by\":\"emilgardis\",\"created_by_user_id\":\"27620241\",\"msg_id\":\"\",\"target_user_id\":\"1234\",\"target_user_login\":\"\",\"from_automod\":false}}"
}
}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
#[test]
fn check_deser() {
use std::convert::TryInto as _;
let s = "chat_moderator_actions.1337.1234";
assert_eq!(
ChatModeratorActions {
user_id: 1337,
channel_id: 1234,
},
s.to_string().try_into().unwrap()
);
}
#[test]
fn check_ser() {
let s = "chat_moderator_actions.1337.1234";
let right: String = ChatModeratorActions {
user_id: 1337,
channel_id: 1234,
}
.into();
assert_eq!(s.to_string(), right);
}
#[test]
fn mod_action_timeout() {
let source = r#"{"type":"MESSAGE","data":{"topic":"chat_moderator_actions.27620241.27620241","message":"{\"type\":\"moderation_action\",\"data\":{\"type\":\"chat_login_moderation\",\"moderation_action\":\"timeout\",\"args\":[\"tmo\",\"1\",\"\"],\"created_by\":\"emilgardis\",\"created_by_user_id\":\"27620241\",\"msg_id\":\"\",\"target_user_id\":\"1234\",\"target_user_login\":\"\",\"from_automod\":false}}"}}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
#[test]
fn mod_add_moderator() {
let source = r#"{"type":"MESSAGE","data":{"topic":"chat_moderator_actions.27620241.27620241","message":"{\"type\":\"moderator_added\", \"data\":{\"channel_id\":\"27620241\",\"target_user_id\":\"19264788\",\"moderation_action\":\"mod\",\"target_user_login\":\"nightbot\",\"created_by_user_id\":\"27620241\",\"created_by\":\"emilgardis\"}}"}}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
#[test]
fn mod_add_moderator_no_user_id() {
let source = r#"{"type":"MESSAGE","data":{"topic":"chat_moderator_actions.27620241.27620241","message":"{\"type\":\"moderator_added\", \"data\":{\"channel_id\":\"27620241\",\"target_user_id\":\"19264788\",\"moderation_action\":\"mod\",\"target_user_login\":\"nightbot\",\"created_by_user_id\":\"27620241\",\"created_by\":\"emilgardis\"}}"}}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
#[test]
fn mod_automod() {
let source = r#"
{
"type": "MESSAGE",
"data": {
"topic": "chat_moderator_actions.27620241.27620241",
"message": "{\"type\":\"moderation_action\",\"data\":{\"type\":\"chat_channel_moderation\",\"moderation_action\":\"modified_automod_properties\",\"args\":null,\"created_by\":\"emilgardis\",\"created_by_user_id\":\"27620241\",\"msg_id\":\"\",\"target_user_id\":\"\",\"target_user_login\":\"\",\"from_automod\":false}}"
}
}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
#[test]
fn mod_automod_delete_blocked_term() {
let source = r#"
{
"type": "MESSAGE",
"data": {
"topic": "chat_moderator_actions.27620241.27620241",
"message": "{\"type\":\"moderation_action\",\"data\":{\"type\":\"chat_channel_moderation\",\"moderation_action\":\"delete_blocked_term\",\"args\":[\"cunt dick pussy vagina\"],\"created_by\":\"emilgardis\",\"created_by_user_id\":\"27620241\",\"msg_id\":\"\",\"target_user_id\":\"\",\"target_user_login\":\"\",\"from_automod\":false}}"
}
}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
#[test]
fn mod_slowmode() {
let source = r#"
{
"type": "MESSAGE",
"data": {
"topic": "chat_moderator_actions.27620241.27620241",
"message": "{\"type\":\"moderation_action\",\"data\":{\"type\":\"chat_channel_moderation\",\"moderation_action\":\"slow\",\"args\":[\"5\"],\"created_by\":\"tmo\",\"created_by_user_id\":\"1234\",\"msg_id\":\"\",\"target_user_id\":\"\",\"target_user_login\":\"\",\"from_automod\":false}}"
}
}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
#[test]
#[cfg(feature = "allow_unknown_fields")]
fn allow_unknown() {
let source = r#"
{
"type": "MESSAGE",
"data": {
"topic": "chat_moderator_actions.27620241.27620241",
"message": "{\"type\":\"moderation_action\",\"data\":{\"type\":\"chat_channel_moderation\",\"moderation_action\":\"slow\",\"unknownfield\": 1,\"args\":[\"5\"],\"created_by\":\"tmo\",\"created_by_user_id\":\"1234\",\"msg_id\":\"\",\"target_user_id\":\"\",\"target_user_login\":\"\",\"from_automod\":false}}"
}
}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
#[test]
fn deny_unban_request() {
let source = r#"
{
"type": "MESSAGE",
"data": {
"topic": "chat_moderator_actions.80525799.80525799",
"message": "{\"type\":\"deny_unban_request\",\"data\":{\"moderation_action\":\"DENY_UNBAN_REQUEST\",\"created_by_id\":\"27620241\",\"created_by_login\":\"emilgardis\",\"moderator_message\":\"ok\",\"target_user_id\":\"465894629\",\"target_user_login\":\"emil_the_impostor\"}}"
}
}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
#[test]
fn approve_unban_request() {
let source = r#"
{
"type": "MESSAGE",
"data": {
"topic": "chat_moderator_actions.80525799.80525799",
"message": "{\"type\":\"approve_unban_request\",\"data\":{\"moderation_action\":\"APPROVE_UNBAN_REQUEST\",\"created_by_id\":\"27620241\",\"created_by_login\":\"emilgardis\",\"moderator_message\":\"ok\",\"target_user_id\":\"465894629\",\"target_user_login\":\"emil_the_impostor\"}}"
}
}"#;
let actual = dbg!(Response::parse(source).unwrap());
assert!(matches!(
actual,
Response::Message {
data: TopicData::ChatModeratorActions { .. },
}
));
}
}