spectacles_model/message/
mod.rs

1//! Structs related to Discord messages in a guild channel.
2use chrono::{DateTime, FixedOffset};
3use serde_repr::{Deserialize_repr, Serialize_repr};
4
5use crate::guild::GuildMember;
6use crate::snowflake::Snowflake;
7use crate::User;
8
9pub use self::embed::*;
10pub use self::emoji::*;
11pub use self::webhook::*;
12
13mod embed;
14mod webhook;
15mod emoji;
16
17/// Represents different types that can be sent to the Discord API.
18pub trait MessageResponse {
19    fn as_message(self) -> CreateMessageOptions;
20}
21
22impl MessageResponse for &str {
23    fn as_message(self) -> CreateMessageOptions {
24        CreateMessageOptions::default().content(self)
25    }
26}
27
28impl MessageResponse for &String {
29    fn as_message(self) -> CreateMessageOptions {
30        CreateMessageOptions::default().content(self.clone())
31    }
32}
33
34impl MessageResponse for CreateMessageOptions {
35    fn as_message(self) -> CreateMessageOptions {
36        self
37    }
38}
39
40impl MessageResponse for String {
41    fn as_message(self) -> CreateMessageOptions {
42        CreateMessageOptions::default().content(self)
43    }
44}
45
46impl MessageResponse for Embed {
47    fn as_message(self) -> CreateMessageOptions {
48        CreateMessageOptions::default().embed(self)
49    }
50}
51impl MessageResponse for EditMessage {
52    fn as_message(self) -> CreateMessageOptions {
53        let mut m = CreateMessageOptions::default();
54        m = m.content(self.content.unwrap_or_default());
55
56        if let Some(e) = self.embed {
57            m.embed(e)
58        } else {
59            m
60        }
61    }
62}
63
64/// A message sent in a channel on Discord.
65#[derive(Deserialize, Serialize, Clone, Debug)]
66pub struct Message {
67    /// The message ID of the message.
68    pub id: Snowflake,
69    /// The ID of the channel that the message was sent in.
70    pub channel_id: Snowflake,
71    /// The ID of the guild that the message was sent in.
72    #[serde(default)]
73    pub guild_id: Option<Snowflake>,
74    /// The author of the message.
75    pub author: User,
76    /// The contents of this message.
77    pub content: String,
78    /// The guild member form of the message author.
79    #[serde(default)]
80    pub member: Option<GuildMember>,
81    /// The time that this message was sent.
82    pub timestamp: DateTime<FixedOffset>,
83    /// When this message was edited, if applicable.
84    pub edited_timestamp: Option<DateTime<FixedOffset>>,
85    /// Whether or not this was a TTS message.
86    pub tts: bool,
87    /// Whether or not this message mentioned everyone.
88    pub mention_everyone: bool,
89    /// Roles that were mentioned in this message.
90    pub mention_roles: Vec<Snowflake>,
91    /// The message's attached files, if any.
92    pub attachments: Vec<MessageAttachment>,
93    /// Any embeds sent with this message.
94    pub embeds: Vec<Embed>,
95    /// The message's reactions.
96    #[serde(default)]
97    pub reactions: Vec<MessageReaction>,
98    /// A snowflake used to validate that a message was sent.
99    #[serde(default)]
100    pub nonce: Option<Snowflake>,
101    /// Whether or not the message is pinned.
102    pub pinned: bool,
103    /// The ID of the webhook if the message was sent by a webhook.
104    #[serde(default)]
105    pub webhook_id: Option<Snowflake>,
106    /// The type of message sent.
107    #[serde(rename = "type")]
108    pub kind: MessageType,
109    /// Message Activity sent with rich-presence embeds.
110    #[serde(default)]
111    pub activity: Option<MessageActivity>,
112    /// Message Application ent with Rich Presence embeds.
113    #[serde(default)]
114    pub application: Option<MessageApplication>,
115}
116
117/// Represents a message that is being sent to Discord.
118#[derive(Serialize, Debug, Default)]
119pub struct CreateMessageOptions {
120    /// The content of this message.
121    #[serde(skip_serializing_if = "Option::is_none")]
122    content: Option<String>,
123    /// The embed that this message has.
124    #[serde(skip_serializing_if = "Option::is_none")]
125    embed: Option<Embed>,
126    /// Whether or not this message is a TTS message.
127    tts: Option<bool>,
128    #[serde(skip_serializing)]
129    pub file: Option<(String, Vec<u8>)>
130}
131
132impl CreateMessageOptions {
133    /// Creates a new message with the specified content string.
134    pub fn new() -> Self {
135        CreateMessageOptions {
136            content: None,
137            embed: None,
138            tts: None,
139            file: None
140        }
141    }
142
143    /// Adds content to the message.
144    pub fn content(mut self, content: impl ToString) -> Self {
145        self.content = Some(content.to_string());
146
147        self
148    }
149
150    /// Adds an Embed object to the message.
151    pub fn embed(mut self, embed: Embed) -> Self {
152        self.embed = Some(embed);
153
154        self
155    }
156
157    /// Adds an attachment to this message.
158    pub fn file(mut self, name: &str, file: Vec<u8>) -> Self {
159        self.file = Some((name.to_string(), file));
160        self
161    }
162
163    /// Whether or not this message will be a TTS message.
164    pub fn tts(mut self, opt: bool) -> Self {
165        self.tts = Some(opt);
166
167        self
168    }
169}
170
171/// Represents a message that is being edited in a Discord channel.
172#[derive(Serialize, Clone, Debug, Default)]
173pub struct EditMessage {
174    #[serde(skip_serializing_if = "Option::is_none")]
175    content: Option<String>,
176    #[serde(skip_serializing_if = "Option::is_none")]
177    embed: Option<Embed>
178}
179
180impl EditMessage {
181    pub fn new() -> EditMessage {
182        EditMessage {
183            content: None,
184            embed: None
185        }
186    }
187
188    /// Adds the content to edit into this message.
189    pub fn with_content(mut self, content: impl Into<String>) -> Self {
190        self.content = Some(content.into());
191
192        self
193    }
194
195
196    /// Adds an embed to be edited into this message.
197    pub fn with_embed(mut self, embed: Embed) -> Self {
198        self.embed = Some(embed);
199
200        self
201    }
202}
203
204/// Options for retrieving messages from a channel.
205#[derive(Serialize, Clone, Debug)]
206pub struct ChannelMessagesQuery {
207    #[serde(skip_serializing_if = "Option::is_none")]
208    around: Option<Snowflake>,
209    #[serde(skip_serializing_if = "Option::is_none")]
210    before: Option<Snowflake>,
211    #[serde(skip_serializing_if = "Option::is_none")]
212    after: Option<Snowflake>,
213    limit: i32
214}
215
216impl ChannelMessagesQuery {
217    pub fn new() -> ChannelMessagesQuery {
218        ChannelMessagesQuery {
219            around: None,
220            before: None,
221            after: None,
222            limit: 50
223        }
224    }
225
226
227    /// Fetch messages from this channel that are around this message ID.
228    pub fn around(mut self, id: u64) -> Self {
229        if self.after.is_some() || self.before.is_some() {
230            return self;
231        };
232        self.around = Some(id.into());
233        self
234    }
235
236    /// Fetch messages from this channel that are before this message ID.
237    pub fn before(mut self, id: u64) -> Self {
238        if self.around.is_some() || self.after.is_some() {
239            return self;
240        };
241        self.before = Some(id.into());
242        self
243    }
244
245    /// Fetch messages in this channels that are after this message ID.
246    pub fn after(mut self, id: u64) -> Self {
247        if self.around.is_some() || self.before.is_some() {
248            return self;
249        };
250        self.after = Some(id.into());
251        self
252    }
253}
254
255
256/// Represents an attachment sent by a user.
257#[derive(Deserialize, Serialize, Clone, Debug)]
258pub struct MessageAttachment {
259    /// The attachment ID.
260    pub id: Snowflake,
261    /// The name of the file attached.
262    pub filename: String,
263    /// The size of the file in bytes.
264    pub size: i32,
265    /// The source URL of the file.
266    pub url: String,
267    /// A proxied URL of the file.
268    pub proxy_url: String,
269    /// The height of the file, if it is an image.
270    pub height: Option<i32>,
271    /// The width of the file, if it is an image.
272    pub width: Option<i32>
273
274}
275/// A Rich Presence Message activity.
276#[derive(Deserialize, Serialize, Clone, Debug, Default)]
277pub struct MessageActivity {
278    /// The type of message activity.
279    #[serde(rename = "type")]
280    pub kind: MessageActivityType,
281    /// The party ID from a Rich Presence event.
282    #[serde(default)]
283    pub party_id: String
284}
285
286/// A Rich Presence Message Application.
287#[derive(Deserialize, Serialize, Clone, Debug, Default)]
288pub struct MessageApplication {
289    /// The ID of the application.
290    pub id: Snowflake,
291    /// The ID of the embeds's image.
292    pub cover_image: String,
293    /// The application description.
294    pub description: String,
295    /// The ID of the application icon.
296    pub icon: String,
297    /// The name of the application.
298    pub name: String
299}
300
301/// A list of Message types.
302#[derive(Deserialize_repr, Debug, Clone, Serialize_repr)]
303#[repr(u8)]
304pub enum MessageType {
305    Default,
306    RecipientAdd,
307    RecipientRemove,
308    Call,
309    ChannelNameChange,
310    ChannelIconChange,
311    ChannelPinnedMessage,
312    GuildMemberJoin
313}
314
315impl Default for MessageType {
316    fn default() -> Self {
317        MessageType::Default
318    }
319}
320
321/// A list of Message Activity types.
322#[derive(Deserialize, Serialize, Debug, Clone)]
323
324pub enum MessageActivityType {
325    Join = 1,
326    Spectate,
327    Listen = 3,
328    JoinRequest = 5
329}
330
331impl Default for MessageActivityType {
332    fn default() -> Self {
333        MessageActivityType::Join
334    }
335}