serenity/model/channel/
private_channel.rs

1use std::fmt;
2#[cfg(feature = "model")]
3use std::sync::Arc;
4
5#[cfg(feature = "model")]
6use crate::builder::{CreateAttachment, CreateMessage, EditMessage, GetMessages};
7#[cfg(feature = "model")]
8use crate::http::CacheHttp;
9#[cfg(feature = "model")]
10use crate::http::{Http, Typing};
11use crate::model::prelude::*;
12use crate::model::utils::single_recipient;
13
14/// A Direct Message text channel with another user.
15///
16/// [Discord docs](https://discord.com/developers/docs/resources/channel#channel-object).
17#[cfg_attr(feature = "typesize", derive(typesize::derive::TypeSize))]
18#[derive(Clone, Debug, Default, Deserialize, Serialize)]
19#[non_exhaustive]
20pub struct PrivateChannel {
21    /// The unique Id of the private channel.
22    ///
23    /// Can be used to calculate the first message's creation date.
24    pub id: ChannelId,
25    /// The Id of the last message sent.
26    pub last_message_id: Option<MessageId>,
27    /// Timestamp of the last time a [`Message`] was pinned.
28    pub last_pin_timestamp: Option<Timestamp>,
29    /// Indicator of the type of channel this is.
30    ///
31    /// This should always be [`ChannelType::Private`].
32    #[serde(rename = "type")]
33    pub kind: ChannelType,
34    /// The recipient to the private channel.
35    #[serde(with = "single_recipient", rename = "recipients")]
36    pub recipient: User,
37}
38
39#[cfg(feature = "model")]
40impl PrivateChannel {
41    /// Broadcasts that the current user is typing to the recipient.
42    ///
43    /// See [ChannelId::broadcast_typing] for more details.
44    #[allow(clippy::missing_errors_doc)]
45    #[inline]
46    pub async fn broadcast_typing(&self, http: impl AsRef<Http>) -> Result<()> {
47        self.id.broadcast_typing(http).await
48    }
49
50    /// React to a [`Message`] with a custom [`Emoji`] or unicode character.
51    ///
52    /// [`Message::react`] may be a more suited method of reacting in most cases.
53    ///
54    /// # Errors
55    ///
56    /// Returns [`Error::Http`] if the reaction cannot be added, or if a message with that Id does
57    /// not exist.
58    #[inline]
59    pub async fn create_reaction(
60        &self,
61        http: impl AsRef<Http>,
62        message_id: impl Into<MessageId>,
63        reaction_type: impl Into<ReactionType>,
64    ) -> Result<()> {
65        self.id.create_reaction(http, message_id, reaction_type).await
66    }
67
68    /// Deletes the channel. This does not delete the contents of the channel, and is equivalent to
69    /// closing a private channel on the client, which can be re-opened.
70    #[allow(clippy::missing_errors_doc)]
71    #[inline]
72    pub async fn delete(&self, http: impl AsRef<Http>) -> Result<PrivateChannel> {
73        self.id.delete(http).await?.private().ok_or(Error::Model(ModelError::InvalidChannelType))
74    }
75
76    /// Deletes all messages by Ids from the given vector in the channel.
77    ///
78    /// The minimum amount of messages is 2 and the maximum amount is 100.
79    ///
80    /// Requires the [Manage Messages] permission.
81    ///
82    /// **Note**: Messages that are older than 2 weeks can't be deleted using this method.
83    ///
84    /// # Errors
85    ///
86    /// Returns [`ModelError::BulkDeleteAmount`] if an attempt was made to delete either 0 or more
87    /// than 100 messages.
88    ///
89    /// [Manage Messages]: Permissions::MANAGE_MESSAGES
90    #[inline]
91    pub async fn delete_messages<T: AsRef<MessageId>>(
92        &self,
93        http: impl AsRef<Http>,
94        message_ids: impl IntoIterator<Item = T>,
95    ) -> Result<()> {
96        self.id.delete_messages(http, message_ids).await
97    }
98
99    /// Deletes all permission overrides in the channel from a member or role.
100    ///
101    /// **Note**: Requires the [Manage Channel] permission.
102    ///
103    /// [Manage Channel]: Permissions::MANAGE_CHANNELS
104    #[allow(clippy::missing_errors_doc)]
105    #[inline]
106    pub async fn delete_permission(
107        &self,
108        http: impl AsRef<Http>,
109        permission_type: PermissionOverwriteType,
110    ) -> Result<()> {
111        self.id.delete_permission(http, permission_type).await
112    }
113
114    /// Deletes the given [`Reaction`] from the channel.
115    ///
116    /// **Note**: In private channels, the current user may only delete it's own reactions.
117    ///
118    /// # Errors
119    ///
120    /// Returns [`Error::Http`] if the reaction is not from the current user.
121    #[inline]
122    pub async fn delete_reaction(
123        &self,
124        http: impl AsRef<Http>,
125        message_id: impl Into<MessageId>,
126        user_id: Option<UserId>,
127        reaction_type: impl Into<ReactionType>,
128    ) -> Result<()> {
129        self.id.delete_reaction(http, message_id, user_id, reaction_type).await
130    }
131
132    /// Edits a [`Message`] in the channel given its Id.
133    ///
134    /// Message editing preserves all unchanged message data, with some exceptions for embeds and
135    /// attachments.
136    ///
137    /// **Note**: In most cases requires that the current user be the author of the message.
138    ///
139    /// Refer to the documentation for [`EditMessage`] for information regarding content
140    /// restrictions and requirements.
141    ///
142    /// # Errors
143    ///
144    /// See [`EditMessage::execute`] for a list of possible errors, and their corresponding
145    /// reasons.
146    ///
147    /// [`EditMessage::execute`]: ../../builder/struct.EditMessage.html#method.execute
148    #[inline]
149    pub async fn edit_message(
150        &self,
151        cache_http: impl CacheHttp,
152        message_id: impl Into<MessageId>,
153        builder: EditMessage,
154    ) -> Result<Message> {
155        self.id.edit_message(cache_http, message_id, builder).await
156    }
157
158    /// Determines if the channel is NSFW.
159    #[inline]
160    #[must_use]
161    #[allow(clippy::unused_self)]
162    #[deprecated = "This always returns false"]
163    pub fn is_nsfw(&self) -> bool {
164        false
165    }
166
167    /// Gets a message from the channel.
168    ///
169    /// # Errors
170    ///
171    /// Returns [`Error::Http`] if a message with that Id does not exist in this channel.
172    #[inline]
173    pub async fn message(
174        &self,
175        cache_http: impl CacheHttp,
176        message_id: impl Into<MessageId>,
177    ) -> Result<Message> {
178        self.id.message(cache_http, message_id).await
179    }
180
181    /// Gets messages from the channel.
182    ///
183    /// **Note**: If the user does not have the [Read Message History] permission, returns an empty
184    /// [`Vec`].
185    ///
186    /// # Errors
187    ///
188    /// Returns [`Error::Http`] if the current user lacks permission.
189    ///
190    /// [Read Message History]: Permissions::READ_MESSAGE_HISTORY
191    #[inline]
192    pub async fn messages(
193        &self,
194        cache_http: impl CacheHttp,
195        builder: GetMessages,
196    ) -> Result<Vec<Message>> {
197        self.id.messages(cache_http, builder).await
198    }
199
200    /// Returns "DM with $username#discriminator".
201    #[must_use]
202    pub fn name(&self) -> String {
203        format!("DM with {}", self.recipient.tag())
204    }
205
206    /// Gets the list of [`User`]s who have reacted to a [`Message`] with a certain [`Emoji`].
207    ///
208    /// The default `limit` is `50` - specify otherwise to receive a different maximum number of
209    /// users. The maximum that may be retrieve at a time is `100`, if a greater number is provided
210    /// then it is automatically reduced.
211    ///
212    /// The optional `after` attribute is to retrieve the users after a certain user. This is
213    /// useful for pagination.
214    ///
215    /// # Errors
216    ///
217    /// Returns [`Error::Http`] if a message with the given Id does not exist in the channel.
218    #[inline]
219    pub async fn reaction_users(
220        &self,
221        http: impl AsRef<Http>,
222        message_id: impl Into<MessageId>,
223        reaction_type: impl Into<ReactionType>,
224        limit: Option<u8>,
225        after: impl Into<Option<UserId>>,
226    ) -> Result<Vec<User>> {
227        self.id.reaction_users(http, message_id, reaction_type, limit, after).await
228    }
229
230    /// Pins a [`Message`] to the channel.
231    ///
232    /// # Errors
233    ///
234    /// Returns [`Error::Http`] if the number of pinned messages would exceed the 50 message limit.
235    #[inline]
236    pub async fn pin(
237        &self,
238        http: impl AsRef<Http>,
239        message_id: impl Into<MessageId>,
240    ) -> Result<()> {
241        self.id.pin(http, message_id).await
242    }
243
244    /// Retrieves the list of messages that have been pinned in the private channel.
245    #[allow(clippy::missing_errors_doc)]
246    #[inline]
247    pub async fn pins(&self, http: impl AsRef<Http>) -> Result<Vec<Message>> {
248        self.id.pins(http).await
249    }
250
251    /// Sends a message with just the given message content in the channel.
252    ///
253    /// **Note**: Message content must be under 2000 unicode code points.
254    ///
255    /// # Errors
256    ///
257    /// Returns a [`ModelError::MessageTooLong`] if the content length is over the above limit. See
258    /// [`CreateMessage::execute`] for more details.
259    ///
260    /// [`CreateMessage::execute`]: ../../builder/struct.CreateMessage.html#method.execute
261    #[inline]
262    pub async fn say(
263        &self,
264        cache_http: impl CacheHttp,
265        content: impl Into<String>,
266    ) -> Result<Message> {
267        self.id.say(cache_http, content).await
268    }
269
270    /// Sends file(s) along with optional message contents.
271    ///
272    /// Refer to [`ChannelId::send_files`] for examples and more information.
273    ///
274    /// # Errors
275    ///
276    /// See [`CreateMessage::execute`] for a list of possible errors, and their corresponding
277    /// reasons.
278    ///
279    /// [`CreateMessage::execute`]: ../../builder/struct.CreateMessage.html#method.execute
280    #[inline]
281    pub async fn send_files(
282        self,
283        cache_http: impl CacheHttp,
284        files: impl IntoIterator<Item = CreateAttachment>,
285        builder: CreateMessage,
286    ) -> Result<Message> {
287        self.id.send_files(cache_http, files, builder).await
288    }
289
290    /// Sends a message to the channel.
291    ///
292    /// Refer to the documentation for [`CreateMessage`] for information regarding content
293    /// restrictions and requirements.
294    ///
295    /// # Errors
296    ///
297    /// See [`CreateMessage::execute`] for a list of possible errors, and their corresponding
298    /// reasons.
299    ///
300    /// [`CreateMessage::execute`]: ../../builder/struct.CreateMessage.html#method.execute
301    #[inline]
302    pub async fn send_message(
303        &self,
304        cache_http: impl CacheHttp,
305        builder: CreateMessage,
306    ) -> Result<Message> {
307        self.id.send_message(cache_http, builder).await
308    }
309
310    /// Starts typing in the channel for an indefinite period of time.
311    ///
312    /// Returns [`Typing`] that is used to trigger the typing. [`Typing::stop`] must be called on
313    /// the returned struct to stop typing. Note that on some clients, typing may persist for a few
314    /// seconds after [`Typing::stop`] is called. Typing is also stopped when the struct is
315    /// dropped.
316    ///
317    /// If a message is sent while typing is triggered, the user will stop typing for a brief
318    /// period of time and then resume again until either [`Typing::stop`] is called or the struct
319    /// is dropped.
320    ///
321    /// This should rarely be used for bots, although it is a good indicator that a long-running
322    /// command is still being processed.
323    ///
324    /// ## Examples
325    ///
326    /// ```rust,no_run
327    /// # #[cfg(feature = "cache")]
328    /// # async fn run() {
329    /// # use serenity::{cache::Cache, http::Http, model::channel::PrivateChannel, Result};
330    /// # use std::sync::Arc;
331    /// #
332    /// # fn long_process() {}
333    /// # let http: Arc<Http> = unimplemented!();
334    /// # let cache = Cache::default();
335    /// # let channel: PrivateChannel = unimplemented!();
336    /// // Initiate typing (assuming http is `Arc<Http>` and `channel` is bound)
337    /// let typing = channel.start_typing(&http);
338    ///
339    /// // Run some long-running process
340    /// long_process();
341    ///
342    /// // Stop typing
343    /// typing.stop();
344    /// # }
345    /// ```
346    ///
347    /// # Errors
348    ///
349    /// May return [`Error::Http`] if the current user cannot send a direct message to this user.
350    pub fn start_typing(self, http: &Arc<Http>) -> Typing {
351        http.start_typing(self.id)
352    }
353
354    /// Unpins a [`Message`] in the channel given by its Id.
355    ///
356    /// # Errors
357    ///
358    /// Returns [`Error::Http`] if the current user lacks permission, if the message was deleted,
359    /// or if the channel already has the limit of 50 pinned messages.
360    #[inline]
361    pub async fn unpin(
362        &self,
363        http: impl AsRef<Http>,
364        message_id: impl Into<MessageId>,
365    ) -> Result<()> {
366        self.id.unpin(http, message_id).await
367    }
368}
369
370impl fmt::Display for PrivateChannel {
371    /// Formats the private channel, displaying the recipient's username.
372    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373        f.write_str(&self.recipient.name)
374    }
375}