use serde::{Deserialize, Serialize};
#[cfg(feature = "utoipa")]
use utoipa::{IntoParams, ToSchema};
#[cfg(feature = "validator")]
use validator::Validate;
use crate::v1::types::emoji::Emoji;
use crate::v1::types::moderation::Report;
use crate::v1::types::reaction::ReactionCounts;
use crate::v1::types::util::{some_option, Diff, Time};
use crate::v1::types::{AuditLogEntry, Embed, RoleId, UserId};
use crate::v1::types::{EmojiId, RoomId};
use super::channel::Channel;
use super::EmbedCreate;
use super::{
media::{Media, MediaRef},
ChannelId, MessageId, MessageVerId,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct Message {
#[serde(flatten)]
pub message_type: MessageType,
pub id: MessageId,
pub channel_id: ChannelId,
pub version_id: MessageVerId,
pub nonce: Option<String>,
pub author_id: UserId,
pub mentions: Mentions,
pub pinned: Option<Pinned>,
#[serde(default)]
pub reactions: ReactionCounts,
pub created_at: Option<Time>,
pub deleted_at: Option<Time>,
pub removed_at: Option<Time>,
pub edited_at: Option<Time>,
#[serde(skip_serializing_if = "Option::is_none")]
pub thread: Option<Box<Channel>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct Pinned {
pub time: Time,
pub position: u16,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct PinsReorder {
#[serde(default)]
#[validate(length(min = 1, max = 1024))]
pub messages: Vec<PinsReorderItem>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct PinsReorderItem {
pub id: MessageId,
#[serde(default, deserialize_with = "some_option")]
pub position: Option<Option<u16>>,
}
fn true_fn() -> bool {
true
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct ParseMentions {
pub users: Option<Vec<UserId>>,
pub roles: Option<Vec<RoleId>>,
#[serde(default = "true_fn")]
pub everyone: bool,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct Mentions {
pub users: Vec<UserId>,
pub roles: Vec<RoleId>,
pub threads: Vec<ChannelId>,
#[serde(default)]
pub emojis: Vec<EmojiId>,
#[serde(default)]
pub everyone: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct MessageCreate {
#[cfg_attr(feature = "utoipa", schema(min_length = 1, max_length = 8192))]
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 8192)))]
pub content: Option<String>,
#[cfg_attr(
feature = "utoipa",
schema(required = false, min_length = 0, max_length = 32)
)]
#[cfg_attr(feature = "validator", validate(length(min = 0, max = 32)))]
#[serde(default)]
pub attachments: Vec<MediaRef>,
#[cfg_attr(feature = "utoipa", schema(deprecated))]
pub metadata: Option<serde_json::Value>,
pub reply_id: Option<MessageId>,
#[cfg_attr(feature = "utoipa", schema(deprecated))]
#[serde(default)]
pub override_name: Option<String>,
#[serde(default)]
pub embeds: Vec<EmbedCreate>,
pub created_at: Option<Time>,
#[serde(default)]
pub mentions: ParseMentions,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct MessagePatch {
#[cfg_attr(feature = "utoipa", schema(min_length = 1, max_length = 8192))]
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 8192)))]
#[serde(default, deserialize_with = "some_option")]
pub content: Option<Option<String>>,
#[cfg_attr(
feature = "utoipa",
schema(required = false, min_length = 0, max_length = 32)
)]
#[cfg_attr(feature = "validator", validate(length(min = 0, max = 32)))]
pub attachments: Option<Vec<MediaRef>>,
#[cfg_attr(feature = "utoipa", schema(deprecated))]
#[serde(default, deserialize_with = "some_option")]
pub metadata: Option<Option<serde_json::Value>>,
#[serde(default, deserialize_with = "some_option")]
pub reply_id: Option<Option<MessageId>>,
#[cfg_attr(feature = "utoipa", schema(deprecated))]
pub override_name: Option<Option<String>>,
pub embeds: Option<Vec<EmbedCreate>>,
pub edited_at: Option<Time>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[serde(tag = "type")]
pub enum MessageType {
DefaultMarkdown(MessageDefaultMarkdown),
#[cfg(feature = "feat_message_forwarding")]
Forward(MessageDefaultTagged),
MessagePinned(MessagePin),
#[cfg(feature = "feat_message_move")]
MessagesMoved(MessagesMoved),
MemberAdd(MessageMember),
MemberRemove(MessageMember),
MemberJoin,
Call(MessageCall),
ThreadRename(MessageThreadRename),
ThreadCreated(MessageThreadCreated),
ThreadPingback(MessageThreadPingback),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessagePin {
pub pinned_message_id: MessageId,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessageThreadRename {
#[serde(alias = "new")]
pub name_new: String,
#[serde(alias = "old")]
pub name_old: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessageThreadCreated {
pub source_message_id: Option<MessageId>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessageThreadPingback {
pub source_room_id: RoomId,
pub source_channel_id: ChannelId,
pub source_user_id: UserId,
}
#[cfg(feature = "feat_message_move")]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessagesMoved {
pub start_id: MessageId,
pub end_id: MessageId,
pub source_id: ChannelId,
pub target_id: ChannelId,
pub reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessageMember {
pub target_user_id: UserId,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessageRoomFollowed {
pub thread_id: ChannelId,
pub reason: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessageModerationLog {
pub audit_log_entry: AuditLogEntry,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessageModerationReport {
pub report: Report,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct MessageBotCommand {
pub command_id: String,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct MessageDefaultMarkdown {
#[cfg_attr(feature = "utoipa", schema(min_length = 1, max_length = 8192))]
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 8192)))]
pub content: Option<String>,
#[cfg_attr(feature = "utoipa", schema(min_length = 1, max_length = 32))]
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 32), nested))]
pub attachments: Vec<Media>,
#[cfg_attr(feature = "utoipa", schema(deprecated))]
pub metadata: Option<serde_json::Value>,
pub reply_id: Option<MessageId>,
#[cfg_attr(feature = "utoipa", schema(min_length = 1, max_length = 32))]
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 32), nested))]
pub embeds: Vec<Embed>,
#[cfg_attr(feature = "utoipa", schema(deprecated))]
pub override_name: Option<String>,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct MessageCall {
pub ended_at: Option<Time>,
pub participants: Vec<UserId>,
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct Interactions {
#[cfg(feature = "feat_interaction_reaction")]
pub reactions_default: Option<Vec<Emoji>>,
#[cfg(feature = "feat_interaction_status")]
#[serde(flatten)]
pub status: Option<InteractionStatus>,
}
#[cfg(feature = "feat_interaction_reaction")]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub enum InteractionStatus {
Loading,
Failed {
reason: String,
can_retry: bool,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct MessageMigrate {
#[serde(default)]
#[cfg_attr(feature = "validator", validate(length(min = 1, max = 128)))]
pub message_ids: Vec<MessageId>,
pub target_id: ChannelId,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct MessageModerate {
#[serde(default)]
#[cfg_attr(feature = "validator", validate(length(max = 128)))]
pub delete: Vec<MessageId>,
#[serde(default)]
#[cfg_attr(feature = "validator", validate(length(max = 128)))]
pub remove: Vec<MessageId>,
#[serde(default)]
#[cfg_attr(feature = "validator", validate(length(max = 128)))]
pub restore: Vec<MessageId>,
}
#[derive(Debug, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema, IntoParams))]
#[cfg_attr(feature = "validator", derive(Validate))]
pub struct RepliesQuery {
#[serde(default = "fn_one")]
#[cfg_attr(feature = "validator", validate(range(min = 1, max = 8)))]
pub depth: u16,
pub breadth: Option<u16>,
}
fn fn_one() -> u16 {
1
}
#[derive(Debug, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema, IntoParams))]
pub struct ContextQuery {
pub to_start: Option<MessageId>,
pub to_end: Option<MessageId>,
pub limit: Option<u16>,
}
#[derive(Debug, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(ToSchema))]
pub struct ContextResponse {
pub items: Vec<Message>,
pub total: u64,
pub has_after: bool,
pub has_before: bool,
}
impl Diff<Message> for MessagePatch {
fn changes(&self, other: &Message) -> bool {
match &other.message_type {
MessageType::DefaultMarkdown(m) => {
self.content.changes(&m.content)
|| self.metadata.changes(&m.metadata)
|| self.reply_id.changes(&m.reply_id)
|| self.override_name.changes(&m.override_name)
|| self.embeds.is_some()
|| self.attachments.as_ref().is_some_and(|a| {
a.len() != m.attachments.len()
|| a.iter().zip(&m.attachments).any(|(a, b)| a.id != b.id)
})
}
_ => false,
}
}
}
impl MessageType {
pub fn is_deletable(&self) -> bool {
match self {
MessageType::DefaultMarkdown(_) => true,
#[cfg(feature = "feat_message_forwarding")]
MessageType::Forward(_) => true,
MessageType::MessagePinned(_) => true,
MessageType::MemberAdd(_) => false,
MessageType::MemberRemove(_) => false,
MessageType::MemberJoin => true,
MessageType::ThreadRename(_) => false,
MessageType::ThreadPingback(_) => true,
#[cfg(feature = "feat_message_move")]
MessageType::MessagesMoved(_) => false,
MessageType::Call(_) => false,
MessageType::ThreadCreated(_) => false,
}
}
pub fn is_editable(&self) -> bool {
matches!(self, MessageType::DefaultMarkdown(_))
}
pub fn is_movable(&self) -> bool {
matches!(self, MessageType::DefaultMarkdown(_))
}
}