diff --git a/src/api/channels/messages.rs b/src/api/channels/messages.rs index cd2b899..a181784 100644 --- a/src/api/channels/messages.rs +++ b/src/api/channels/messages.rs @@ -1,113 +1,111 @@ -pub mod messages { - use http::header::CONTENT_DISPOSITION; - use http::HeaderMap; - use reqwest::{multipart, Client}; - use serde_json::to_string; +use http::header::CONTENT_DISPOSITION; +use http::HeaderMap; +use reqwest::{multipart, Client}; +use serde_json::to_string; - use crate::instance::UserMeta; - use crate::limit::LimitedRequester; - use crate::types::{Message, MessageSendSchema, PartialDiscordFileAttachment}; +use crate::instance::UserMeta; +use crate::limit::LimitedRequester; +use crate::types::{Message, MessageSendSchema, PartialDiscordFileAttachment}; - impl Message { - /** - Sends a message to the Spacebar server. - # Arguments - * `url_api` - The URL of the Spacebar server's API. - * `message` - The [`Message`] that will be sent to the Spacebar server. - * `limits_user` - The [`Limits`] of the user. - * `limits_instance` - The [`Limits`] of the instance. - * `requester` - The [`LimitedRequester`] that will be used to make requests to the Spacebar server. - # Errors - * [`InstanceServerError`] - If the message cannot be sent. - */ - pub async fn send( - user: &mut UserMeta, - channel_id: String, - message: &mut MessageSendSchema, - files: Option>, - ) -> Result { - let mut belongs_to = user.belongs_to.borrow_mut(); - let url_api = belongs_to.urls.get_api(); - let mut requester = LimitedRequester::new().await; +impl Message { + /** + Sends a message to the Spacebar server. + # Arguments + * `url_api` - The URL of the Spacebar server's API. + * `message` - The [`Message`] that will be sent to the Spacebar server. + * `limits_user` - The [`Limits`] of the user. + * `limits_instance` - The [`Limits`] of the instance. + * `requester` - The [`LimitedRequester`] that will be used to make requests to the Spacebar server. + # Errors + * [`InstanceServerError`] - If the message cannot be sent. + */ + pub async fn send( + user: &mut UserMeta, + channel_id: String, + message: &mut MessageSendSchema, + files: Option>, + ) -> Result { + let mut belongs_to = user.belongs_to.borrow_mut(); + let url_api = belongs_to.urls.get_api(); + let mut requester = LimitedRequester::new().await; - if files.is_none() { - let message_request = Client::new() - .post(format!("{}/channels/{}/messages/", url_api, channel_id)) - .bearer_auth(user.token()) - .body(to_string(message).unwrap()); - requester - .send_request( - message_request, - crate::api::limits::LimitType::Channel, - &mut belongs_to.limits, - &mut user.limits, - ) - .await - } else { - for (index, attachment) in message.attachments.iter_mut().enumerate() { - attachment.get_mut(index).unwrap().set_id(index as i16); - } - let mut form = reqwest::multipart::Form::new(); - let payload_json = to_string(message).unwrap(); - let payload_field = reqwest::multipart::Part::text(payload_json); - - form = form.part("payload_json", payload_field); - - for (index, attachment) in files.unwrap().into_iter().enumerate() { - let (attachment_content, current_attachment) = attachment.move_content(); - let (attachment_filename, _) = current_attachment.move_filename(); - let part_name = format!("files[{}]", index); - let content_disposition = format!( - "form-data; name=\"{}\"'; filename=\"{}\"", - part_name, &attachment_filename - ); - let mut header_map = HeaderMap::new(); - header_map.insert(CONTENT_DISPOSITION, content_disposition.parse().unwrap()); - - let part = multipart::Part::bytes(attachment_content) - .file_name(attachment_filename) - .headers(header_map); - - form = form.part(part_name, part); - } - - let message_request = Client::new() - .post(format!("{}/channels/{}/messages/", url_api, channel_id)) - .bearer_auth(user.token()) - .multipart(form); - - requester - .send_request( - message_request, - crate::api::limits::LimitType::Channel, - &mut belongs_to.limits, - &mut user.limits, - ) - .await + if files.is_none() { + let message_request = Client::new() + .post(format!("{}/channels/{}/messages/", url_api, channel_id)) + .bearer_auth(user.token()) + .body(to_string(message).unwrap()); + requester + .send_request( + message_request, + crate::api::limits::LimitType::Channel, + &mut belongs_to.limits, + &mut user.limits, + ) + .await + } else { + for (index, attachment) in message.attachments.iter_mut().enumerate() { + attachment.get_mut(index).unwrap().set_id(index as i16); } - } - } + let mut form = reqwest::multipart::Form::new(); + let payload_json = to_string(message).unwrap(); + let payload_field = reqwest::multipart::Part::text(payload_json); - impl UserMeta { - /// Shorthand call for Message::send() - /** - Sends a message to the Spacebar server. - # Arguments - * `url_api` - The URL of the Spacebar server's API. - * `message` - The [`Message`] that will be sent to the Spacebar server. - * `limits_user` - The [`Limits`] of the user. - * `limits_instance` - The [`Limits`] of the instance. - * `requester` - The [`LimitedRequester`] that will be used to make requests to the Spacebar server. - # Errors - * [`InstanceServerError`] - If the message cannot be sent. - */ - pub async fn send_message( - &mut self, - message: &mut MessageSendSchema, - channel_id: String, - files: Option>, - ) -> Result { - Message::send(self, channel_id, message, files).await + form = form.part("payload_json", payload_field); + + for (index, attachment) in files.unwrap().into_iter().enumerate() { + let (attachment_content, current_attachment) = attachment.move_content(); + let (attachment_filename, _) = current_attachment.move_filename(); + let part_name = format!("files[{}]", index); + let content_disposition = format!( + "form-data; name=\"{}\"'; filename=\"{}\"", + part_name, &attachment_filename + ); + let mut header_map = HeaderMap::new(); + header_map.insert(CONTENT_DISPOSITION, content_disposition.parse().unwrap()); + + let part = multipart::Part::bytes(attachment_content) + .file_name(attachment_filename) + .headers(header_map); + + form = form.part(part_name, part); + } + + let message_request = Client::new() + .post(format!("{}/channels/{}/messages/", url_api, channel_id)) + .bearer_auth(user.token()) + .multipart(form); + + requester + .send_request( + message_request, + crate::api::limits::LimitType::Channel, + &mut belongs_to.limits, + &mut user.limits, + ) + .await } } } + +impl UserMeta { + /// Shorthand call for Message::send() + /** + Sends a message to the Spacebar server. + # Arguments + * `url_api` - The URL of the Spacebar server's API. + * `message` - The [`Message`] that will be sent to the Spacebar server. + * `limits_user` - The [`Limits`] of the user. + * `limits_instance` - The [`Limits`] of the instance. + * `requester` - The [`LimitedRequester`] that will be used to make requests to the Spacebar server. + # Errors + * [`InstanceServerError`] - If the message cannot be sent. + */ + pub async fn send_message( + &mut self, + message: &mut MessageSendSchema, + channel_id: String, + files: Option>, + ) -> Result { + Message::send(self, channel_id, message, files).await + } +} diff --git a/src/api/channels/mod.rs b/src/api/channels/mod.rs index 72f4e3e..28a9dd3 100644 --- a/src/api/channels/mod.rs +++ b/src/api/channels/mod.rs @@ -1,5 +1,7 @@ pub mod channels; pub mod messages; +pub mod reactions; pub use channels::*; pub use messages::*; +pub use reactions::*; diff --git a/src/api/channels/reactions.rs b/src/api/channels/reactions.rs new file mode 100644 index 0000000..0fc265b --- /dev/null +++ b/src/api/channels/reactions.rs @@ -0,0 +1,183 @@ +use reqwest::Client; + +use crate::{ + instance::UserMeta, + limit::LimitedRequester, + types::{self, Snowflake}, +}; + +/** +Extends the [`types::Reaction`] struct with useful metadata. + */ +pub struct ReactionMeta { + pub message_id: types::Snowflake, + pub channel_id: types::Snowflake, + pub reaction: types::Reaction, +} + +impl ReactionMeta { + /** + Deletes all reactions for a message. + # Arguments + * `user` - A mutable reference to a [`UserMeta`] instance. + + # Returns + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + + # Reference + See [https://discord.com/developers/docs/resources/channel#delete-all-reactions](https://discord.com/developers/docs/resources/channel#delete-all-reactions) + */ + pub async fn delete_all( + &self, + user: &mut UserMeta, + ) -> Result { + let mut belongs_to = user.belongs_to.borrow_mut(); + let url = format!( + "{}/channels/{}/messages/{}/reactions/", + belongs_to.urls.get_api(), + self.channel_id, + self.message_id + ); + let request = Client::new().delete(url).bearer_auth(user.token()); + LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Channel, + &mut belongs_to.limits, + &mut user.limits, + ) + .await + } + + /** + Gets a list of users that reacted with a specific emoji to a message. + + # Arguments + * `emoji` - A string slice containing the emoji to search for. The emoji must be URL Encoded or + the request will fail with 10014: Unknown Emoji. To use custom emoji, you must encode it in the + format name:id with the emoji name and emoji id. + * `user` - A mutable reference to a [`UserMeta`] instance. + + # Returns + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + + # Reference + See [https://discord.com/developers/docs/resources/channel#get-reactions](https://discord.com/developers/docs/resources/channel#get-reactions) + */ + pub async fn get( + &self, + emoji: &str, + user: &mut UserMeta, + ) -> Result { + let mut belongs_to = user.belongs_to.borrow_mut(); + let url = format!( + "{}/channels/{}/messages/{}/reactions/{}/", + belongs_to.urls.get_api(), + self.channel_id, + self.message_id, + emoji + ); + let request = Client::new().get(url).bearer_auth(user.token()); + LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Channel, + &mut belongs_to.limits, + &mut user.limits, + ) + .await + } + + /** + Deletes all the reactions for a given `emoji` on a message. This endpoint requires the + MANAGE_MESSAGES permission to be present on the current user. Fires a `Message Reaction + Remove Emoji` Gateway event. + + # Arguments + * `emoji` - A string slice containing the emoji to delete. The `emoji` must be URL Encoded or + the request will fail with 10014: Unknown Emoji. To use custom emoji, you must encode it in the + format name:id with the emoji name and emoji id. + * `user` - A mutable reference to a [`UserMeta`] instance. + + # Returns + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + + # Reference + See [https://discord.com/developers/docs/resources/channel#delete-all-reactions-for-emoji](https://discord.com/developers/docs/resources/channel#delete-all-reactions-for-emoji) + */ + pub async fn delete_emoji( + &self, + emoji: &str, + user: &mut UserMeta, + ) -> Result { + let mut belongs_to = user.belongs_to.borrow_mut(); + let url = format!( + "{}/channels/{}/messages/{}/reactions/{}/", + belongs_to.urls.get_api(), + self.channel_id, + self.message_id, + emoji + ); + let request = Client::new().delete(url).bearer_auth(user.token()); + LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Channel, + &mut belongs_to.limits, + &mut user.limits, + ) + .await + } +} + +impl types::Reaction { + /** + Create a reaction for the message. + + This endpoint requires the READ_MESSAGE_HISTORY permission + to be present on the current user. Additionally, if nobody else has reacted to the message using + this emoji, this endpoint requires the ADD_REACTIONS permission to be present on the current + user. Fires a Message Reaction Add Gateway event. + + # Arguments + * `emoji` - A string slice containing the emoji to delete. The `emoji` must be URL Encoded or + the request will fail with 10014: Unknown Emoji. To use custom emoji, you must encode it in the + format name:id with the emoji name and emoji id. + * `user` - A mutable reference to a [`UserMeta`] instance. + + # Returns + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + Returns a 204 empty response on success. + + # Reference + See [https://discord.com/developers/docs/resources/channel#create-reaction](https://discord.com/developers/docs/resources/channel#create-reaction) + */ + pub async fn create( + channel_id: &Snowflake, + message_id: &Snowflake, + emoji: &str, + user: &mut UserMeta, + ) -> Result { + let mut belongs_to = user.belongs_to.borrow_mut(); + let url = format!( + "{}/channels/{}/messages/{}/reactions/{}/@me/", + belongs_to.urls.get_api(), + channel_id, + message_id, + emoji + ); + let request = Client::new().put(url).bearer_auth(user.token()); + LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Channel, + &mut belongs_to.limits, + &mut user.limits, + ) + .await + } +}