use core::str;
use serde::{Deserialize, Serialize};
use serde_repr::Deserialize_repr;
use crate::models::{
ActionRow, Application, Attachment, Channel, Embed, Emoji, Interaction, Role,
RoleSubscriptionData, Snowflake, StickerItem, User,
};
#[derive(Debug, Deserialize)]
pub struct Message {
pub id: Snowflake,
pub channel_id: Snowflake,
pub author: User,
pub content: String,
pub timestamp: String,
pub edited_timestamp: Option<String>,
pub tts: bool,
pub mention_everyone: bool,
pub mentions: Vec<User>,
pub mention_roles: Vec<Role>,
pub mention_channels: Option<Vec<ChannelMention>>,
pub attachments: Vec<Attachment>,
pub embeds: Vec<Embed>,
pub reactions: Option<Vec<Reaction>>,
pub pinned: bool,
pub webhook_id: Option<Snowflake>,
#[serde(rename = "type")]
pub t: MessageType,
pub activity: Option<MessageActivity>,
pub application: Option<Application>,
pub application_id: Option<Snowflake>,
pub message_reference: Option<MessageReference>,
pub flags: Option<MessageFlags>,
pub interaction: Option<Interaction>,
pub thread: Option<Channel>,
pub components: Option<Vec<ActionRow>>,
pub sticker_items: Option<Vec<StickerItem>>,
pub position: Option<i32>,
pub role_subscription_data: Option<RoleSubscriptionData>,
}
#[derive(Debug, Deserialize)]
pub struct ChannelMention {
pub id: Snowflake,
pub guild_id: Snowflake,
#[serde(rename = "type")]
pub t: i32,
pub name: String,
}
#[derive(Debug, Deserialize)]
pub struct Reaction {
pub count: i32,
pub me: bool,
pub emoji: Emoji,
}
#[derive(Debug, Deserialize_repr)]
#[repr(u8)]
pub enum MessageType {
Default = 0,
RecipientAdd = 1,
RecipientRemove = 2,
Call = 3,
ChannelNameChange = 4,
ChannelIconChange = 5,
ChannelPinnedMessage = 6,
UserJoin = 7,
GuildBoost = 8,
GuildBoostTier1 = 9,
GuildBoostTier2 = 10,
GuildBoostTier3 = 11,
ChannelFollowAdd = 12,
GuildDiscoveryDisqualified = 14,
GuildDiscoveryRequalified = 15,
GuildDiscoveryGracePeriodInitialWarning = 16,
GuildDiscoveryGracePeriodFinalWarning = 17,
ThreadCreated = 18,
Reply = 19,
ChatInputCommand = 20,
ThreadStarterMessage = 21,
GuildInviteReminder = 22,
ContextMenuCommand = 23,
AutoModerationAction = 24,
RoleSubscriptionPurchase = 25,
InteractionPremiumUpsell = 26,
StageStart = 27,
StageEnd = 28,
StageSpeaker = 29,
StageTopic = 31,
GuildApplicationPremiumSubscription = 32,
}
#[derive(Debug, Deserialize)]
pub struct MessageActivity {
#[serde(rename = "type")]
pub t: MessageActivityType,
pub party_id: Option<String>,
}
#[derive(Debug, Deserialize_repr)]
#[repr(u8)]
pub enum MessageActivityType {
Join = 1,
Spectate = 2,
Listen = 3,
JoinRequest = 5,
}
bitflags::bitflags! {
#[derive(Debug)]
pub struct MessageFlags: u16 {
const Crossposted = 1 << 0;
const IsCrosspost = 1 << 1;
const SuppressEmbeds = 1 << 2;
const SourceMessageDeleted = 1 << 3;
const Urgent = 1 << 4;
const HasThread = 1 << 5;
const Ephemeral = 1 << 6;
const Loading = 1 << 7;
const FailedToMentionSomeRolesInThread = 1 << 8;
const SuppressNotifications = 1 << 12;
const IsVoiceMessage = 1 << 13;
}
}
impl Serialize for MessageFlags {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.bits().to_string().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for MessageFlags {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let bit_str = String::deserialize(deserializer)?;
let bits = bit_str
.parse::<u16>()
.map_err(|e| serde::de::Error::custom(e))?;
Ok(MessageFlags::from_bits_retain(bits))
}
}
#[derive(Debug, Deserialize)]
pub struct MessageReference {
pub message_id: Option<Snowflake>,
pub channel_id: Option<Snowflake>,
pub guild_id: Option<Snowflake>,
pub fail_if_not_exists: Option<bool>,
}
#[cfg(test)]
pub mod tests {
use crate::models::Component;
use super::*;
#[test]
pub fn button_component() {
let json = r#"{
"type": 1,
"components": [
{
"type": 2,
"label": "Click me!",
"style": 1,
"custom_id": "click_one"
}
]
}"#;
let res = serde_json::from_str::<ActionRow>(json);
assert!(res.is_ok());
let action_row = res.unwrap();
assert_eq!(action_row.components.len(), 1);
assert!(matches!(action_row.components[0], Component::Button { .. }));
}
#[test]
pub fn select_menu_component() {
let json = r#" {
"type": 1,
"components": [
{
"type": 3,
"custom_id": "class_select_1",
"options":[
{
"label": "Rogue",
"value": "rogue",
"description": "Sneak n stab",
"emoji": {
"name": "rogue",
"id": "625891304148303894"
}
},
{
"label": "Mage",
"value": "mage",
"description": "Turn 'em into a sheep",
"emoji": {
"name": "mage",
"id": "625891304081063986"
}
},
{
"label": "Priest",
"value": "priest",
"description": "You get heals when I'm done doing damage",
"emoji": {
"name": "priest",
"id": "625891303795982337"
}
}
],
"placeholder": "Choose a class",
"min_values": 1,
"max_values": 3
}
]
}"#;
let res = serde_json::from_str::<ActionRow>(json);
assert!(res.is_ok());
let component = res.unwrap();
println!("{:#?}", component);
}
}