diff --git a/.gitignore b/.gitignore index d3170e2..1bb4c89 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # Generated by Cargo # will have compiled files and executables -/target/ +/**/target/ # These are backup files generated by rustfmt **/*.rs.bk diff --git a/Cargo.toml b/Cargo.toml index 8dbb172..6c15102 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,19 +10,19 @@ backend = ["poem", "sqlx"] client = [] [dependencies] -tokio = {version = "1.29.1", features = ["macros"]} -serde = {version = "1.0.171", features = ["derive"]} -serde_json = {version= "1.0.103", features = ["raw_value"]} +tokio = { version = "1.29.1", features = ["macros"] } +serde = { version = "1.0.171", features = ["derive", "rc"] } +serde_json = { version = "1.0.103", features = ["raw_value"] } serde-aux = "4.2.0" serde_with = "3.0.0" serde_repr = "0.1.14" -reqwest = {version = "0.11.18", features = ["multipart"]} +reqwest = { version = "0.11.18", features = ["multipart"] } url = "2.4.0" -chrono = {version = "0.4.26", features = ["serde"]} +chrono = { version = "0.4.26", features = ["serde"] } regex = "1.9.1" custom_error = "1.9.2" native-tls = "0.2.11" -tokio-tungstenite = {version = "0.19.0", features = ["native-tls"]} +tokio-tungstenite = { version = "0.19.0", features = ["native-tls"] } futures-util = "0.3.28" http = "0.2.9" openssl = "0.10.55" @@ -31,14 +31,22 @@ hostname = "0.3.1" bitflags = { version = "2.3.3", features = ["serde"] } lazy_static = "1.4.0" poem = { version = "1.3.56", optional = true } -sqlx = { git = "https://github.com/zert3x/sqlx", branch="feature/skip", features = ["mysql", "sqlite", "json", "chrono", "ipnetwork", "runtime-tokio-native-tls", "any"], optional = true } +sqlx = { git = "https://github.com/zert3x/sqlx", branch = "feature/skip", features = [ + "mysql", + "sqlite", + "json", + "chrono", + "ipnetwork", + "runtime-tokio-native-tls", + "any", +], optional = true } thiserror = "1.0.43" jsonwebtoken = "8.3.0" log = "0.4.19" async-trait = "0.1.71" -chorus-macros = {path = "chorus-macros"} +chorus-macros = { path = "chorus-macros" } [dev-dependencies] -tokio = {version = "1.29.1", features = ["full"]} +tokio = { version = "1.29.1", features = ["full"] } lazy_static = "1.4.0" rusty-hook = "0.11.2" diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 68604d9..447e4c0 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::rc::Rc; +use std::sync::{Arc, Mutex}; use reqwest::Client; use serde_json::to_string; @@ -12,6 +13,10 @@ use crate::ratelimiter::ChorusRequest; use crate::types::{GatewayIdentifyPayload, LoginResult, LoginSchema}; impl Instance { + /// Logs into an existing account on the spacebar server. + /// + /// # Reference + /// See pub async fn login_account(&mut self, login_schema: &LoginSchema) -> ChorusResult { let endpoint_url = self.urls.api.clone() + "/auth/login"; let chorus_request = ChorusRequest { @@ -41,7 +46,7 @@ impl Instance { login_result.token, self.clone_limits_if_some(), login_result.settings, - object, + Arc::new(Mutex::new(object)), gateway, ); Ok(user) diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index e818d82..ea74f29 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -1,3 +1,4 @@ +use std::sync::{Arc, Mutex}; use std::{cell::RefCell, rc::Rc}; use reqwest::Client; @@ -14,15 +15,10 @@ use crate::{ }; impl Instance { - /// Registers a new user on the Spacebar server. + /// Registers a new user on the server. /// - /// # Arguments - /// - /// * `register_schema` - The [`RegisterSchema`] that contains all the information that is needed to register a new user. - /// - /// # Errors - /// - /// * [`ChorusLibError`] - If the server does not respond. + /// # Reference + /// See pub async fn register_account( &mut self, register_schema: &RegisterSchema, @@ -56,8 +52,8 @@ impl Instance { Rc::new(RefCell::new(self.clone())), token.clone(), self.clone_limits_if_some(), - settings, - user_object, + Arc::new(Mutex::new(settings)), + Arc::new(Mutex::new(user_object)), gateway, ); Ok(user) diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs index df8e290..0c6f3e3 100644 --- a/src/api/channels/channels.rs +++ b/src/api/channels/channels.rs @@ -11,35 +11,33 @@ use crate::{ }; impl Channel { + /// Retrieves a channel from the server. + /// + /// # Reference + /// See pub async fn get(user: &mut UserMeta, channel_id: Snowflake) -> ChorusResult { let url = user.belongs_to.borrow().urls.api.clone(); let chorus_request = ChorusRequest { request: Client::new() - .get(format!("{}/channels/{}/", url, channel_id)) + .get(format!("{}/channels/{}", url, channel_id)) .bearer_auth(user.token()), limit_type: LimitType::Channel(channel_id), }; chorus_request.deserialize_response::(user).await } - /// Deletes a channel. + /// Deletes self. /// - /// # Arguments + /// Requires the [`MANAGE_CHANNELS`](crate::types::PermissionFlags::MANAGE_CHANNELS) permission in a guild, or + /// the [`MANAGE_THREADS`](crate::types::PermissionFlags::MANAGE_THREADS) permission if the channel is a thread. /// - /// * `token` - A string slice that holds the authorization token. - /// * `url_api` - A string slice that holds the URL of the API. - /// * `channel` - A `Channel` object that represents the channel to be deleted. - /// * `limits_user` - A mutable reference to a `Limits` object that represents the user's rate limits. - /// * `limits_instance` - A mutable reference to a `Limits` object that represents the instance's rate limits. - /// - /// # Returns - /// - /// A `Result` that contains a `ChorusLibError` if an error occurred during the request, or `()` if the request was successful. + /// # Reference + /// See pub async fn delete(self, user: &mut UserMeta) -> ChorusResult<()> { let chorus_request = ChorusRequest { request: Client::new() .delete(format!( - "{}/channels/{}/", + "{}/channels/{}", user.belongs_to.borrow().urls.api, self.id )) @@ -49,20 +47,20 @@ impl Channel { chorus_request.handle_request_as_result(user).await } - /// Modifies a channel. + /// Modifies a channel with the provided data. + /// Returns the new Channel. /// - /// # Arguments + /// Requires the [`MANAGE_CHANNELS`](crate::types::PermissionFlags::MANAGE_CHANNELS) permission in a guild. /// - /// * `modify_data` - A `ChannelModifySchema` object that represents the modifications to be made to the channel. - /// * `token` - A string slice that holds the authorization token. - /// * `url_api` - A string slice that holds the URL of the API. - /// * `channel_id` - A string slice that holds the ID of the channel to be modified. - /// * `limits_user` - A mutable reference to a `Limits` object that represents the user's rate limits. - /// * `limits_instance` - A mutable reference to a `Limits` object that represents the instance's rate limits. + /// If modifying permission overwrites, the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission is required. + /// Only permissions you have in the guild or parent channel (if applicable) can be allowed/denied + /// (unless you have a [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) overwrite in the channel). /// - /// # Returns + /// If modifying a thread and setting `archived` to `false`, when `locked` is also `false`, only the [`SEND_MESSAGES`](crate::types::PermissionFlags::SEND_MESSAGES) permission is required. + /// Otherwise, requires the [`MANAGE_THREADS`](crate::types::PermissionFlags::MANAGE_THREADS) permission. Requires the thread to have `archived` set to `false` or be set to `false` in the request. /// - /// A `Result` that contains a `Channel` object if the request was successful, or an `ChorusLibError` if an error occurred during the request. + /// # Reference + /// See pub async fn modify( &self, modify_data: ChannelModifySchema, @@ -72,7 +70,7 @@ impl Channel { let chorus_request = ChorusRequest { request: Client::new() .patch(format!( - "{}/channels/{}/", + "{}/channels/{}", user.belongs_to.borrow().urls.api, channel_id )) @@ -83,6 +81,15 @@ impl Channel { chorus_request.deserialize_response::(user).await } + /// Fetches recent messages from a channel. + /// + /// If operating on a guild channel, this endpoint requires the [`VIEW_CHANNEL`](crate::types::PermissionFlags::VIEW_CHANNEL) permission. + /// + /// If the user is missing the [`READ_MESSAGE_HISTORY`](crate::types::PermissionFlags::READ_MESSAGE_HISTORY) permission, + /// this method returns an empty list. + /// + /// # Reference + /// See pub async fn messages( range: GetChannelMessagesSchema, channel_id: Snowflake, @@ -105,8 +112,10 @@ impl Channel { .await } + /// Adds a recipient to a group DM. + /// /// # Reference: - /// Read: + /// See pub async fn add_channel_recipient( &self, recipient_id: Snowflake, @@ -115,7 +124,7 @@ impl Channel { ) -> ChorusResult<()> { let mut request = Client::new() .put(format!( - "{}/channels/{}/recipients/{}/", + "{}/channels/{}/recipients/{}", user.belongs_to.borrow().urls.api, self.id, recipient_id @@ -132,8 +141,10 @@ impl Channel { .await } + /// Removes a recipient from a group DM. + /// /// # Reference: - /// Read: + /// See pub async fn remove_channel_recipient( &self, recipient_id: Snowflake, @@ -141,7 +152,7 @@ impl Channel { ) -> ChorusResult<()> { let request = Client::new() .delete(format!( - "{}/channels/{}/recipients/{}/", + "{}/channels/{}/recipients/{}", user.belongs_to.borrow().urls.api, self.id, recipient_id diff --git a/src/api/channels/messages.rs b/src/api/channels/messages.rs index 6beec7f..b93ce2e 100644 --- a/src/api/channels/messages.rs +++ b/src/api/channels/messages.rs @@ -4,22 +4,28 @@ use reqwest::{multipart, Client}; use serde_json::to_string; use crate::api::LimitType; +use crate::errors::ChorusResult; use crate::instance::UserMeta; use crate::ratelimiter::ChorusRequest; use crate::types::{Message, MessageSendSchema, Snowflake}; impl Message { + /// Sends a message in the channel with the provided channel_id. + /// Returns the sent message. + /// + /// # Reference + /// See pub async fn send( user: &mut UserMeta, channel_id: Snowflake, mut message: MessageSendSchema, - ) -> Result { + ) -> ChorusResult { let url_api = user.belongs_to.borrow().urls.api.clone(); if message.attachments.is_none() { let chorus_request = ChorusRequest { request: Client::new() - .post(format!("{}/channels/{}/messages/", url_api, channel_id)) + .post(format!("{}/channels/{}/messages", url_api, channel_id)) .bearer_auth(user.token()) .body(to_string(&message).unwrap()), limit_type: LimitType::Channel(channel_id), @@ -55,7 +61,7 @@ impl Message { let chorus_request = ChorusRequest { request: Client::new() - .post(format!("{}/channels/{}/messages/", url_api, channel_id)) + .post(format!("{}/channels/{}/messages", url_api, channel_id)) .bearer_auth(user.token()) .multipart(form), limit_type: LimitType::Channel(channel_id), @@ -66,11 +72,19 @@ impl Message { } impl UserMeta { + /// Sends a message in the channel with the provided channel_id. + /// Returns the sent message. + /// + /// # Notes + /// Shorthand call for [`Message::send`] + /// + /// # Reference + /// See pub async fn send_message( &mut self, message: MessageSendSchema, channel_id: Snowflake, - ) -> Result { + ) -> ChorusResult { Message::send(self, channel_id, message).await } } diff --git a/src/api/channels/permissions.rs b/src/api/channels/permissions.rs index bc666ff..7c83d85 100644 --- a/src/api/channels/permissions.rs +++ b/src/api/channels/permissions.rs @@ -10,17 +10,16 @@ use crate::{ }; impl types::Channel { - /// Edits the permission overwrites for a channel. + /// Edits the permission overwrites for a user or role in a channel. /// - /// # Arguments + /// Only usable for guild channels. /// - /// * `user` - A mutable reference to a [`UserMeta`] instance. - /// * `channel_id` - A string slice representing the ID of the channel. - /// * `overwrite` - A [`PermissionOverwrite`] instance representing the new permission overwrites. + /// Requires the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission. + /// Only permissions you have in the guild or parent channel (if applicable) can be allowed/denied + /// (unless you have a [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) overwrite in the channel). /// - /// # Returns - /// - /// This function returns a result that is either [`Ok(())`] if the request is successful, or an [`Err(ChorusLibError)`]. + /// # Reference + /// See pub async fn edit_permissions( user: &mut UserMeta, channel_id: Snowflake, @@ -47,17 +46,14 @@ impl types::Channel { chorus_request.handle_request_as_result(user).await } - /// Deletes a permission overwrite for a channel. + /// Deletes a permission overwrite for a user or role in a channel. /// - /// # Arguments + /// Only usable for guild channels. /// - /// * `user` - A mutable reference to a [`UserMeta`] instance. - /// * `channel_id` - A string slice representing the ID of the channel. - /// * `overwrite_id` - A string slice representing the ID of the permission overwrite to delete. + /// Requires the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission. /// - /// # Returns - /// - /// This function returns a Result that is either [`Ok(())`] if the request is successfulm or an [`Err(ChorusLibError)`]. + /// # Reference + /// See pub async fn delete_permission( user: &mut UserMeta, channel_id: Snowflake, diff --git a/src/api/channels/reactions.rs b/src/api/channels/reactions.rs index 35dbb94..05fcea0 100644 --- a/src/api/channels/reactions.rs +++ b/src/api/channels/reactions.rs @@ -8,9 +8,7 @@ use crate::{ types::{self, PublicUser, Snowflake}, }; -/** -Useful metadata for working with [`types::Reaction`], bundled together nicely. - */ +/// Useful metadata for working with [`types::Reaction`], bundled together nicely. pub struct ReactionMeta { pub message_id: types::Snowflake, pub channel_id: types::Snowflake, @@ -18,17 +16,14 @@ pub struct ReactionMeta { impl ReactionMeta { /// Deletes all reactions for a message. - /// This endpoint requires the `MANAGE_MESSAGES` permission to be present on the current user. - /// # Arguments - /// * `user` - A mutable reference to a [`UserMeta`] instance. - /// # Returns - /// A `Result` [`()`] [`crate::errors::ChorusLibError`] if something went wrong. - /// Fires a `Message Reaction Remove All` Gateway event. + /// + /// This endpoint requires the [`MANAGE_MESSAGES`](crate::types::PermissionFlags::MANAGE_MESSAGES) permission. + /// /// # Reference - /// See [https://discord.com/developers/docs/resources/channel#delete-all-reactions](https://discord.com/developers/docs/resources/channel#delete-all-reactions) + /// See pub async fn delete_all(&self, user: &mut UserMeta) -> ChorusResult<()> { let url = format!( - "{}/channels/{}/messages/{}/reactions/", + "{}/channels/{}/messages/{}/reactions", user.belongs_to.borrow().urls.api, self.channel_id, self.message_id @@ -41,18 +36,15 @@ impl ReactionMeta { } /// 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 that is [`Err(crate::errors::ChorusLibError)`] if something went wrong. + /// + /// The emoji must be URL Encoded or the request will fail with 10014: Unknown Emoji. + /// To use custom emoji, the format of the emoji string must be name:id. + /// /// # Reference - /// See [https://discord.com/developers/docs/resources/channel#get-reactions](https://discord.com/developers/docs/resources/channel#get-reactions) + /// See pub async fn get(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult> { let url = format!( - "{}/channels/{}/messages/{}/reactions/{}/", + "{}/channels/{}/messages/{}/reactions/{}", user.belongs_to.borrow().urls.api, self.channel_id, self.message_id, @@ -67,21 +59,18 @@ impl ReactionMeta { .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. - /// # 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 that is [`Err(crate::errors::ChorusLibError)`] if something went wrong. - /// Fires a `Message Reaction Remove Emoji` Gateway event. + /// Deletes all the reactions for a given emoji on a message. + /// + /// This endpoint requires the [`MANAGE_MESSAGES`](crate::types::PermissionFlags::MANAGE_MESSAGES) permission. + /// + /// The emoji must be URL Encoded or the request will fail with 10014: Unknown Emoji. + /// To use custom emoji, the format of the emoji string must be name:id. + /// /// # 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) + /// See pub async fn delete_emoji(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<()> { let url = format!( - "{}/channels/{}/messages/{}/reactions/{}/", + "{}/channels/{}/messages/{}/reactions/{}", user.belongs_to.borrow().urls.api, self.channel_id, self.message_id, @@ -94,24 +83,21 @@ impl ReactionMeta { chorus_request.handle_request_as_result(user).await } - /// 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. - /// # 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 [`()`] or a [`crate::errors::ChorusLibError`]. - /// # Reference - /// See [https://discord.com/developers/docs/resources/channel#create-reaction](https://discord.com/developers/docs/resources/channel#create-reaction) + /// Create a reaction on a message. /// + /// This endpoint requires the [`READ_MESSAGE_HISTORY`](crate::types::PermissionFlags::READ_MESSAGE_HISTORY) permission. + /// + /// Additionally, if nobody else has reacted to the message using this emoji, + /// this endpoint requires the [`ADD_REACTIONS`](crate::types::PermissionFlags::ADD_REACTIONS) permission. + /// + /// The emoji must be URL Encoded or the request will fail with 10014: Unknown Emoji. + /// To use custom emoji, the format of the emoji string must be `name:id`. + /// + /// # Reference + /// See pub async fn create(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<()> { let url = format!( - "{}/channels/{}/messages/{}/reactions/{}/@me/", + "{}/channels/{}/messages/{}/reactions/{}/@me", user.belongs_to.borrow().urls.api, self.channel_id, self.message_id, @@ -124,20 +110,16 @@ impl ReactionMeta { chorus_request.handle_request_as_result(user).await } - /// Delete a reaction the current user has made for the message. - /// # 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 [`()`] or a [`crate::errors::ChorusLibError`]. - /// Fires a `Message Reaction Remove` Gateway event. + /// Deletes a reaction the current user has made to the message. + /// + /// The reaction emoji must be URL Encoded or the request will fail with 10014: Unknown Emoji. + /// To use custom emoji, the format of the emoji string must be name:id. + /// /// # Reference - /// See [https://discord.com/developers/docs/resources/channel#delete-own-reaction](https://discord.com/developers/docs/resources/channel#delete-own-reaction) + /// See pub async fn remove(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<()> { let url = format!( - "{}/channels/{}/messages/{}/reactions/{}/@me/", + "{}/channels/{}/messages/{}/reactions/{}/@me", user.belongs_to.borrow().urls.api, self.channel_id, self.message_id, @@ -150,19 +132,15 @@ impl ReactionMeta { chorus_request.handle_request_as_result(user).await } - /// Delete a user's reaction to a message. - /// This endpoint requires the MANAGE_MESSAGES permission to be present on the current user. - /// # Arguments - /// * `user_id` - ID of the user whose reaction is to be deleted. - /// * `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 [`()`] or a [`crate::errors::ChorusLibError`]. - /// Fires a Message Reaction Remove Gateway event. + /// Deletes a user's reaction to a message. + /// + /// This endpoint requires the [`MANAGE_MESSAGES`](crate::types::PermissionFlags::MANAGE_MESSAGES) permission. + /// + /// The reaction emoji must be URL Encoded or the request will fail with 10014: Unknown Emoji. + /// To use custom emoji, the format of the emoji string must be name:id. + /// /// # Reference - /// See [https://discord.com/developers/docs/resources/channel#delete-own-reaction](https://discord.com/developers/docs/resources/channel#delete-own-reaction) + /// See pub async fn delete_user( &self, user_id: Snowflake, diff --git a/src/api/guilds/guilds.rs b/src/api/guilds/guilds.rs index 3654698..0c8b9cf 100644 --- a/src/api/guilds/guilds.rs +++ b/src/api/guilds/guilds.rs @@ -11,27 +11,15 @@ use crate::types::Snowflake; use crate::types::{Channel, ChannelCreateSchema, Guild, GuildCreateSchema}; impl Guild { - /// Creates a new guild with the given parameters. - /// - /// # Arguments - /// - /// * `user` - A mutable reference to the user creating the guild. - /// * `instance` - A mutable reference to the instance where the guild will be created. - /// * `guild_create_schema` - A reference to the schema containing the guild creation parameters. - /// - /// # Returns - /// - /// A `Result` containing the object of the newly created guild, or an error if the request fails. - /// - /// # Errors - /// - /// Returns an `ChorusLibError` if the request fails. + /// Creates a new guild. /// + /// # Reference + /// See pub async fn create( user: &mut UserMeta, guild_create_schema: GuildCreateSchema, ) -> ChorusResult { - let url = format!("{}/guilds/", user.belongs_to.borrow().urls.api); + let url = format!("{}/guilds", user.belongs_to.borrow().urls.api); let chorus_request = ChorusRequest { request: Client::new() .post(url.clone()) @@ -42,17 +30,9 @@ impl Guild { chorus_request.deserialize_response::(user).await } - /// Deletes a guild. + /// Deletes a guild by its id. /// - /// # Arguments - /// - /// * `user` - A mutable reference to a `User` instance. - /// * `instance` - A mutable reference to an `Instance` instance. - /// * `guild_id` - ID of the guild to delete. - /// - /// # Returns - /// - /// An `Result` containing an `ChorusLibError` if an error occurred during the request, otherwise `()`. + /// User must be the owner. /// /// # Example /// @@ -61,14 +41,17 @@ impl Guild { /// let mut instance = Instance::new(); /// let guild_id = String::from("1234567890"); /// - /// match Guild::delete(&mut user, &mut instance, guild_id) { - /// Some(e) => println!("Error deleting guild: {:?}", e), - /// None => println!("Guild deleted successfully"), + /// match Guild::delete(&mut user, guild_id) { + /// Err(e) => println!("Error deleting guild: {:?}", e), + /// Ok(_) => println!("Guild deleted successfully"), /// } /// ``` + /// + /// # Reference + /// See pub async fn delete(user: &mut UserMeta, guild_id: Snowflake) -> ChorusResult<()> { let url = format!( - "{}/guilds/{}/delete/", + "{}/guilds/{}/delete", user.belongs_to.borrow().urls.api, guild_id ); @@ -81,19 +64,15 @@ impl Guild { chorus_request.handle_request_as_result(user).await } - /// Sends a request to create a new channel in the guild. + /// Creates a new channel in a guild. /// - /// # Arguments + /// Requires the [MANAGE_CHANNELS](crate::types::PermissionFlags::MANAGE_CHANNELS) permission. /// - /// * `url_api` - The base URL for the Discord API. - /// * `token` - A Discord bot token. - /// * `schema` - A `ChannelCreateSchema` struct containing the properties of the new channel. - /// * `limits_user` - A mutable reference to a `Limits` struct containing the user's rate limits. - /// * `limits_instance` - A mutable reference to a `Limits` struct containing the instance's rate limits. + /// # Notes + /// This method is a wrapper for [Channel::create]. /// - /// # Returns - /// - /// A `Result` containing a `reqwest::Response` if the request was successful, or an `ChorusLibError` if there was an error. + /// # Reference + /// See pub async fn create_channel( &self, user: &mut UserMeta, @@ -102,20 +81,17 @@ impl Guild { Channel::create(user, self.id, schema).await } - /// Returns a `Result` containing a vector of `Channel` structs if the request was successful, or an `ChorusLibError` if there was an error. + /// Returns a list of the guild's channels. /// - /// # Arguments - /// - /// * `url_api` - A string slice that holds the URL of the API. - /// * `token` - A string slice that holds the authorization token. - /// * `limits_user` - A mutable reference to a `Limits` struct containing the user's rate limits. - /// * `limits_instance` - A mutable reference to a `Limits` struct containing the instance's rate limits. + /// Doesn't include threads. /// + /// # Reference + /// See pub async fn channels(&self, user: &mut UserMeta) -> ChorusResult> { let chorus_request = ChorusRequest { request: Client::new() .get(format!( - "{}/guilds/{}/channels/", + "{}/guilds/{}/channels", user.belongs_to.borrow().urls.api, self.id )) @@ -141,21 +117,15 @@ impl Guild { }; } - /// Returns a `Result` containing a `Guild` struct if the request was successful, or an `ChorusLibError` if there was an error. - /// - /// # Arguments - /// - /// * `url_api` - A string slice that holds the URL of the API. - /// * `guild_id` - ID of the guild. - /// * `token` - A string slice that holds the authorization token. - /// * `limits_user` - A mutable reference to a `Limits` struct containing the user's rate limits. - /// * `limits_instance` - A mutable reference to a `Limits` struct containing the instance's rate limits. + /// Fetches a guild by its id. /// + /// # Reference + /// See pub async fn get(guild_id: Snowflake, user: &mut UserMeta) -> ChorusResult { let chorus_request = ChorusRequest { request: Client::new() .get(format!( - "{}/guilds/{}/", + "{}/guilds/{}", user.belongs_to.borrow().urls.api, guild_id )) @@ -168,20 +138,12 @@ impl Guild { } impl Channel { - /// Sends a request to create a new channel in a guild. + /// Creates a new channel in a guild. /// - /// # Arguments + /// Requires the [MANAGE_CHANNELS](crate::types::PermissionFlags::MANAGE_CHANNELS) permission. /// - /// * `token` - A Discord bot token. - /// * `url_api` - The base URL for the Discord API. - /// * `guild_id` - The ID of the guild where the channel will be created. - /// * `schema` - A `ChannelCreateSchema` struct containing the properties of the new channel. - /// * `limits_user` - A mutable reference to a `Limits` struct containing the user's rate limits. - /// * `limits_instance` - A mutable reference to a `Limits` struct containing the instance's rate limits. - /// - /// # Returns - /// - /// A `Result` containing a `reqwest::Response` if the request was successful, or an `ChorusLibError` if there was an error. + /// # Reference + /// See pub async fn create( user: &mut UserMeta, guild_id: Snowflake, @@ -190,7 +152,7 @@ impl Channel { let chorus_request = ChorusRequest { request: Client::new() .post(format!( - "{}/guilds/{}/channels/", + "{}/guilds/{}/channels", user.belongs_to.borrow().urls.api, guild_id )) diff --git a/src/api/guilds/member.rs b/src/api/guilds/member.rs index 5fa99cd..28fa68f 100644 --- a/src/api/guilds/member.rs +++ b/src/api/guilds/member.rs @@ -5,28 +5,21 @@ use crate::{ errors::ChorusResult, instance::UserMeta, ratelimiter::ChorusRequest, - types::{self, Snowflake}, + types::{self, GuildMember, Snowflake}, }; impl types::GuildMember { - /// Retrieves a guild member by their ID. + /// Retrieves a guild member. /// - /// # Arguments - /// - /// * `user` - A mutable reference to a [`UserMeta`] instance. - /// * `guild_id` - The ID of the guild. - /// * `member_id` - The ID of the member. - /// - /// # Returns - /// - /// A [`Result`] containing a [`GuildMember`] if the request succeeds, or a [`ChorusLibError`] if the request fails. + /// # Reference + /// See pub async fn get( user: &mut UserMeta, guild_id: Snowflake, member_id: Snowflake, - ) -> ChorusResult { + ) -> ChorusResult { let url = format!( - "{}/guilds/{}/members/{}/", + "{}/guilds/{}/members/{}", user.belongs_to.borrow().urls.api, guild_id, member_id @@ -36,22 +29,16 @@ impl types::GuildMember { limit_type: LimitType::Guild(guild_id), }; chorus_request - .deserialize_response::(user) + .deserialize_response::(user) .await } /// Adds a role to a guild member. /// - /// # Arguments + /// Requires the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission. /// - /// * `user` - A mutable reference to a `UserMeta` instance. - /// * `guild_id` - The ID of the guild. - /// * `member_id` - The ID of the member. - /// * `role_id` - The ID of the role to add. - /// - /// # Returns - /// - /// An `Result` containing a `ChorusLibError` if the request fails, or `()` if the request succeeds. + /// # Reference + /// See pub async fn add_role( user: &mut UserMeta, guild_id: Snowflake, @@ -59,7 +46,7 @@ impl types::GuildMember { role_id: Snowflake, ) -> ChorusResult<()> { let url = format!( - "{}/guilds/{}/members/{}/roles/{}/", + "{}/guilds/{}/members/{}/roles/{}", user.belongs_to.borrow().urls.api, guild_id, member_id, @@ -74,16 +61,10 @@ impl types::GuildMember { /// Removes a role from a guild member. /// - /// # Arguments + /// Requires the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission. /// - /// * `user` - A mutable reference to a `UserMeta` instance. - /// * `guild_id` - The ID of the guild. - /// * `member_id` - The ID of the member. - /// * `role_id` - The ID of the role to remove. - /// - /// # Returns - /// - /// A `Result` containing a `ChorusLibError` if the request fails, or `()` if the request succeeds. + /// # Reference + /// See pub async fn remove_role( user: &mut UserMeta, guild_id: Snowflake, @@ -91,7 +72,7 @@ impl types::GuildMember { role_id: Snowflake, ) -> Result<(), crate::errors::ChorusError> { let url = format!( - "{}/guilds/{}/members/{}/roles/{}/", + "{}/guilds/{}/members/{}/roles/{}", user.belongs_to.borrow().urls.api, guild_id, member_id, diff --git a/src/api/guilds/roles.rs b/src/api/guilds/roles.rs index 1d1bc68..91b7bd4 100644 --- a/src/api/guilds/roles.rs +++ b/src/api/guilds/roles.rs @@ -6,30 +6,20 @@ use crate::{ errors::{ChorusError, ChorusResult}, instance::UserMeta, ratelimiter::ChorusRequest, - types::{self, RoleCreateModifySchema, RoleObject, Snowflake}, + types::{self, RoleCreateModifySchema, RoleObject, RolePositionUpdateSchema, Snowflake}, }; impl types::RoleObject { - /// Retrieves all roles for a given guild. + /// Retrieves a list of roles for a given guild. /// - /// # Arguments - /// - /// * `user` - A mutable reference to a [`UserMeta`] instance. - /// * `guild_id` - The ID of the guild to retrieve roles from. - /// - /// # Returns - /// - /// An `Option` containing a `Vec` of [`RoleObject`]s if roles were found, or `None` if no roles were found. - /// - /// # Errors - /// - /// Returns a [`ChorusLibError`] if the request fails or if the response is invalid. + /// # Reference + /// See pub async fn get_all( user: &mut UserMeta, guild_id: Snowflake, - ) -> ChorusResult>> { + ) -> ChorusResult> { let url = format!( - "{}/guilds/{}/roles/", + "{}/guilds/{}/roles", user.belongs_to.borrow().urls.api, guild_id ); @@ -41,34 +31,20 @@ impl types::RoleObject { .deserialize_response::>(user) .await .unwrap(); - if roles.is_empty() { - return Ok(None); - } - Ok(Some(roles)) + Ok(roles) } /// Retrieves a single role for a given guild. /// - /// # Arguments - /// - /// * `user` - A mutable reference to a [`UserMeta`] instance. - /// * `guild_id` - The ID of the guild to retrieve the role from. - /// * `role_id` - The ID of the role to retrieve. - /// - /// # Returns - /// - /// A `Result` containing the retrieved [`RoleObject`] if successful, or a [`ChorusLibError`] if the request fails or if the response is invalid. - /// - /// # Errors - /// - /// Returns a [`ChorusLibError`] if the request fails or if the response is invalid. + /// # Reference + /// See pub async fn get( user: &mut UserMeta, guild_id: Snowflake, role_id: Snowflake, ) -> ChorusResult { let url = format!( - "{}/guilds/{}/roles/{}/", + "{}/guilds/{}/roles/{}", user.belongs_to.borrow().urls.api, guild_id, role_id @@ -84,26 +60,17 @@ impl types::RoleObject { /// Creates a new role for a given guild. /// - /// # Arguments + /// Requires the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission. /// - /// * `user` - A mutable reference to a [`UserMeta`] instance. - /// * `guild_id` - The ID of the guild to create the role in. - /// * `role_create_schema` - A [`RoleCreateModifySchema`] instance containing the properties of the role to be created. - /// - /// # Returns - /// - /// A `Result` containing the newly created [`RoleObject`] if successful, or a [`ChorusLibError`] if the request fails or if the response is invalid. - /// - /// # Errors - /// - /// Returns a [`ChorusLibError`] if the request fails or if the response is invalid. + /// # Reference + /// See pub async fn create( user: &mut UserMeta, guild_id: Snowflake, role_create_schema: RoleCreateModifySchema, ) -> ChorusResult { let url = format!( - "{}/guilds/{}/roles/", + "{}/guilds/{}/roles", user.belongs_to.borrow().urls.api, guild_id ); @@ -121,28 +88,19 @@ impl types::RoleObject { .await } - /// Updates the position of a role in the guild's hierarchy. + /// Updates the position of a role in a given guild's hierarchy. /// - /// # Arguments + /// Requires the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission. /// - /// * `user` - A mutable reference to a [`UserMeta`] instance. - /// * `guild_id` - The ID of the guild to update the role position in. - /// * `role_position_update_schema` - A [`RolePositionUpdateSchema`] instance containing the new position of the role. - /// - /// # Returns - /// - /// A `Result` containing the updated [`RoleObject`] if successful, or a [`ChorusLibError`] if the request fails or if the response is invalid. - /// - /// # Errors - /// - /// Returns a [`ChorusLibError`] if the request fails or if the response is invalid. + /// # Reference + /// See pub async fn position_update( user: &mut UserMeta, guild_id: Snowflake, - role_position_update_schema: types::RolePositionUpdateSchema, + role_position_update_schema: RolePositionUpdateSchema, ) -> ChorusResult { let url = format!( - "{}/guilds/{}/roles/", + "{}/guilds/{}/roles", user.belongs_to.borrow().urls.api, guild_id ); @@ -164,20 +122,10 @@ impl types::RoleObject { /// Updates a role in a guild. /// - /// # Arguments + /// Requires the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission. /// - /// * `user` - A mutable reference to a [`UserMeta`] instance. - /// * `guild_id` - The ID of the guild to update the role in. - /// * `role_id` - The ID of the role to update. - /// * `role_create_schema` - A [`RoleCreateModifySchema`] instance containing the new properties of the role. - /// - /// # Returns - /// - /// A `Result` containing the updated [`RoleObject`] if successful, or a [`ChorusLibError`] if the request fails or if the response is invalid. - /// - /// # Errors - /// - /// Returns a [`ChorusLibError`] if the request fails or if the response is invalid. + /// # Reference + /// See pub async fn update( user: &mut UserMeta, guild_id: Snowflake, diff --git a/src/api/invites/mod.rs b/src/api/invites/mod.rs index b766a5b..ac9c120 100644 --- a/src/api/invites/mod.rs +++ b/src/api/invites/mod.rs @@ -7,12 +7,12 @@ use crate::ratelimiter::ChorusRequest; use crate::types::{CreateChannelInviteSchema, GuildInvite, Invite, Snowflake}; impl UserMeta { - /// # Arguments - /// - invite_code: The invite code to accept the invite for. - /// - session_id: The session ID that is accepting the invite, required for guest invites. + /// Accepts an invite to a guild, group DM, or DM. + /// + /// Note that the session ID is required for guest invites. /// /// # Reference: - /// Read + /// See pub async fn accept_invite( &mut self, invite_code: &str, @@ -21,7 +21,7 @@ impl UserMeta { let mut request = ChorusRequest { request: Client::new() .post(format!( - "{}/invites/{}/", + "{}/invites/{}", self.belongs_to.borrow().urls.api, invite_code )) @@ -35,12 +35,18 @@ impl UserMeta { } request.deserialize_response::(self).await } + + /// Creates a new friend invite. + /// /// Note: Spacebar does not yet implement this endpoint. + /// + /// # Reference: + /// See pub async fn create_user_invite(&mut self, code: Option<&str>) -> ChorusResult { ChorusRequest { request: Client::new() .post(format!( - "{}/users/@me/invites/", + "{}/users/@me/invites", self.belongs_to.borrow().urls.api )) .body(to_string(&code).unwrap()) @@ -51,7 +57,14 @@ impl UserMeta { .await } - pub async fn create_guild_invite( + /// Creates a new invite for a guild channel or group DM. + /// + /// # Guild Channels + /// For guild channels, the endpoint requires the [`CREATE_INSTANT_INVITE`](crate::types::PermissionFlags::CREATE_INSTANT_INVITE) permission. + /// + /// # Reference + /// See + pub async fn create_channel_invite( &mut self, create_channel_invite_schema: CreateChannelInviteSchema, channel_id: Snowflake, @@ -59,7 +72,7 @@ impl UserMeta { ChorusRequest { request: Client::new() .post(format!( - "{}/channels/{}/invites/", + "{}/channels/{}/invites", self.belongs_to.borrow().urls.api, channel_id )) diff --git a/src/api/policies/instance/instance.rs b/src/api/policies/instance/instance.rs index 75f832c..aa529ad 100644 --- a/src/api/policies/instance/instance.rs +++ b/src/api/policies/instance/instance.rs @@ -6,10 +6,14 @@ use crate::types::GeneralConfiguration; impl Instance { /// Gets the instance policies schema. - /// # Errors - /// [`ChorusLibError`] - If the request fails. + /// + /// # Notes + /// This is a Spacebar only endpoint. + /// + /// # Reference + /// See pub async fn general_configuration_schema(&self) -> ChorusResult { - let endpoint_url = self.urls.api.clone() + "/policies/instance/"; + let endpoint_url = self.urls.api.clone() + "/policies/instance"; let request = match self.client.get(&endpoint_url).send().await { Ok(result) => result, Err(e) => { diff --git a/src/api/policies/instance/ratelimits.rs b/src/api/policies/instance/ratelimits.rs index e32a835..a95a2c6 100644 --- a/src/api/policies/instance/ratelimits.rs +++ b/src/api/policies/instance/ratelimits.rs @@ -24,8 +24,6 @@ pub enum LimitType { } /// A struct that represents the current ratelimits, either instance-wide or user-wide. -/// Unlike [`RateLimits`], this struct shows the current ratelimits, not the rate limit -/// configuration for the instance. /// See for more information. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Limit { diff --git a/src/api/users/channels.rs b/src/api/users/channels.rs index 806bd9f..faa58ad 100644 --- a/src/api/users/channels.rs +++ b/src/api/users/channels.rs @@ -12,8 +12,11 @@ use crate::{ impl UserMeta { /// Creates a DM channel or group DM channel. /// + /// One recipient creates or returns an existing DM channel, + /// none or multiple recipients create a group DM channel. + /// /// # Reference: - /// Read + /// See pub async fn create_private_channel( &mut self, create_private_channel_schema: PrivateChannelCreateSchema, diff --git a/src/api/users/guilds.rs b/src/api/users/guilds.rs index 735ed9e..3967e8e 100644 --- a/src/api/users/guilds.rs +++ b/src/api/users/guilds.rs @@ -7,16 +7,18 @@ use crate::ratelimiter::ChorusRequest; use crate::types::Snowflake; impl UserMeta { - /// # Arguments: - /// - lurking: Whether the user is lurking in the guild + /// Leaves a given guild. /// /// # Reference: - /// Read + /// See + // TODO: Docs: What is "lurking" here? + // It is documented as "Whether the user is lurking in the guild", + // but that says nothing about what this field actually does / means pub async fn leave_guild(&mut self, guild_id: &Snowflake, lurking: bool) -> ChorusResult<()> { ChorusRequest { request: Client::new() .delete(format!( - "{}/users/@me/guilds/{}/", + "{}/users/@me/guilds/{}", self.belongs_to.borrow().urls.api, guild_id )) diff --git a/src/api/users/relationships.rs b/src/api/users/relationships.rs index 39c75d8..41270e1 100644 --- a/src/api/users/relationships.rs +++ b/src/api/users/relationships.rs @@ -6,24 +6,22 @@ use crate::{ errors::ChorusResult, instance::UserMeta, ratelimiter::ChorusRequest, - types::{self, CreateUserRelationshipSchema, RelationshipType, Snowflake}, + types::{ + self, CreateUserRelationshipSchema, FriendRequestSendSchema, RelationshipType, Snowflake, + }, }; impl UserMeta { - /// Retrieves the mutual relationships between the authenticated user and the specified user. + /// Retrieves a list of mutual friends between the authenticated user and a given user. /// - /// # Arguments - /// - /// * `user_id` - ID of the user to retrieve the mutual relationships with. - /// - /// # Returns - /// This function returns a [`ChorusResult>`]. + /// # Reference + /// See pub async fn get_mutual_relationships( &mut self, user_id: Snowflake, ) -> ChorusResult> { let url = format!( - "{}/users/{}/relationships/", + "{}/users/{}/relationships", self.belongs_to.borrow().urls.api, user_id ); @@ -36,13 +34,13 @@ impl UserMeta { .await } - /// Retrieves the authenticated user's relationships. + /// Retrieves the user's relationships. /// - /// # Returns - /// This function returns a [`ChorusResult>`]. + /// # Reference + /// See pub async fn get_relationships(&mut self) -> ChorusResult> { let url = format!( - "{}/users/@me/relationships/", + "{}/users/@me/relationships", self.belongs_to.borrow().urls.api ); let chorus_request = ChorusRequest { @@ -56,18 +54,14 @@ impl UserMeta { /// Sends a friend request to a user. /// - /// # Arguments - /// - /// * `schema` - A [`FriendRequestSendSchema`] struct that holds the information about the friend request to be sent. - /// - /// # Returns - /// This function returns a [`Result`] that holds a [`ChorusLibError`] if the request fails. + /// # Reference + /// See pub async fn send_friend_request( &mut self, - schema: types::FriendRequestSendSchema, + schema: FriendRequestSendSchema, ) -> ChorusResult<()> { let url = format!( - "{}/users/@me/relationships/", + "{}/users/@me/relationships", self.belongs_to.borrow().urls.api ); let body = to_string(&schema).unwrap(); @@ -78,20 +72,9 @@ impl UserMeta { chorus_request.handle_request_as_result(self).await } - /// Modifies the relationship between the authenticated user and the specified user. + /// Modifies the relationship between the authenticated user and a given user. /// - /// # Arguments - /// - /// * `user_id` - ID of the user to modify the relationship with. - /// * `relationship_type` - A [`RelationshipType`] enum that specifies the type of relationship to modify. - /// * [`RelationshipType::None`]: Removes the relationship between the two users. - /// * [`RelationshipType::Friends`] | [`RelationshipType::Incoming`] | [`RelationshipType::Outgoing`]: - /// Either accepts an incoming friend request, or sends a new friend request, if there is no - /// incoming friend request from the specified `user_id`. - /// * [`RelationshipType::Blocked`]: Blocks the specified user_id. - /// - /// # Returns - /// This function returns an [`Result`] that holds a [`ChorusLibError`] if the request fails. + /// Can be used to unfriend users, accept or send friend requests and block or unblock users. pub async fn modify_user_relationship( &mut self, user_id: Snowflake, @@ -102,7 +85,7 @@ impl UserMeta { RelationshipType::None => { let chorus_request = ChorusRequest { request: Client::new() - .delete(format!("{}/users/@me/relationships/{}/", api_url, user_id)) + .delete(format!("{}/users/@me/relationships/{}", api_url, user_id)) .bearer_auth(self.token()), limit_type: LimitType::Global, }; @@ -116,7 +99,7 @@ impl UserMeta { }; let chorus_request = ChorusRequest { request: Client::new() - .put(format!("{}/users/@me/relationships/{}/", api_url, user_id)) + .put(format!("{}/users/@me/relationships/{}", api_url, user_id)) .bearer_auth(self.token()) .body(to_string(&body).unwrap()), limit_type: LimitType::Global, @@ -131,7 +114,7 @@ impl UserMeta { }; let chorus_request = ChorusRequest { request: Client::new() - .put(format!("{}/users/@me/relationships/{}/", api_url, user_id)) + .put(format!("{}/users/@me/relationships/{}", api_url, user_id)) .bearer_auth(self.token()) .body(to_string(&body).unwrap()), limit_type: LimitType::Global, @@ -142,17 +125,13 @@ impl UserMeta { } } - /// Removes the relationship between the authenticated user and the specified user. + /// Removes the relationship between the authenticated user and a given user. /// - /// # Arguments - /// - /// * `user_id` - ID of the user to remove the relationship with. - /// - /// # Returns - /// This function returns a [`Result`] that holds a [`ChorusLibError`] if the request fails. + /// # Reference + /// See pub async fn remove_relationship(&mut self, user_id: Snowflake) -> ChorusResult<()> { let url = format!( - "{}/users/@me/relationships/{}/", + "{}/users/@me/relationships/{}", self.belongs_to.borrow().urls.api, user_id ); diff --git a/src/api/users/users.rs b/src/api/users/users.rs index af6d2ce..fd28b7a 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -1,3 +1,4 @@ +use std::sync::{Arc, Mutex}; use std::{cell::RefCell, rc::Rc}; use reqwest::Client; @@ -12,22 +13,22 @@ use crate::{ }; impl UserMeta { - /// Get a user object by id, or get the current user. + /// Gets a user by id, or if the id is None, gets the current user. /// - /// # Arguments + /// # Notes + /// This function is a wrapper around [`User::get`]. /// - /// * `token` - A valid access token for the API. - /// * `url_api` - The URL to the API. - /// * `id` - The id of the user that will be retrieved. If this is None, the current user will be retrieved. - /// * `instance_limits` - The [`Limits`] of the instance. - /// - /// # Errors - /// - /// * [`ChorusLibError`] - If the request fails. + /// # Reference + /// See and + /// pub async fn get(user: &mut UserMeta, id: Option<&String>) -> ChorusResult { User::get(user, id).await } + /// Gets the user's settings. + /// + /// # Notes + /// This functions is a wrapper around [`User::get_settings`]. pub async fn get_settings( token: &String, url_api: &String, @@ -36,15 +37,10 @@ impl UserMeta { User::get_settings(token, url_api, instance).await } - /// Modify the current user's `UserObject`. + /// Modifies the current user's representation. (See [`User`]) /// - /// # Arguments - /// - /// * `modify_schema` - A `UserModifySchema` object containing the fields to modify. - /// - /// # Errors - /// - /// Returns an `ChorusLibError` if the request fails or if a password is required but not provided. + /// # Reference + /// See pub async fn modify(&mut self, modify_schema: UserModifySchema) -> ChorusResult { if modify_schema.new_password.is_some() || modify_schema.email.is_some() @@ -53,7 +49,7 @@ impl UserMeta { return Err(ChorusError::PasswordRequired); } let request = Client::new() - .patch(format!("{}/users/@me/", self.belongs_to.borrow().urls.api)) + .patch(format!("{}/users/@me", self.belongs_to.borrow().urls.api)) .body(to_string(&modify_schema).unwrap()) .bearer_auth(self.token()); let chorus_request = ChorusRequest { @@ -64,23 +60,18 @@ impl UserMeta { .deserialize_response::(self) .await .unwrap(); - let _ = std::mem::replace(&mut self.object, user_updated.clone()); + self.object = Arc::new(Mutex::new(user_updated.clone())); Ok(user_updated) } - /// Sends a request to the server which deletes the user from the Instance. + /// Deletes the user from the Instance. /// - /// # Arguments - /// - /// * `self` - The `User` object to delete. - /// - /// # Returns - /// - /// Returns `()` if the user was successfully deleted, or a `ChorusLibError` if an error occurred. + /// # Reference + /// See pub async fn delete(mut self) -> ChorusResult<()> { let request = Client::new() .post(format!( - "{}/users/@me/delete/", + "{}/users/@me/delete", self.belongs_to.borrow().urls.api )) .bearer_auth(self.token()); @@ -93,10 +84,15 @@ impl UserMeta { } impl User { + /// Gets a user by id, or if the id is None, gets the current user. + /// + /// # Reference + /// See and + /// pub async fn get(user: &mut UserMeta, id: Option<&String>) -> ChorusResult { let url_api = user.belongs_to.borrow().urls.api.clone(); let url = if id.is_none() { - format!("{}/users/@me/", url_api) + format!("{}/users/@me", url_api) } else { format!("{}/users/{}", url_api, id.unwrap()) }; @@ -114,13 +110,17 @@ impl User { } } + /// Gets the user's settings. + /// + /// # Reference + /// See pub async fn get_settings( token: &String, url_api: &String, instance: &mut Instance, ) -> ChorusResult { let request: reqwest::RequestBuilder = Client::new() - .get(format!("{}/users/@me/settings/", url_api)) + .get(format!("{}/users/@me/settings", url_api)) .bearer_auth(token); let mut user = UserMeta::shell(Rc::new(RefCell::new(instance.clone())), token.clone()).await; @@ -141,16 +141,14 @@ impl User { } impl Instance { - /** - Get a user object by id, or get the current user. - # Arguments - * `token` - A valid access token for the API. - * `id` - The id of the user that will be retrieved. If this is None, the current user will be retrieved. - # Errors - * [`ChorusLibError`] - If the request fails. - # Notes - This function is a wrapper around [`User::get`]. - */ + /// Gets a user by id, or if the id is None, gets the current user. + /// + /// # Notes + /// This function is a wrapper around [`User::get`]. + /// + /// # Reference + /// See and + /// pub async fn get_user(&mut self, token: String, id: Option<&String>) -> ChorusResult { let mut user = UserMeta::shell(Rc::new(RefCell::new(self.clone())), token).await; let result = User::get(&mut user, id).await; diff --git a/src/gateway.rs b/src/gateway.rs index a9a3749..eaac29f 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -78,7 +78,7 @@ const GATEWAY_LAZY_REQUEST: u8 = 14; /// The amount of time we wait for a heartbeat ack before resending our heartbeat in ms const HEARTBEAT_ACK_TIMEOUT: u64 = 2000; -/// Represents a messsage received from the gateway. This will be either a [GatewayReceivePayload], containing events, or a [GatewayError]. +/// Represents a messsage received from the gateway. This will be either a [types::GatewayReceivePayload], containing events, or a [GatewayError]. /// This struct is used internally when handling messages. #[derive(Clone, Debug)] pub struct GatewayMessage { @@ -150,7 +150,7 @@ impl GatewayMessage { /// Represents a handle to a Gateway connection. A Gateway connection will create observable /// [`GatewayEvents`](GatewayEvent), which you can subscribe to. Gateway events include all currently -/// implemented [Types] with the trait [`WebSocketEvent`] +/// implemented types with the trait [`WebSocketEvent`] /// Using this handle you can also send Gateway Events directly. #[derive(Debug)] pub struct GatewayHandle { diff --git a/src/instance.rs b/src/instance.rs index 9795557..5c2e98b 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::fmt; use std::rc::Rc; +use std::sync::{Arc, Mutex}; use reqwest::Client; use serde::{Deserialize, Serialize}; @@ -15,10 +16,8 @@ use crate::types::{GeneralConfiguration, User, UserSettings}; use crate::UrlBundle; #[derive(Debug, Clone)] -/** -The [`Instance`] what you will be using to perform all sorts of actions on the Spacebar server. -If `limits_information` is `None`, then the instance will not be rate limited. - */ +/// The [`Instance`]; what you will be using to perform all sorts of actions on the Spacebar server. +/// If `limits_information` is `None`, then the instance will not be rate limited. pub struct Instance { pub urls: UrlBundle, pub instance_info: GeneralConfiguration, @@ -33,12 +32,7 @@ pub struct LimitsInformation { } impl Instance { - /// Creates a new [`Instance`]. - /// # Arguments - /// * `urls` - The [`URLBundle`] that contains all the URLs that are needed to connect to the Spacebar server. - /// * `requester` - The [`LimitedRequester`] that will be used to make requests to the Spacebar server. - /// # Errors - /// * [`InstanceError`] - If the instance cannot be created. + /// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle), where `limited` is whether or not to automatically use rate limits. pub async fn new(urls: UrlBundle, limited: bool) -> ChorusResult { let limits_information; if limited { @@ -90,12 +84,15 @@ impl fmt::Display for Token { } #[derive(Debug)] +/// A UserMeta is a representation of an authenticated user on an [Instance]. +/// It is used for most authenticated actions on a Spacebar server. +/// It also has its own [Gateway] connection. pub struct UserMeta { pub belongs_to: Rc>, pub token: String, pub limits: Option>, - pub settings: UserSettings, - pub object: User, + pub settings: Arc>, + pub object: Arc>, pub gateway: GatewayHandle, } @@ -108,12 +105,17 @@ impl UserMeta { self.token = token; } + /// Creates a new [UserMeta] from existing data. + /// + /// # Notes + /// This isn't the prefered way to create a UserMeta. + /// See [Instance::login_account] and [Instance::register_account] instead. pub fn new( belongs_to: Rc>, token: String, limits: Option>, - settings: UserSettings, - object: User, + settings: Arc>, + object: Arc>, gateway: GatewayHandle, ) -> UserMeta { UserMeta { @@ -132,8 +134,8 @@ impl UserMeta { /// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify /// first. pub(crate) async fn shell(instance: Rc>, token: String) -> UserMeta { - let settings = UserSettings::default(); - let object = User::default(); + let settings = Arc::new(Mutex::new(UserSettings::default())); + let object = Arc::new(Mutex::new(User::default())); let wss_url = instance.borrow().urls.wss.clone(); // Dummy gateway object let gateway = Gateway::new(wss_url).await.unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 77425b8..6563bed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,15 +16,25 @@ pub mod types; pub mod voice; #[derive(Clone, Default, Debug, PartialEq, Eq)] -/// A URLBundle is a struct which bundles together the API-, Gateway- and CDN-URLs of a Spacebar -/// instance. +/// A URLBundle bundles together the API-, Gateway- and CDN-URLs of a Spacebar instance. +/// +/// # Notes +/// All the urls can be found on the /api/policies/instance/domains endpoint of a spacebar server pub struct UrlBundle { + /// The api's url. + /// Ex: `https://old.server.spacebar.chat/api` pub api: String, + /// The gateway websocket url. + /// Note that because this is a websocket url, it will always start with `wss://` or `ws://` + /// Ex: `wss://gateway.old.server.spacebar.chat` pub wss: String, + /// The CDN's url. + /// Ex: `https://cdn.old.server.spacebar.chat` pub cdn: String, } impl UrlBundle { + /// Creates a new UrlBundle from the relevant urls. pub fn new(api: String, wss: String, cdn: String) -> Self { Self { api: UrlBundle::parse_url(api), @@ -33,9 +43,10 @@ impl UrlBundle { } } - /// parse(url: String) parses a URL using the Url library and formats it in a standardized - /// way. If no protocol is given, HTTP (not HTTPS) is assumed. - /// # Example: + /// Parses a URL using the Url library and formats it in a standardized way. + /// If no protocol is given, HTTP (not HTTPS) is assumed. + /// + /// # Examples: /// ```rs /// let url = parse_url("localhost:3000"); /// ``` diff --git a/src/ratelimiter.rs b/src/ratelimiter.rs index 9227737..2c1ecd0 100644 --- a/src/ratelimiter.rs +++ b/src/ratelimiter.rs @@ -237,6 +237,9 @@ impl ChorusRequest { /// reset to the rate limit limit. /// 2. The remaining rate limit is decreased by 1. fn update_rate_limits(user: &mut UserMeta, limit_type: &LimitType, response_was_err: bool) { + if user.belongs_to.borrow().limits_information.is_none() { + return; + } let instance_dictated_limits = [ &LimitType::AuthLogin, &LimitType::AuthRegister, @@ -292,6 +295,13 @@ impl ChorusRequest { } } + /// Gets the ratelimit configuration. + /// + /// # Notes + /// This is a spacebar only endpoint. + /// + /// # Reference + /// See pub(crate) async fn get_limits_config(url_api: &str) -> ChorusResult { let request = Client::new() .get(format!("{}/policies/instance/limits/", url_api)) diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index 6cac20b..ad48ab4 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use bitflags::bitflags; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -6,8 +8,10 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::utils::Snowflake; use crate::types::{Team, User}; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// # Reference +/// See pub struct Application { pub id: Snowflake, pub name: String, @@ -23,7 +27,7 @@ pub struct Application { pub bot_require_code_grant: bool, pub verify_key: String, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub owner: User, + pub owner: Arc>, pub flags: u64, #[cfg(feature = "sqlx")] pub redirect_uris: Option>>, @@ -45,7 +49,7 @@ pub struct Application { #[cfg(feature = "sqlx")] pub install_params: Option>, #[cfg(not(feature = "sqlx"))] - pub install_params: Option, + pub install_params: Option>>, pub terms_of_service_url: Option, pub privacy_policy_url: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] @@ -93,44 +97,64 @@ impl Application { } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +/// # Reference +/// See pub struct InstallParams { pub scopes: Vec, pub permissions: String, } bitflags! { - #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] + #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] + /// # Reference + /// See pub struct ApplicationFlags: u64 { + /// Indicates if an app uses the Auto Moderation API const APPLICATION_AUTO_MODERATION_RULE_CREATE_BADGE = 1 << 6; + /// Intent required for bots in 100 or more servers to receive presence_update events const GATEWAY_PRESENCE = 1 << 12; + /// Intent required for bots in under 100 servers to receive presence_update events, found on the Bot page in your app's settings on discord.com const GATEWAY_PRESENCE_LIMITED = 1 << 13; + /// Intent required for bots in 100 or more servers to receive member-related events like guild_member_add. + /// See the list of member-related events under GUILD_MEMBERS const GATEWAY_GUILD_MEMBERS = 1 << 14; + /// Intent required for bots in under 100 servers to receive member-related events like guild_member_add, found on the Bot page in your app's settings on discord.com. + /// See the list of member-related events under GUILD_MEMBERS const GATEWAY_GUILD_MEMBERS_LIMITED = 1 << 15; + /// Indicates unusual growth of an app that prevents verification const VERIFICATION_PENDING_GUILD_LIMIT = 1 << 16; + /// Indicates if an app is embedded within the Discord client (currently unavailable publicly) const EMBEDDED = 1 << 17; + /// Intent required for bots in 100 or more servers to receive message content const GATEWAY_MESSAGE_CONTENT = 1 << 18; + /// Intent required for bots in under 100 servers to receive message content, found on the Bot page in your app's settings on discord.com const GATEWAY_MESSAGE_CONTENT_LIMITED = 1 << 19; + /// Indicates if an app has registered slash commands const APPLICATION_COMMAND_BADGE = 1 << 23; } } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] +/// # Reference +/// See pub struct ApplicationCommand { pub id: Snowflake, pub application_id: Snowflake, pub name: String, pub description: String, - pub options: Vec, + pub options: Vec>>, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] +/// Reference +/// See pub struct ApplicationCommandOption { pub r#type: ApplicationCommandOptionType, pub name: String, pub description: String, pub required: bool, pub choices: Vec, - pub options: Vec, + pub options: Arc>>, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] @@ -139,45 +163,54 @@ pub struct ApplicationCommandOptionChoice { pub value: Value, } -#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)] +#[derive(Debug, Clone, Copy, Serialize_repr, Deserialize_repr, PartialEq, Eq, Hash)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[repr(i32)] +/// # Reference +/// See pub enum ApplicationCommandOptionType { SubCommand = 1, SubCommandGroup = 2, String = 3, + /// Any integer between -2^53 and 2^53 Integer = 4, Boolean = 5, User = 6, + /// Includes all channel types + categories Channel = 7, Role = 8, + /// Includes users and roles + Mentionable = 9, + /// Any double between -2^53 and 2^53 + Number = 10, + Attachment = 11, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApplicationCommandInteractionData { pub id: Snowflake, pub name: String, - pub options: Vec, + pub options: Vec>>, } -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ApplicationCommandInteractionDataOption { pub name: String, pub value: Value, - pub options: Vec, + pub options: Vec>>, } -#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] -/// See https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +/// See pub struct GuildApplicationCommandPermissions { pub id: Snowflake, pub application_id: Snowflake, pub guild_id: Snowflake, - pub permissions: Vec, + pub permissions: Vec>>, } #[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] -/// See https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-structure +/// See pub struct ApplicationCommandPermission { pub id: Snowflake, #[serde(rename = "type")] @@ -186,10 +219,10 @@ pub struct ApplicationCommandPermission { pub permission: bool, } -#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq)] +#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone, PartialEq, Eq, Hash)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[repr(u8)] -/// See https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permission-type +/// See pub enum ApplicationCommandPermissionType { #[default] Role = 1, diff --git a/src/types/entities/attachment.rs b/src/types/entities/attachment.rs index 7bd9d2b..75ec860 100644 --- a/src/types/entities/attachment.rs +++ b/src/types/entities/attachment.rs @@ -4,9 +4,12 @@ use crate::types::utils::Snowflake; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// # Reference +/// See pub struct Attachment { pub id: Snowflake, pub filename: String, + /// Max 1024 characters pub description: Option, pub content_type: Option, pub size: u64, @@ -15,7 +18,13 @@ pub struct Attachment { pub height: Option, pub width: Option, pub ephemeral: Option, + /// The duration of the audio file (only for voice messages) pub duration_secs: Option, + /// A Base64 encoded bytearray representing a sampled waveform (only for voice messages) + /// + /// # Notes + /// Note that this is computed on the client side. + /// This means it can be spoofed and isn't necessarily accurate. pub waveform: Option, #[serde(skip_serializing)] #[cfg_attr(feature = "sqlx", sqlx(default))] @@ -26,6 +35,7 @@ pub struct Attachment { pub struct PartialDiscordFileAttachment { pub id: Option, pub filename: String, + /// Max 1024 characters pub description: Option, pub content_type: Option, pub size: Option, @@ -34,18 +44,20 @@ pub struct PartialDiscordFileAttachment { pub height: Option, pub width: Option, pub ephemeral: Option, + /// The duration of the audio file (only for voice messages) pub duration_secs: Option, + /// A Base64 encoded bytearray representing a sampled waveform (only for voice messages) + /// + /// # Notes + /// Note that this is computed on the client side. + /// This means it can be spoofed and isn't necessarily accurate. pub waveform: Option, #[serde(skip_serializing)] pub content: Vec, } impl PartialDiscordFileAttachment { - /** - Moves `self.content` out of `self` and returns it. - # Returns - Vec - */ + /// Moves `self.content` out of `self` and returns it. pub fn move_content(self) -> (Vec, PartialDiscordFileAttachment) { let content = self.content; let updated_struct = PartialDiscordFileAttachment { @@ -66,6 +78,7 @@ impl PartialDiscordFileAttachment { (content, updated_struct) } + /// Moves `self.filename` out of `self` and returns it. pub fn move_filename(self) -> (String, PartialDiscordFileAttachment) { let filename = self.filename; let updated_struct = PartialDiscordFileAttachment { @@ -87,6 +100,7 @@ impl PartialDiscordFileAttachment { (filename, updated_struct) } + /// Moves `self.content_type` out of `self` and returns it. pub fn move_content_type(self) -> (Option, PartialDiscordFileAttachment) { let content_type = self.content_type; let updated_struct = PartialDiscordFileAttachment { diff --git a/src/types/entities/audit_log.rs b/src/types/entities/audit_log.rs index 1e04e8b..e0d05e3 100644 --- a/src/types/entities/audit_log.rs +++ b/src/types/entities/audit_log.rs @@ -1,12 +1,14 @@ +use std::sync::{Arc, Mutex}; + use serde::{Deserialize, Serialize}; use crate::types::utils::Snowflake; #[derive(Serialize, Deserialize, Debug, Default, Clone)] -/// See https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object +/// See pub struct AuditLogEntry { pub target_id: Option, - pub changes: Option>, + pub changes: Option>>>, pub user_id: Option, pub id: Snowflake, // to:do implement an enum for these types @@ -17,7 +19,7 @@ pub struct AuditLogEntry { } #[derive(Serialize, Deserialize, Debug, Default, Clone)] -/// See https://discord.com/developers/docs/resources/audit-log#audit-log-change-object +/// See pub struct AuditLogChange { pub new_value: Option, pub old_value: Option, diff --git a/src/types/entities/auto_moderation.rs b/src/types/entities/auto_moderation.rs index 144aa4b..afb1ec6 100644 --- a/src/types/entities/auto_moderation.rs +++ b/src/types/entities/auto_moderation.rs @@ -1,10 +1,12 @@ +use std::sync::{Arc, Mutex}; + use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::utils::Snowflake; #[derive(Serialize, Deserialize, Debug, Default, Clone)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object +/// See pub struct AutoModerationRule { pub id: Snowflake, pub guild_id: Snowflake, @@ -12,8 +14,8 @@ pub struct AutoModerationRule { pub creator_id: Snowflake, pub event_type: AutoModerationRuleEventType, pub trigger_type: AutoModerationRuleTriggerType, - pub trigger_metadata: AutoModerationRuleTriggerMetadata, - pub actions: Vec, + pub trigger_metadata: Arc>, + pub actions: Vec>>, pub enabled: bool, pub exempt_roles: Vec, pub exempt_channels: Vec, @@ -22,7 +24,7 @@ pub struct AutoModerationRule { #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-event-types +/// See pub enum AutoModerationRuleEventType { #[default] MessageSend = 1, @@ -31,7 +33,7 @@ pub enum AutoModerationRuleEventType { #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types +/// See pub enum AutoModerationRuleTriggerType { #[default] Keyword = 1, @@ -42,7 +44,7 @@ pub enum AutoModerationRuleTriggerType { #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(untagged)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata +/// See pub enum AutoModerationRuleTriggerMetadata { ForKeyword(AutoModerationRuleTriggerMetadataForKeyword), ForKeywordPreset(AutoModerationRuleTriggerMetadataForKeywordPreset), @@ -52,7 +54,7 @@ pub enum AutoModerationRuleTriggerMetadata { } #[derive(Serialize, Deserialize, Debug, Clone, Default)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata +/// See pub struct AutoModerationRuleTriggerMetadataForKeyword { pub keyword_filter: Vec, pub regex_patterns: Vec, @@ -60,14 +62,14 @@ pub struct AutoModerationRuleTriggerMetadataForKeyword { } #[derive(Serialize, Deserialize, Debug, Clone, Default)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata +/// See pub struct AutoModerationRuleTriggerMetadataForKeywordPreset { pub presets: Vec, pub allow_list: Vec, } #[derive(Serialize, Deserialize, Debug, Clone, Default)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata +/// See pub struct AutoModerationRuleTriggerMetadataForMentionSpam { /// Max 50 pub mention_total_limit: u8, @@ -77,7 +79,7 @@ pub struct AutoModerationRuleTriggerMetadataForMentionSpam { #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-preset-types +/// See pub enum AutoModerationRuleKeywordPresetType { #[default] Profanity = 1, @@ -86,17 +88,17 @@ pub enum AutoModerationRuleKeywordPresetType { } #[derive(Serialize, Deserialize, Debug, Clone, Default)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object +/// See pub struct AutoModerationAction { #[serde(rename = "type")] pub action_type: AutoModerationActionType, - pub metadata: Option, + pub metadata: Option>>, } #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-types +/// See pub enum AutoModerationActionType { #[default] BlockMessage = 1, @@ -106,7 +108,7 @@ pub enum AutoModerationActionType { #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(untagged)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata +/// See pub enum AutoModerationActionMetadata { ForBlockMessage(AutoModerationActionMetadataForBlockMessage), ForSendAlertMessage(AutoModerationActionMetadataForSendAlertMessage), @@ -116,19 +118,19 @@ pub enum AutoModerationActionMetadata { } #[derive(Serialize, Deserialize, Debug, Clone, Default)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata +/// See pub struct AutoModerationActionMetadataForBlockMessage { pub custom_message: Option, } #[derive(Serialize, Deserialize, Debug, Clone, Default)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata +/// See pub struct AutoModerationActionMetadataForSendAlertMessage { pub channel_id: Snowflake, } #[derive(Serialize, Deserialize, Debug, Clone, Default)] -/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata +/// See pub struct AutoModerationActionMetadataForTimeout { /// Max 2419200 pub duration_seconds: u32, diff --git a/src/types/entities/channel.rs b/src/types/entities/channel.rs index 154b83c..61754f0 100644 --- a/src/types/entities/channel.rs +++ b/src/types/entities/channel.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use chorus_macros::Updateable; use chrono::Utc; use serde::{Deserialize, Serialize}; @@ -10,8 +12,12 @@ use crate::types::{ utils::Snowflake, }; -#[derive(Default, Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Updateable)] +#[derive(Default, Debug, Serialize, Deserialize, Clone, Updateable)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// Represents a guild of private channel +/// +/// # Reference +/// See pub struct Channel { pub application_id: Option, #[cfg(feature = "sqlx")] @@ -42,7 +48,7 @@ pub struct Channel { pub last_pin_timestamp: Option, pub managed: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub member: Option, + pub member: Option>>, pub member_count: Option, pub message_count: Option, pub name: Option, @@ -52,12 +58,12 @@ pub struct Channel { #[cfg(feature = "sqlx")] pub permission_overwrites: Option>>, #[cfg(not(feature = "sqlx"))] - pub permission_overwrites: Option>, + pub permission_overwrites: Option>>>, pub permissions: Option, pub position: Option, pub rate_limit_per_user: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub recipients: Option>, + pub recipients: Option>>>, pub rtc_region: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub thread_metadata: Option, @@ -67,10 +73,50 @@ pub struct Channel { pub video_quality_mode: Option, } -#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +impl PartialEq for Channel { + fn eq(&self, other: &Self) -> bool { + self.application_id == other.application_id + && self.bitrate == other.bitrate + && self.channel_type == other.channel_type + && self.created_at == other.created_at + && self.default_auto_archive_duration == other.default_auto_archive_duration + && self.default_forum_layout == other.default_forum_layout + && self.default_sort_order == other.default_sort_order + && self.default_thread_rate_limit_per_user == other.default_thread_rate_limit_per_user + && self.flags == other.flags + && self.guild_id == other.guild_id + && self.icon == other.icon + && self.id == other.id + && self.last_message_id == other.last_message_id + && self.last_pin_timestamp == other.last_pin_timestamp + && self.managed == other.managed + && self.member_count == other.member_count + && self.message_count == other.message_count + && self.name == other.name + && self.nsfw == other.nsfw + && self.owner_id == other.owner_id + && self.parent_id == other.parent_id + && self.permissions == other.permissions + && self.position == other.position + && self.rate_limit_per_user == other.rate_limit_per_user + && self.rtc_region == other.rtc_region + && self.topic == other.topic + && self.total_message_sent == other.total_message_sent + && self.user_limit == other.user_limit + && self.video_quality_mode == other.video_quality_mode + } +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +/// A tag that can be applied to a thread in a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel. +/// +/// # Reference +/// See pub struct Tag { pub id: Snowflake, + /// The name of the tag (max 20 characters) pub name: String, + /// Whether this tag can only be added to or removed from threads by members with the [MANAGE_THREADS](crate::types::PermissionFlags::MANAGE_THREADS) permission pub moderated: bool, pub emoji_id: Option, pub emoji_name: Option, @@ -91,6 +137,8 @@ pub struct PermissionOverwrite { } #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// # Reference +/// See pub struct ThreadMetadata { pub archived: bool, pub auto_archive_duration: i32, @@ -100,47 +148,81 @@ pub struct ThreadMetadata { pub create_timestamp: Option, } -#[derive(Default, Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +#[derive(Default, Debug, Deserialize, Serialize, Clone)] +/// # Reference +/// See pub struct ThreadMember { pub id: Option, pub user_id: Option, pub join_timestamp: Option, pub flags: Option, - pub member: Option, + pub member: Option>>, } #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +/// Specifies the emoji to use as the default way to react to a [ChannelType::GuildForum] or [ChannelType::GuildMedia] channel post. +/// +/// # Reference +/// See pub struct DefaultReaction { #[serde(default)] pub emoji_id: Option, pub emoji_name: Option, } -#[derive(Default, Clone, Copy, Debug, Serialize_repr, Deserialize_repr, PartialEq, Eq)] +#[derive(Default, Clone, Copy, Debug, Serialize_repr, Deserialize_repr, PartialEq, Eq, Hash)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[repr(i32)] +/// # Reference +/// See pub enum ChannelType { #[default] + /// A text channel within a guild GuildText = 0, + /// A private channel between two users Dm = 1, + /// A voice channel within a guild GuildVoice = 2, + /// A private channel between multiple users GroupDm = 3, + /// An organizational category that contains up to 50 channels GuildCategory = 4, + /// Similar to [GuildText](ChannelType::GuildText), a channel that users can follow and crosspost into their own guild GuildNews = 5, + /// A channel in which game developers can sell their game on Discord + /// + /// # Note + /// Deprecated. GuildStore = 6, + // FIXME userdoccers says 7 is GuildLfg, is this a spacebar specific thing? Encrypted = 7, + // FIXME userdoccers says 8 is LfgGuildDm, is this a spacebar specific thing? EncryptedThreads = 8, + // FIXME userdoccers says 9 is ThreadAlpha, was this changed? Transactional = 9, + /// A thread within a [GuildNews](ChannelType::GuildNews) channel GuildNewsThread = 10, + /// A thread within a [GuildText](ChannelType::GuildText), [GuildForum](ChannelType::GuildForum), or [GuildMedia](ChannelType::GuildMedia) channel GuildPublicThread = 11, + /// A thread within a [GuildText](ChannelType::GuildText) channel, that is only viewable by those invited and those with the [MANAGE_THREADS](crate::types::entities::PermissionFlags::MANAGE_THREADS) permission GuildPrivateThread = 12, + /// A voice channel for hosting events with an audience in a guild GuildStageVoice = 13, + /// The main channel in a hub containing the listed guilds Directory = 14, + /// A channel that can only contain threads GuildForum = 15, + /// A channel that can only contain threads in a gallery view + GuildMedia = 16, + // TODO: Couldn't find reference TicketTracker = 33, + // TODO: Couldn't find reference Kanban = 34, + // TODO: Couldn't find reference VoicelessWhiteboard = 35, + // TODO: Couldn't find reference CustomStart = 64, + // TODO: Couldn't find reference Unhandled = 255, } diff --git a/src/types/entities/emoji.rs b/src/types/entities/emoji.rs index a0e8d14..38d7da7 100644 --- a/src/types/entities/emoji.rs +++ b/src/types/entities/emoji.rs @@ -1,10 +1,14 @@ +use std::sync::{Arc, Mutex}; + use serde::{Deserialize, Serialize}; use crate::types::entities::User; use crate::types::Snowflake; -#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize, Default)] +#[derive(Debug, Clone, Deserialize, Serialize, Default)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// # Reference +/// See pub struct Emoji { pub id: Option, pub name: Option, @@ -13,7 +17,7 @@ pub struct Emoji { #[cfg(not(feature = "sqlx"))] pub roles: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub user: Option, + pub user: Option>>, pub require_colons: Option, pub managed: Option, pub animated: Option, diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 67e7f44..651884f 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; @@ -9,8 +11,8 @@ use crate::types::{ utils::Snowflake, }; -/// See https://discord.com/developers/docs/resources/guild -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +/// See +#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Guild { pub afk_channel_id: Option, @@ -25,13 +27,13 @@ pub struct Guild { #[cfg_attr(feature = "sqlx", sqlx(skip))] pub bans: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub channels: Option>, + pub channels: Option>>>, pub default_message_notifications: Option, pub description: Option, pub discovery_splash: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] #[serde(default)] - pub emojis: Vec, + pub emojis: Vec>>, pub explicit_content_filter: Option, //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] pub features: Option, @@ -40,7 +42,7 @@ pub struct Guild { pub icon_hash: Option, pub id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub invites: Option>, + pub invites: Option>>>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub joined_at: Option, pub large: Option, @@ -66,7 +68,7 @@ pub struct Guild { pub public_updates_channel_id: Option, pub region: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub roles: Option>, + pub roles: Option>>>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub rules_channel: Option, pub rules_channel_id: Option, @@ -79,18 +81,18 @@ pub struct Guild { pub vanity_url_code: Option, pub verification_level: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub voice_states: Option>, + pub voice_states: Option>>>, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub webhooks: Option>, + pub webhooks: Option>>>, #[cfg(feature = "sqlx")] pub welcome_screen: Option>, #[cfg(not(feature = "sqlx"))] - pub welcome_screen: Option, + pub welcome_screen: Option>>, pub widget_channel_id: Option, pub widget_enabled: Option, } -/// See https://docs.spacebar.chat/routes/#get-/guilds/-guild_id-/bans/-user- +/// See #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct GuildBan { @@ -99,8 +101,8 @@ pub struct GuildBan { pub reason: Option, } -/// See https://docs.spacebar.chat/routes/#cmp--schemas-invite -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +/// See +#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct GuildInvite { pub code: String, @@ -111,11 +113,11 @@ pub struct GuildInvite { pub created_at: DateTime, pub expires_at: Option>, pub guild_id: Snowflake, - pub guild: Option, + pub guild: Option>>, pub channel_id: Snowflake, - pub channel: Option, + pub channel: Option>>, pub inviter_id: Option, - pub inviter: Option, + pub inviter: Option>>, pub target_user_id: Option, pub target_user: Option, pub target_user_type: Option, @@ -134,7 +136,7 @@ pub struct GuildCreateResponse { } #[derive(Serialize, Deserialize, Debug, Default, Clone)] -/// See https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object +/// See pub struct GuildScheduledEvent { pub id: Snowflake, pub guild_id: Snowflake, @@ -149,14 +151,14 @@ pub struct GuildScheduledEvent { pub entity_type: GuildScheduledEventEntityType, pub entity_id: Option, pub entity_metadata: Option, - pub creator: Option, + pub creator: Option>>, pub user_count: Option, pub image: Option, } #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] #[repr(u8)] -/// See https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-privacy-level +/// See pub enum GuildScheduledEventPrivacyLevel { #[default] GuildOnly = 2, @@ -164,7 +166,7 @@ pub enum GuildScheduledEventPrivacyLevel { #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] #[repr(u8)] -/// See https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-status +/// See pub enum GuildScheduledEventStatus { #[default] Scheduled = 1, @@ -175,7 +177,7 @@ pub enum GuildScheduledEventStatus { #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] #[repr(u8)] -/// See https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-types +/// See pub enum GuildScheduledEventEntityType { #[default] StageInstance = 1, @@ -184,7 +186,7 @@ pub enum GuildScheduledEventEntityType { } #[derive(Serialize, Deserialize, Debug, Default, Clone)] -/// See https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-metadata +/// See pub struct GuildScheduledEventEntityMetadata { pub location: Option, } diff --git a/src/types/entities/guild_member.rs b/src/types/entities/guild_member.rs index 01f43de..af63cfb 100644 --- a/src/types/entities/guild_member.rs +++ b/src/types/entities/guild_member.rs @@ -1,10 +1,16 @@ +use std::sync::{Arc, Mutex}; + use serde::{Deserialize, Serialize}; use crate::types::{entities::PublicUser, Snowflake}; -#[derive(Debug, Deserialize, Default, Serialize, Clone, PartialEq, Eq)] +#[derive(Debug, Deserialize, Default, Serialize, Clone)] +/// Represents a participating user in a guild. +/// +/// # Reference +/// See pub struct GuildMember { - pub user: Option, + pub user: Option>>, pub nick: Option, pub avatar: Option, pub roles: Vec, diff --git a/src/types/entities/integration.rs b/src/types/entities/integration.rs index 8076e70..a95c33c 100644 --- a/src/types/entities/integration.rs +++ b/src/types/entities/integration.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -8,7 +10,7 @@ use crate::types::{ #[derive(Default, Debug, Deserialize, Serialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] -/// See https://discord.com/developers/docs/resources/guild#integration-object-integration-structure +/// See pub struct Integration { pub id: Snowflake, pub name: String, @@ -21,19 +23,19 @@ pub struct Integration { pub expire_behaviour: Option, pub expire_grace_period: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub user: Option, + pub user: Option>>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub account: IntegrationAccount, pub synced_at: Option>, pub subscriber_count: Option, pub revoked: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub application: Option, + pub application: Option>>, pub scopes: Option>, } #[derive(Default, Debug, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/resources/guild#integration-account-object-integration-account-structure +/// See pub struct IntegrationAccount { pub id: String, pub name: String, diff --git a/src/types/entities/invite.rs b/src/types/entities/invite.rs index 6d7b570..7eefd98 100644 --- a/src/types/entities/invite.rs +++ b/src/types/entities/invite.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -68,7 +70,7 @@ pub enum NSFWLevel { /// See #[derive(Debug, Serialize, Deserialize)] pub struct InviteStageInstance { - pub members: Vec, + pub members: Vec>>, pub participant_count: i32, pub speaker_count: i32, pub topic: String, diff --git a/src/types/entities/message.rs b/src/types/entities/message.rs index 745d001..f104f97 100644 --- a/src/types/entities/message.rs +++ b/src/types/entities/message.rs @@ -8,8 +8,12 @@ use crate::types::{ utils::Snowflake, }; -#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// Represents a message sent in a channel. +/// +/// # Reference +/// See pub struct Message { pub id: Snowflake, pub channel_id: Snowflake, @@ -64,6 +68,8 @@ pub struct Message { } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +/// # Reference +/// See pub struct MessageReference { pub message_id: Snowflake, pub channel_id: Snowflake, @@ -71,7 +77,7 @@ pub struct MessageReference { pub fail_if_not_exists: Option, } -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct MessageInteraction { pub id: Snowflake, #[serde(rename = "type")] @@ -106,7 +112,7 @@ pub struct ChannelMention { name: String, } -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Embed { title: Option, #[serde(rename = "type")] @@ -176,10 +182,13 @@ pub struct EmbedField { inline: Option, } -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Reaction { - pub count: i32, + pub count: u32, + pub burst_count: u32, pub me: bool, + pub burst_me: bool, + pub burst_colors: Vec, pub emoji: Emoji, } @@ -196,6 +205,8 @@ pub enum Component { } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +/// # Reference +/// See pub struct MessageActivity { #[serde(rename = "type")] pub activity_type: i64, diff --git a/src/types/entities/relationship.rs b/src/types/entities/relationship.rs index a6abc09..a5f5bcb 100644 --- a/src/types/entities/relationship.rs +++ b/src/types/entities/relationship.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; @@ -6,20 +8,29 @@ use crate::types::Snowflake; use super::PublicUser; -#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq, Eq)] -/// See https://discord-userdoccers.vercel.app/resources/user#relationship-structure +#[derive(Debug, Deserialize, Serialize, Clone, Default)] +/// See pub struct Relationship { pub id: Snowflake, #[serde(rename = "type")] pub relationship_type: RelationshipType, pub nickname: Option, - pub user: PublicUser, + pub user: Arc>, pub since: Option>, } +impl PartialEq for Relationship { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + && self.relationship_type == other.relationship_type + && self.since == other.since + && self.nickname == other.nickname + } +} + #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Eq, PartialEq)] #[repr(u8)] -/// See https://discord-userdoccers.vercel.app/resources/user#relationship-type +/// See pub enum RelationshipType { Suggestion = 6, Implicit = 5, diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 1719d28..3ad53ce 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -6,7 +6,7 @@ use crate::types::utils::Snowflake; #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] -/// See https://discord.com/developers/docs/topics/permissions#role-object +/// See pub struct RoleObject { pub id: Snowflake, pub name: String, @@ -34,8 +34,8 @@ pub struct RoleSubscriptionData { pub is_renewal: bool, } -#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)] -/// See https://discord.com/developers/docs/topics/permissions#role-object-role-tags-structure +#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)] +/// See pub struct RoleTags { #[serde(default)] #[serde(deserialize_with = "deserialize_option_number_from_string")] @@ -53,57 +53,110 @@ pub struct RoleTags { } bitflags! { - #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] + #[derive(Debug, Default, Clone, Hash, Serialize, Deserialize, PartialEq, Eq)] + /// Permissions limit what users of certain roles can do on a Guild to Guild basis. + /// + /// # Reference: + /// See pub struct PermissionFlags: u64 { + /// Allows creation of instant invites const CREATE_INSTANT_INVITE = 1 << 0; + /// Allows kicking members const KICK_MEMBERS = 1 << 1; + /// Allows banning members const BAN_MEMBERS = 1 << 2; + /// Allows all permissions and bypasses channel permission overwrites const ADMINISTRATOR = 1 << 3; + /// Allows management and editing of channels const MANAGE_CHANNELS = 1 << 4; + /// Allows management and editing of the guild and guild settings const MANAGE_GUILD = 1 << 5; + /// Allows for the addition of reactions to messages const ADD_REACTIONS = 1 << 6; + /// Allows viewing of the audit log const VIEW_AUDIT_LOG = 1 << 7; + /// Allows using priority speaker in a voice channel const PRIORITY_SPEAKER = 1 << 8; + /// Allows the user to go live and share their screen const STREAM = 1 << 9; + /// Allows guild members to view a channel, which includes reading messages in text channels and joining voice channels const VIEW_CHANNEL = 1 << 10; + /// Allows sending messages in a channel and creating threads in a forum (does not allow sending messages in threads) const SEND_MESSAGES = 1 << 11; + /// Allows sending /tts messages const SEND_TTS_MESSAGES = 1 << 12; + /// Allows deletion of other users' messages const MANAGE_MESSAGES = 1 << 13; + /// Links sent by users with this permission will be auto-embedded const EMBED_LINKS = 1 << 14; + /// Allows uploading images and files const ATTACH_FILES = 1 << 15; + /// Allows reading of message history const READ_MESSAGE_HISTORY = 1 << 16; + /// Allows using the @everyone tag to notify all users in a channel, and the @here tag to notify all online users in a channel const MENTION_EVERYONE = 1 << 17; + /// Allows the usage of custom emojis from other servers const USE_EXTERNAL_EMOJIS = 1 << 18; + /// Allows viewing guild insights const VIEW_GUILD_INSIGHTS = 1 << 19; + /// Allows joining of a voice channel const CONNECT = 1 << 20; + /// Allows speaking in a voice channel const SPEAK = 1 << 21; + /// Allows muting members in a voice channel const MUTE_MEMBERS = 1 << 22; + /// Allows deafening of members in a voice channel const DEAFEN_MEMBERS = 1 << 23; + /// Allows moving of members between voice channels const MOVE_MEMBERS = 1 << 24; + /// Allows using voice activity (VAD = voice-activity-detection) in a voice channel const USE_VAD = 1 << 25; + /// Allows modification of own nickname const CHANGE_NICKNAME = 1 << 26; + /// Allows modification of other users' nicknames const MANAGE_NICKNAMES = 1 << 27; + /// Allows management and editing of roles const MANAGE_ROLES = 1 << 28; + /// Allows management and editing of webhooks const MANAGE_WEBHOOKS = 1 << 29; + /// Allows management and editing of emojis, stickers, and soundboard sounds const MANAGE_GUILD_EXPRESSIONS = 1 << 30; + /// Allows members to use application commands, including slash commands and context menu commands. const USE_APPLICATION_COMMANDS = 1 << 31; + /// Allows requesting to speak in stage channels. (*This permission is under active development and may be changed or removed.*) const REQUEST_TO_SPEAK = 1 << 32; + /// Allows creating, editing, and deleting scheduled events const MANAGE_EVENTS = 1 << 33; + /// Allows deleting and archiving threads, and viewing all private threads const MANAGE_THREADS = 1 << 34; + /// Allows creating public and announcement threads const CREATE_PUBLIC_THREADS = 1 << 35; + /// Allows creating private threads const CREATE_PRIVATE_THREADS = 1 << 36; + /// Allows the usage of custom stickers from other servers const USE_EXTERNAL_STICKERS = 1 << 37; + /// Allows sending messages in threads const SEND_MESSAGES_IN_THREADS = 1 << 38; + /// Allows using Activities in a voice channel const USE_EMBEDDED_ACTIVITIES = 1 << 39; + /// Allows timing out users to prevent them from sending or reacting to messages in chat and threads, and from speaking in voice and stage channels const MODERATE_MEMBERS = 1 << 40; + /// Allows viewing role subscription insights const VIEW_CREATOR_MONETIZATION_ANALYTICS = 1 << 41; + /// Allows using the soundboard in a voice channel const USE_SOUNDBOARD = 1 << 42; + /// Allows using custom soundboard sounds from other servers const USE_EXTERNAL_SOUNDS = 1 << 45; + /// Allows sending voice messages const SEND_VOICE_MESSAGES = 1 << 46; } } impl PermissionFlags { + /// Returns if the PermissionFlags object has specific permissions + /// + /// # Notes + /// Note that if the object has the [PermissionFlags::ADMINISTRATOR] permission, this always returns true pub fn has_permission(&self, permission: PermissionFlags) -> bool { self.contains(permission) || self.contains(PermissionFlags::ADMINISTRATOR) } @@ -114,6 +167,7 @@ impl PermissionFlags { } /// Creates a String of Permissions from a given [`Vec`] of [`PermissionFlags`]. + /// /// # Example: /// ``` /// use chorus::types::{PermissionFlags}; diff --git a/src/types/entities/stage_instance.rs b/src/types/entities/stage_instance.rs index b2d19c3..8810f52 100644 --- a/src/types/entities/stage_instance.rs +++ b/src/types/entities/stage_instance.rs @@ -4,12 +4,12 @@ use serde_repr::{Deserialize_repr, Serialize_repr}; use crate::types::Snowflake; #[derive(Serialize, Deserialize, Debug, Default, Clone)] -/// See https://discord.com/developers/docs/resources/stage-instance +/// See pub struct StageInstance { pub id: Snowflake, pub guild_id: Snowflake, pub channel_id: Snowflake, - /// 1 - 120 chars + /// 1 - 120 characters pub topic: String, pub privacy_level: StageInstancePrivacyLevel, /// deprecated, apparently @@ -20,7 +20,7 @@ pub struct StageInstance { #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[repr(u8)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] -/// See https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level +/// See pub enum StageInstancePrivacyLevel { /// deprecated, apparently Public = 1, diff --git a/src/types/entities/sticker.rs b/src/types/entities/sticker.rs index 098394d..42edb7f 100644 --- a/src/types/entities/sticker.rs +++ b/src/types/entities/sticker.rs @@ -1,9 +1,15 @@ +use std::sync::{Arc, Mutex}; + use serde::{Deserialize, Serialize}; use crate::types::{entities::User, utils::Snowflake}; -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] +#[derive(Debug, Serialize, Deserialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] +/// Represents a sticker that can be sent in messages. +/// +/// # Reference +/// See pub struct Sticker { #[serde(default)] pub id: Snowflake, @@ -18,11 +24,17 @@ pub struct Sticker { pub available: Option, pub guild_id: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub user: Option, + pub user: Option>>, pub sort_value: Option, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +/// A partial sticker object. +/// +/// Represents the smallest amount of data required to render a sticker. +/// +/// # Reference +/// See pub struct StickerItem { pub id: Snowflake, pub name: String, diff --git a/src/types/entities/team.rs b/src/types/entities/team.rs index a6f2ef1..fe6562b 100644 --- a/src/types/entities/team.rs +++ b/src/types/entities/team.rs @@ -1,9 +1,11 @@ +use std::sync::{Arc, Mutex}; + use serde::{Deserialize, Serialize}; use crate::types::entities::User; use crate::types::Snowflake; -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Team { pub icon: Option, @@ -14,10 +16,10 @@ pub struct Team { pub owner_user_id: Snowflake, } -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct TeamMember { pub membership_state: u8, pub permissions: Vec, pub team_id: Snowflake, - pub user: User, + pub user: Arc>, } diff --git a/src/types/entities/template.rs b/src/types/entities/template.rs index b6eb3e9..0550e9e 100644 --- a/src/types/entities/template.rs +++ b/src/types/entities/template.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -6,8 +8,8 @@ use crate::types::{ utils::Snowflake, }; -/// See https://docs.spacebar.chat/routes/#cmp--schemas-template -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +/// See +#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct GuildTemplate { pub code: String, @@ -16,13 +18,13 @@ pub struct GuildTemplate { pub usage_count: Option, pub creator_id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub creator: User, + pub creator: Arc>, pub created_at: DateTime, pub updated_at: DateTime, pub source_guild_id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub source_guild: Vec, + pub source_guild: Vec>>, // Unsure how a {recursive: Guild} looks like, might be a Vec? #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub serialized_source_guild: Vec, + pub serialized_source_guild: Vec>>, } diff --git a/src/types/entities/user.rs b/src/types/entities/user.rs index 469c45e..5b31b6d 100644 --- a/src/types/entities/user.rs +++ b/src/types/entities/user.rs @@ -91,7 +91,7 @@ impl From for PublicUser { const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32; bitflags::bitflags! { - #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] + #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))] pub struct UserFlags: u64 { const DISCORD_EMPLOYEE = 1 << 0; diff --git a/src/types/entities/user_settings.rs b/src/types/entities/user_settings.rs index 40b936a..4705a92 100644 --- a/src/types/entities/user_settings.rs +++ b/src/types/entities/user_settings.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use chrono::{serde::ts_milliseconds_option, Utc}; use serde::{Deserialize, Serialize}; @@ -28,7 +30,7 @@ pub enum UserTheme { Light, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct UserSettings { pub afk_timeout: u16, @@ -73,7 +75,7 @@ pub struct UserSettings { #[cfg(not(feature = "sqlx"))] pub restricted_guilds: Vec, pub show_current_game: bool, - pub status: UserStatus, + pub status: Arc>, pub stream_notifications_enabled: bool, pub theme: UserTheme, pub timezone_offset: i16, @@ -109,7 +111,7 @@ impl Default for UserSettings { render_reactions: true, restricted_guilds: Default::default(), show_current_game: true, - status: UserStatus::Online, + status: Arc::new(Mutex::new(UserStatus::Online)), stream_notifications_enabled: false, theme: UserTheme::Dark, timezone_offset: 0, @@ -138,7 +140,7 @@ impl Default for FriendSourceFlags { } } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct GuildFolder { pub color: u32, pub guild_ids: Vec, @@ -149,5 +151,5 @@ pub struct GuildFolder { #[derive(Debug, Serialize, Deserialize)] pub struct LoginResult { pub token: String, - pub settings: UserSettings, + pub settings: Arc>, } diff --git a/src/types/entities/voice_state.rs b/src/types/entities/voice_state.rs index aafc07f..29b8e6e 100644 --- a/src/types/entities/voice_state.rs +++ b/src/types/entities/voice_state.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -6,15 +8,15 @@ use crate::types::{ utils::Snowflake, }; -/// See https://docs.spacebar.chat/routes/#cmp--schemas-voicestate -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +/// See +#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct VoiceState { pub guild_id: Option, pub guild: Option, pub channel_id: Option, pub user_id: Snowflake, - pub member: Option, + pub member: Option>>, pub session_id: Snowflake, pub token: Option, pub deaf: bool, diff --git a/src/types/entities/webhook.rs b/src/types/entities/webhook.rs index 521b93f..f8b6530 100644 --- a/src/types/entities/webhook.rs +++ b/src/types/entities/webhook.rs @@ -1,3 +1,5 @@ +use std::sync::{Arc, Mutex}; + use serde::{Deserialize, Serialize}; use crate::types::{ @@ -5,8 +7,8 @@ use crate::types::{ utils::Snowflake, }; -/// See https://docs.spacebar.chat/routes/#cmp--schemas-webhook -#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] +/// See +#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Webhook { pub id: Snowflake, @@ -20,10 +22,10 @@ pub struct Webhook { pub application_id: Snowflake, #[serde(skip_serializing_if = "Option::is_none")] #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub user: Option, + pub user: Option>>, #[serde(skip_serializing_if = "Option::is_none")] #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub source_guild: Option, + pub source_guild: Option>>, #[serde(skip_serializing_if = "Option::is_none")] pub url: Option, } diff --git a/src/types/events/application.rs b/src/types/events/application.rs index 8afb374..7fee577 100644 --- a/src/types/events/application.rs +++ b/src/types/events/application.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{GuildApplicationCommandPermissions, WebSocketEvent}; #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#application-command-permissions-update +/// See pub struct ApplicationCommandPermissionsUpdate { #[serde(flatten)] pub permissions: GuildApplicationCommandPermissions, diff --git a/src/types/events/auto_moderation.rs b/src/types/events/auto_moderation.rs index d82aa02..0a1600b 100644 --- a/src/types/events/auto_moderation.rs +++ b/src/types/events/auto_moderation.rs @@ -6,7 +6,7 @@ use crate::types::{ }; #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-create +/// See pub struct AutoModerationRuleCreate { #[serde(flatten)] pub rule: AutoModerationRule, @@ -15,7 +15,7 @@ pub struct AutoModerationRuleCreate { impl WebSocketEvent for AutoModerationRuleCreate {} #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update +/// See pub struct AutoModerationRuleUpdate { #[serde(flatten)] pub rule: AutoModerationRule, @@ -24,7 +24,7 @@ pub struct AutoModerationRuleUpdate { impl WebSocketEvent for AutoModerationRuleUpdate {} #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-delete +/// See pub struct AutoModerationRuleDelete { #[serde(flatten)] pub rule: AutoModerationRule, @@ -33,7 +33,7 @@ pub struct AutoModerationRuleDelete { impl WebSocketEvent for AutoModerationRuleDelete {} #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#auto-moderation-action-execution +/// See pub struct AutoModerationActionExecution { pub guild_id: Snowflake, pub action: AutoModerationAction, diff --git a/src/types/events/call.rs b/src/types/events/call.rs index 67225fb..e37c19d 100644 --- a/src/types/events/call.rs +++ b/src/types/events/call.rs @@ -50,7 +50,7 @@ impl WebSocketEvent for CallDelete {} #[derive(Debug, Deserialize, Serialize, Default, Clone)] /// Officially Undocumented; -/// See https://unofficial-discord-docs.vercel.app/gateway/op13; +/// See ; /// /// Ex: {"op":13,"d":{"channel_id":"837609115475771392"}} pub struct CallSync { diff --git a/src/types/events/channel.rs b/src/types/events/channel.rs index b595d57..002230c 100644 --- a/src/types/events/channel.rs +++ b/src/types/events/channel.rs @@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize}; use super::UpdateMessage; #[derive(Debug, Default, Deserialize, Serialize)] -/// See https://discord.com/developers/docs/topics/gateway-events#channel-pins-update +/// See pub struct ChannelPinsUpdate { pub guild_id: Option, pub channel_id: Snowflake, @@ -16,7 +16,7 @@ pub struct ChannelPinsUpdate { impl WebSocketEvent for ChannelPinsUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#channel-create +/// See pub struct ChannelCreate { #[serde(flatten)] pub channel: Channel, @@ -25,7 +25,7 @@ pub struct ChannelCreate { impl WebSocketEvent for ChannelCreate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#channel-update +/// See pub struct ChannelUpdate { #[serde(flatten)] pub channel: Channel, @@ -53,7 +53,7 @@ pub struct ChannelUnreadUpdate { #[derive(Debug, Default, Deserialize, Serialize, Clone)] /// Contains very few fields from [Channel] -/// See also [ChannelUnreadUpdates] +/// See also [ChannelUnreadUpdate] pub struct ChannelUnreadUpdateObject { pub id: Snowflake, pub last_message_id: Snowflake, @@ -63,7 +63,7 @@ pub struct ChannelUnreadUpdateObject { impl WebSocketEvent for ChannelUnreadUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#channel-delete +/// See pub struct ChannelDelete { #[serde(flatten)] pub channel: Channel, diff --git a/src/types/events/guild.rs b/src/types/events/guild.rs index ae69681..2cbdbd0 100644 --- a/src/types/events/guild.rs +++ b/src/types/events/guild.rs @@ -10,7 +10,7 @@ use crate::types::{ use super::PresenceUpdate; #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-create; +/// See ; /// Received to give data about a guild; // This one is particularly painful, it can be a Guild object with an extra field or an unavailable guild object pub struct GuildCreate { @@ -34,7 +34,7 @@ impl Default for GuildCreateDataOption { impl WebSocketEvent for GuildCreate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-ban-add-guild-ban-add-event-fields; +/// See ; /// Received to give info about a user being banned from a guild; pub struct GuildBanAdd { pub guild_id: Snowflake, @@ -44,7 +44,7 @@ pub struct GuildBanAdd { impl WebSocketEvent for GuildBanAdd {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-ban-remove; +/// See ; /// Received to give info about a user being unbanned from a guild; pub struct GuildBanRemove { pub guild_id: Snowflake, @@ -54,7 +54,7 @@ pub struct GuildBanRemove { impl WebSocketEvent for GuildBanRemove {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-update; +/// See ; /// Received to give info about a guild being updated; pub struct GuildUpdate { #[serde(flatten)] @@ -64,7 +64,7 @@ pub struct GuildUpdate { impl WebSocketEvent for GuildUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-delete; +/// See ; /// Received to tell the client about a guild being deleted; pub struct GuildDelete { #[serde(flatten)] @@ -74,7 +74,7 @@ pub struct GuildDelete { impl WebSocketEvent for GuildDelete {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-audit-log-entry-create; +/// See ; /// Received to the client about an audit log entry being added; pub struct GuildAuditLogEntryCreate { #[serde(flatten)] @@ -84,7 +84,7 @@ pub struct GuildAuditLogEntryCreate { impl WebSocketEvent for GuildAuditLogEntryCreate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-emojis-update; +/// See ; /// Received to tell the client about a change to a guild's emoji list; pub struct GuildEmojisUpdate { pub guild_id: Snowflake, @@ -94,7 +94,7 @@ pub struct GuildEmojisUpdate { impl WebSocketEvent for GuildEmojisUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-stickers-update; +/// See ; /// Received to tell the client about a change to a guild's sticker list; pub struct GuildStickersUpdate { pub guild_id: Snowflake, @@ -104,7 +104,7 @@ pub struct GuildStickersUpdate { impl WebSocketEvent for GuildStickersUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-integrations-update +/// See pub struct GuildIntegrationsUpdate { pub guild_id: Snowflake, } @@ -112,7 +112,7 @@ pub struct GuildIntegrationsUpdate { impl WebSocketEvent for GuildIntegrationsUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-member-add; +/// See ; /// Received to tell the client about a user joining a guild; pub struct GuildMemberAdd { #[serde(flatten)] @@ -123,7 +123,7 @@ pub struct GuildMemberAdd { impl WebSocketEvent for GuildMemberAdd {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-member-remove; +/// See ; /// Received to tell the client about a user leaving a guild; pub struct GuildMemberRemove { pub guild_id: Snowflake, @@ -133,7 +133,7 @@ pub struct GuildMemberRemove { impl WebSocketEvent for GuildMemberRemove {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-member-update +/// See pub struct GuildMemberUpdate { pub guild_id: Snowflake, pub roles: Vec, @@ -151,7 +151,7 @@ pub struct GuildMemberUpdate { impl WebSocketEvent for GuildMemberUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-members-chunk +/// See pub struct GuildMembersChunk { pub guild_id: Snowflake, pub members: Vec, @@ -165,7 +165,7 @@ pub struct GuildMembersChunk { impl WebSocketEvent for GuildMembersChunk {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-role-create +/// See pub struct GuildRoleCreate { pub guild_id: Snowflake, pub role: RoleObject, @@ -174,7 +174,7 @@ pub struct GuildRoleCreate { impl WebSocketEvent for GuildRoleCreate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-role-update +/// See pub struct GuildRoleUpdate { pub guild_id: Snowflake, pub role: RoleObject, @@ -183,7 +183,7 @@ pub struct GuildRoleUpdate { impl WebSocketEvent for GuildRoleUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-role-delete +/// See pub struct GuildRoleDelete { pub guild_id: Snowflake, pub role_id: Snowflake, @@ -192,7 +192,7 @@ pub struct GuildRoleDelete { impl WebSocketEvent for GuildRoleDelete {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-create +/// See pub struct GuildScheduledEventCreate { #[serde(flatten)] pub event: GuildScheduledEvent, @@ -201,7 +201,7 @@ pub struct GuildScheduledEventCreate { impl WebSocketEvent for GuildScheduledEventCreate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-update +/// See pub struct GuildScheduledEventUpdate { #[serde(flatten)] pub event: GuildScheduledEvent, @@ -210,7 +210,7 @@ pub struct GuildScheduledEventUpdate { impl WebSocketEvent for GuildScheduledEventUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-delete +/// See pub struct GuildScheduledEventDelete { #[serde(flatten)] pub event: GuildScheduledEvent, @@ -219,7 +219,7 @@ pub struct GuildScheduledEventDelete { impl WebSocketEvent for GuildScheduledEventDelete {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-add +/// See pub struct GuildScheduledEventUserAdd { pub guild_scheduled_event_id: Snowflake, pub user_id: Snowflake, @@ -229,7 +229,7 @@ pub struct GuildScheduledEventUserAdd { impl WebSocketEvent for GuildScheduledEventUserAdd {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-remove +/// See pub struct GuildScheduledEventUserRemove { pub guild_scheduled_event_id: Snowflake, pub user_id: Snowflake, diff --git a/src/types/events/integration.rs b/src/types/events/integration.rs index de55a5b..2423e78 100644 --- a/src/types/events/integration.rs +++ b/src/types/events/integration.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{Integration, Snowflake, WebSocketEvent}; #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#integration-create +/// See pub struct IntegrationCreate { #[serde(flatten)] pub integration: Integration, @@ -13,7 +13,7 @@ pub struct IntegrationCreate { impl WebSocketEvent for IntegrationCreate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#integration-update +/// See pub struct IntegrationUpdate { #[serde(flatten)] pub integration: Integration, @@ -23,7 +23,7 @@ pub struct IntegrationUpdate { impl WebSocketEvent for IntegrationUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#integration-delete +/// See pub struct IntegrationDelete { pub id: Snowflake, pub guild_id: Snowflake, diff --git a/src/types/events/interaction.rs b/src/types/events/interaction.rs index e77ee7c..304e7d4 100644 --- a/src/types/events/interaction.rs +++ b/src/types/events/interaction.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{Interaction, WebSocketEvent}; #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#interaction-create +/// See pub struct InteractionCreate { #[serde(flatten)] pub interaction: Interaction, diff --git a/src/types/events/invite.rs b/src/types/events/invite.rs index f04134d..674cc62 100644 --- a/src/types/events/invite.rs +++ b/src/types/events/invite.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{GuildInvite, Snowflake, WebSocketEvent}; #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#invite-create +/// See pub struct InviteCreate { #[serde(flatten)] pub invite: GuildInvite, @@ -12,7 +12,7 @@ pub struct InviteCreate { impl WebSocketEvent for InviteCreate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#invite-delete +/// See pub struct InviteDelete { pub channel_id: Snowflake, pub guild_id: Option, diff --git a/src/types/events/lazy_request.rs b/src/types/events/lazy_request.rs index 2fd98af..fd53183 100644 --- a/src/types/events/lazy_request.rs +++ b/src/types/events/lazy_request.rs @@ -13,7 +13,7 @@ use super::WebSocketEvent; /// Sent by the official client when switching to a guild or channel; /// After this, you should recieve message updates /// -/// See https://luna.gitlab.io/discord-unofficial-docs/lazy_guilds.html#op-14-lazy-request +/// See /// /// {"op":14,"d":{"guild_id":"848582562217590824","typing":true,"activities":true,"threads":true}} pub struct LazyRequest { diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 5a67417..fac083b 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -8,6 +8,8 @@ use crate::types::{ use super::WebSocketEvent; #[derive(Debug, Deserialize, Serialize, Default, Clone)] +/// # Reference +/// See pub struct TypingStartEvent { pub channel_id: Snowflake, pub guild_id: Option, @@ -19,92 +21,106 @@ pub struct TypingStartEvent { impl WebSocketEvent for TypingStartEvent {} #[derive(Debug, Serialize, Deserialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#message-create +/// See pub struct MessageCreate { #[serde(flatten)] - message: Message, - guild_id: Option, - member: Option, - mentions: Option>, + pub message: Message, + pub guild_id: Option, + pub member: Option, + pub mentions: Option>, } #[derive(Debug, Serialize, Deserialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#message-create-message-create-extra-fields +/// See pub struct MessageCreateUser { #[serde(flatten)] - user: PublicUser, - member: Option, + pub user: PublicUser, + pub member: Option, } impl WebSocketEvent for MessageCreate {} #[derive(Debug, Serialize, Deserialize, Default, Clone)] +/// # Reference +/// See pub struct MessageUpdate { #[serde(flatten)] - message: Message, - guild_id: Option, - member: Option, - mentions: Option>, + pub message: Message, + pub guild_id: Option, + pub member: Option, + pub mentions: Option>, } impl WebSocketEvent for MessageUpdate {} #[derive(Debug, Serialize, Deserialize, Default, Clone)] +/// # Reference +/// See pub struct MessageDelete { - id: Snowflake, - channel_id: Snowflake, - guild_id: Option, + pub id: Snowflake, + pub channel_id: Snowflake, + pub guild_id: Option, } impl WebSocketEvent for MessageDelete {} #[derive(Debug, Serialize, Deserialize, Default, Clone)] +/// # Reference +/// See pub struct MessageDeleteBulk { - ids: Vec, - channel_id: Snowflake, - guild_id: Option, + pub ids: Vec, + pub channel_id: Snowflake, + pub guild_id: Option, } impl WebSocketEvent for MessageDeleteBulk {} #[derive(Debug, Serialize, Deserialize, Default, Clone)] +/// # Reference +/// See pub struct MessageReactionAdd { - user_id: Snowflake, - channel_id: Snowflake, - message_id: Snowflake, - guild_id: Option, - member: Option, - emoji: Emoji, + pub user_id: Snowflake, + pub channel_id: Snowflake, + pub message_id: Snowflake, + pub guild_id: Option, + pub member: Option, + pub emoji: Emoji, } impl WebSocketEvent for MessageReactionAdd {} #[derive(Debug, Serialize, Deserialize, Default, Clone)] +/// # Reference +/// See pub struct MessageReactionRemove { - user_id: Snowflake, - channel_id: Snowflake, - message_id: Snowflake, - guild_id: Option, - emoji: Emoji, + pub user_id: Snowflake, + pub channel_id: Snowflake, + pub message_id: Snowflake, + pub guild_id: Option, + pub emoji: Emoji, } impl WebSocketEvent for MessageReactionRemove {} #[derive(Debug, Serialize, Deserialize, Default, Clone)] +/// # Reference +/// See pub struct MessageReactionRemoveAll { - channel_id: Snowflake, - message_id: Snowflake, - guild_id: Option, + pub channel_id: Snowflake, + pub message_id: Snowflake, + pub guild_id: Option, } impl WebSocketEvent for MessageReactionRemoveAll {} #[derive(Debug, Serialize, Deserialize, Default, Clone)] +/// # Reference +/// See pub struct MessageReactionRemoveEmoji { - channel_id: Snowflake, - message_id: Snowflake, - guild_id: Option, - emoji: Emoji, + pub channel_id: Snowflake, + pub message_id: Snowflake, + pub guild_id: Option, + pub emoji: Emoji, } impl WebSocketEvent for MessageReactionRemoveEmoji {} @@ -114,7 +130,7 @@ impl WebSocketEvent for MessageReactionRemoveEmoji {} /// /// Not documented anywhere unofficially /// -/// Apparently "Message ACK refers to marking a message as read for Discord's API." (https://github.com/Rapptz/discord.py/issues/1851) +/// Apparently "Message ACK refers to marking a message as read for Discord's API." () /// I suspect this is sent and recieved from the gateway to let clients on other devices know the user has read a message /// /// {"t":"MESSAGE_ACK","s":3,"op":0,"d":{"version":52,"message_id":"1107236673638633472","last_viewed":null,"flags":null,"channel_id":"967363950217936897"}} diff --git a/src/types/events/mod.rs b/src/types/events/mod.rs index 42e3912..d477800 100644 --- a/src/types/events/mod.rs +++ b/src/types/events/mod.rs @@ -61,7 +61,7 @@ pub trait WebSocketEvent {} #[derive(Debug, Default, Serialize, Clone)] /// The payload used for sending events to the gateway /// -/// Similar to [GatewayReceivePayload], except we send a [Value] for d whilst we receive a [serde_json::value::RawValue] +/// Similar to [GatewayReceivePayload], except we send a [serde_json::value::Value] for d whilst we receive a [serde_json::value::RawValue] /// Also, we never need to send the event name pub struct GatewaySendPayload { #[serde(rename = "op")] @@ -80,9 +80,6 @@ impl WebSocketEvent for GatewaySendPayload {} #[derive(Debug, Default, Deserialize, Clone)] /// The payload used for receiving events from the gateway -/// -/// Similar to [GatewaySendPayload], except we send a [Value] for d whilst we receive a [serde_json::value::RawValue] -/// Also, we never need to sent the event name pub struct GatewayReceivePayload<'a> { #[serde(rename = "op")] pub op_code: u8, diff --git a/src/types/events/presence.rs b/src/types/events/presence.rs index ad06954..c2d985e 100644 --- a/src/types/events/presence.rs +++ b/src/types/events/presence.rs @@ -4,9 +4,9 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Default, Clone)] /// Sent by the client to update its status and presence; -/// See https://discord.com/developers/docs/topics/gateway-events#update-presence +/// See pub struct UpdatePresence { - /// unix time of when the client went idle, or none if client is not idle + /// Unix time of when the client went idle, or none if client is not idle. pub since: Option, /// the client's status (online, invisible, offline, dnd, idle..) pub status: UserStatus, @@ -16,7 +16,7 @@ pub struct UpdatePresence { #[derive(Debug, Deserialize, Serialize, Default, Clone)] /// Received to tell the client that a user updated their presence / status -/// See https://discord.com/developers/docs/topics/gateway-events#presence-update-presence-update-event-fields +/// See pub struct PresenceUpdate { pub user: PublicUser, #[serde(default)] diff --git a/src/types/events/ready.rs b/src/types/events/ready.rs index 9b6eab9..ea46b69 100644 --- a/src/types/events/ready.rs +++ b/src/types/events/ready.rs @@ -8,7 +8,7 @@ use crate::types::{Activity, GuildMember, PresenceUpdate, VoiceState}; #[derive(Debug, Deserialize, Serialize, Default, Clone)] /// 1/2 half documented; /// Received after identifying, provides initial user info; -/// See https://discord.com/developers/docs/topics/gateway-events#ready; +/// See pub struct GatewayReady { pub analytics_token: Option, pub auth_session_id_hash: Option, @@ -16,7 +16,7 @@ pub struct GatewayReady { pub v: u8, pub user: User, - /// For bots these are [UnavailableGuild]s, for users they are [Guild] + /// For bots these are [crate::types::UnavailableGuild]s, for users they are [Guild] pub guilds: Vec, pub presences: Option>, pub sessions: Option>, diff --git a/src/types/events/relationship.rs b/src/types/events/relationship.rs index 441c74a..a1f75a5 100644 --- a/src/types/events/relationship.rs +++ b/src/types/events/relationship.rs @@ -2,7 +2,7 @@ use crate::types::{events::WebSocketEvent, Relationship, RelationshipType, Snowf use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Default)] -/// See https://github.com/spacebarchat/server/issues/204 +/// See pub struct RelationshipAdd { #[serde(flatten)] pub relationship: Relationship, @@ -12,7 +12,7 @@ pub struct RelationshipAdd { impl WebSocketEvent for RelationshipAdd {} #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://github.com/spacebarchat/server/issues/203 +/// See pub struct RelationshipRemove { pub id: Snowflake, #[serde(rename = "type")] diff --git a/src/types/events/request_members.rs b/src/types/events/request_members.rs index 2d537b9..526313b 100644 --- a/src/types/events/request_members.rs +++ b/src/types/events/request_members.rs @@ -2,7 +2,7 @@ use crate::types::{events::WebSocketEvent, Snowflake}; use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Default)] -/// See https://discord.com/developers/docs/topics/gateway-events#request-guild-members-request-guild-members-structure +/// See pub struct GatewayRequestGuildMembers { pub guild_id: Snowflake, pub query: Option, diff --git a/src/types/events/stage_instance.rs b/src/types/events/stage_instance.rs index 0fe487b..c2bbc46 100644 --- a/src/types/events/stage_instance.rs +++ b/src/types/events/stage_instance.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::types::{StageInstance, WebSocketEvent}; #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#stage-instance-create +/// See pub struct StageInstanceCreate { #[serde(flatten)] pub stage_instance: StageInstance, @@ -12,7 +12,7 @@ pub struct StageInstanceCreate { impl WebSocketEvent for StageInstanceCreate {} #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#stage-instance-update +/// See pub struct StageInstanceUpdate { #[serde(flatten)] pub stage_instance: StageInstance, @@ -21,7 +21,7 @@ pub struct StageInstanceUpdate { impl WebSocketEvent for StageInstanceUpdate {} #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#stage-instance-delete +/// See pub struct StageInstanceDelete { #[serde(flatten)] pub stage_instance: StageInstance, diff --git a/src/types/events/thread.rs b/src/types/events/thread.rs index e8276e7..2faecf7 100644 --- a/src/types/events/thread.rs +++ b/src/types/events/thread.rs @@ -5,7 +5,7 @@ use crate::types::events::WebSocketEvent; use crate::types::Snowflake; #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#thread-create +/// See pub struct ThreadCreate { #[serde(flatten)] pub thread: Channel, @@ -14,7 +14,7 @@ pub struct ThreadCreate { impl WebSocketEvent for ThreadCreate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#thread-update +/// See pub struct ThreadUpdate { #[serde(flatten)] pub thread: Channel, @@ -23,7 +23,7 @@ pub struct ThreadUpdate { impl WebSocketEvent for ThreadUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#thread-delete +/// See pub struct ThreadDelete { #[serde(flatten)] pub thread: Channel, @@ -32,7 +32,7 @@ pub struct ThreadDelete { impl WebSocketEvent for ThreadDelete {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#thread-list-sync +/// See pub struct ThreadListSync { pub guild_id: Snowflake, pub channel_ids: Option>, @@ -43,7 +43,7 @@ pub struct ThreadListSync { impl WebSocketEvent for ThreadListSync {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#thread-member-update +/// See /// The inner payload is a thread member object with an extra field. pub struct ThreadMemberUpdate { #[serde(flatten)] @@ -54,7 +54,7 @@ pub struct ThreadMemberUpdate { impl WebSocketEvent for ThreadMemberUpdate {} #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#thread-members-update +/// See pub struct ThreadMembersUpdate { pub id: Snowflake, pub guild_id: Snowflake, diff --git a/src/types/events/user.rs b/src/types/events/user.rs index 18c8511..e3ce99a 100644 --- a/src/types/events/user.rs +++ b/src/types/events/user.rs @@ -5,7 +5,7 @@ use crate::types::events::WebSocketEvent; use crate::types::utils::Snowflake; #[derive(Debug, Default, Deserialize, Serialize, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#user-update; +/// See ; /// Sent to indicate updates to a user object; (name changes, discriminator changes, etc); pub struct UserUpdate { #[serde(flatten)] diff --git a/src/types/events/voice.rs b/src/types/events/voice.rs index 63e740a..ff13b73 100644 --- a/src/types/events/voice.rs +++ b/src/types/events/voice.rs @@ -16,7 +16,7 @@ pub struct UpdateVoiceState { impl WebSocketEvent for UpdateVoiceState {} #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#voice-state-update; +/// See ; /// /// Received from the server to indicate an update in a user's voice state (leave voice channel, join voice channel, mute, deafen, etc); /// @@ -29,7 +29,7 @@ pub struct VoiceStateUpdate { impl WebSocketEvent for VoiceStateUpdate {} #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#voice-server-update; +/// See ; /// /// Received to indicate which voice endpoint, token and guild_id to use; pub struct VoiceServerUpdate { diff --git a/src/types/events/webhooks.rs b/src/types/events/webhooks.rs index 3f0158e..518b332 100644 --- a/src/types/events/webhooks.rs +++ b/src/types/events/webhooks.rs @@ -5,7 +5,7 @@ use crate::types::Snowflake; use super::WebSocketEvent; #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#webhooks-update +/// See pub struct WebhooksUpdate { pub guild_id: Snowflake, pub channel_id: Snowflake, diff --git a/src/types/interfaces/status.rs b/src/types/interfaces/status.rs index c82e665..fadaf68 100644 --- a/src/types/interfaces/status.rs +++ b/src/types/interfaces/status.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#client-status-object +/// See pub struct ClientStatusObject { pub desktop: Option, pub mobile: Option, diff --git a/src/types/schema/user.rs b/src/types/schema/user.rs index c8cf5bb..9946e73 100644 --- a/src/types/schema/user.rs +++ b/src/types/schema/user.rs @@ -6,6 +6,7 @@ use crate::types::Snowflake; #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] +/// A schema used to modify a user. pub struct UserModifySchema { pub username: Option, pub avatar: Option, @@ -19,6 +20,8 @@ pub struct UserModifySchema { pub discriminator: Option, } +/// A schema used to create a private channel. +/// /// # Attributes: /// - recipients: The users to include in the private channel /// - access_tokens: The access tokens of users that have granted your app the `gdm.join` scope. Only usable for OAuth2 requests (which can only create group DMs). diff --git a/src/types/utils/jwt.rs b/src/types/utils/jwt.rs index c9f1aa5..ca0aebb 100644 --- a/src/types/utils/jwt.rs +++ b/src/types/utils/jwt.rs @@ -1,8 +1,7 @@ +use crate::types::utils::Snowflake; use jsonwebtoken::{encode, EncodingKey, Header}; use serde::{Deserialize, Serialize}; -use crate::types::utils::Snowflake; - pub fn generate_token(id: &Snowflake, email: String, jwt_key: &str) -> String { let claims = Claims::new(&email, id); @@ -11,7 +10,9 @@ pub fn generate_token(id: &Snowflake, email: String, jwt_key: &str) -> String { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Claims { + /// When the token expires, unix epoch pub exp: i64, + /// When the token was issued pub iat: i64, pub email: String, pub id: String, diff --git a/src/types/utils/rights.rs b/src/types/utils/rights.rs index fecf268..5a3c373 100644 --- a/src/types/utils/rights.rs +++ b/src/types/utils/rights.rs @@ -1,56 +1,124 @@ use bitflags::bitflags; bitflags! { + /// Rights are instance-wide, per-user permissions for everything you may perform on the instance, + /// such as sending messages, editing messages, or shutting down the server. + /// They are separate from guild member permissions, which only apply to a given guild. + /// + /// # Notes + /// The default rights on Discord.com are 648540060672 ([source](https://github.com/spacebarchat/server/issues/878#issuecomment-1234669715)) + /// + /// # Reference + /// See pub struct Rights: u64 { + /// All rights const OPERATOR = 1 << 0; + /// Ability to alter or remove others' applications const MANAGE_APPLICATIONS = 1 << 1; + /// Same as the per-guild [MANAGE_GUILD] permission, but applies to all guilds and DM channels, can join any guild without invite const MANAGE_GUILDS = 1 << 2; + /// Can delete or edit any message they can read const MANAGE_MESSAGES = 1 << 3; + /// Can add, change, define rate limits of other users, + /// can also grant others [BYPASS_RATE_LIMITS] when combined + /// with [BYPASS_RATE_LIMITS] and [MANAGE_USERS]. const MANAGE_RATE_LIMITS = 1 << 4; + /// Can create, alter, enable and disable custom message routing rules in any channel/guild const MANAGE_ROUTING = 1 << 5; + /// Respond to or resolve other users' support tickets const MANAGE_TICKETS = 1 << 6; + /// Can create, alter, remove and ban users; can also create, modify and remove user groups const MANAGE_USERS = 1 << 7; + /// Can manually add members into their guilds and group DMs const ADD_MEMBERS = 1 << 8; + /// Makes the user exempt from all rate limits const BYPASS_RATE_LIMITS = 1 << 9; + /// Can create, edit and remove own applications const CREATE_APPLICATIONS = 1 << 10; + /// Can create guild channels and custom channels const CREATE_CHANNELS = 1 << 11; + /// Can create 1:1 DMs + /// + /// # Notes + /// A user without [SEND_MESSAGES] cannot be added to a DM const CREATE_DMS = 1 << 12; + /// Can create group DMs + /// + /// # Notes + /// A user without [SEND_MESSAGES] cannot be added to a DM const CREATE_DM_GROUPS = 1 << 13; + /// Can create guilds const CREATE_GUILDS = 1 << 14; + /// Can create mass invites in guilds where they have [CREATE_INSTANT_INVITE] const CREATE_INVITES = 1 << 15; + /// Can create roles and per-guild or per-channel permission + /// overrides in the guilds that they have permissions const CREATE_ROLES = 1 << 16; + /// Can create templates for guilds, custom channels and channels with custom routing const CREATE_TEMPLATES = 1 << 17; + /// Can create webhooks in the guilds that they have permissions const CREATE_WEBHOOKS = 1 << 18; + /// Can join guilds by using invites or vanity names const JOIN_GUILDS = 1 << 19; + /// Can modify the pinned messages in the guilds that they have permission const PIN_MESSAGES = 1 << 20; + /// Can react to messages, subject to permissions const SELF_ADD_REACTIONS = 1 << 21; + /// Can delete own messages const SELF_DELETE_MESSAGES = 1 << 22; + /// Can edit own messages const SELF_EDIT_MESSAGES = 1 << 23; + /// Can edit own username, nickname and avatar const SELF_EDIT_NAME = 1 << 24; + /// Can send messages in the channels that they have permissions const SEND_MESSAGES = 1 << 25; + /// Can use voice activities, such as watch together or whiteboard const USE_ACTIVITIES = 1 << 26; + /// Can use video and screenshare in guilds/channels that they have permissions const USE_VIDEO = 1 << 27; + /// Can use voice in guilds/channels that they have permissions const USE_VOICE = 1 << 28; + /// Can create user-specific invites in guilds that they have the [`INVITE_USERS`] right in. const INVITE_USERS = 1 << 29; + /// Can delete/disable own account const SELF_DELETE_DISABLE = 1 << 30; + /// Can use pay-to-use features once paid const DEBTABLE = 1 << 31; + /// Can earn money using monetization features in guilds that have [`MonetizationEnabled`](crate::types::types::guild_configuration::GuildFeatures::MonetizationEnabled) const CREDITABLE = 1 << 32; + /// Can kick or ban guild or group DM members in the guilds/groups where they have [`KICK_MEMBERS`](crate::types::PermissionFlags::KICK_MEMBERS) or [`BAN_MEMBERS`](crate::types::PermissionFlags::BAN_MEMBERS) const KICK_BAN_MEMBERS = 1 << 33; + /// Can leave the guilds or group DMs that they joined on their own (one can always leave a guild or group DMs where they have been force-added) const SELF_LEAVE_GROUPS = 1 << 34; + /// Inverts the presence confidentiality default ([`OPERATOR`]'s presence is not routed by default, others' are) for a given user const PRESENCE = 1 << 35; + /// Can mark discoverable guilds where they have permissions to mark as discoverable const SELF_ADD_DISCOVERABLE = 1 << 36; + /// Can change anything in the primary guild directory const MANAGE_GUILD_DIRECTORY = 1 << 37; + /// Can send confetti, screenshake and use the random user mention (@someone) const POGGERS = 1 << 38; + /// Can use achievements and cheers const USE_ACHIEVEMENTS = 1 << 39; + /// Can initiate interactions const INITIATE_INTERACTIONS = 1 << 40; + /// Can respond to interactions const RESPOND_TO_INTERACTIONS = 1 << 41; + /// Can send backdated events const SEND_BACKDATED_EVENTS = 1 << 42; + /// Can accept mass (guild) invites const USE_MASS_INVITES = 1 << 43; + /// Can accept user-specific invites and DM requests const ACCEPT_INVITES = 1 << 44; + /// Can modify own flags const SELF_EDIT_FLAGS = 1 << 45; + /// Can modify other's flags const EDIT_FLAGS = 1 << 46; + /// Can manage other's groups const MANAGE_GROUPS = 1 << 47; + /// Can view server stats at /api/policies/stats const VIEW_SERVER_STATS = 1 << 48; + /// Can resend verification emails using /auth/verify/resend const RESEND_VERIFICATION_EMAIL = 1 << 49; } } @@ -60,10 +128,16 @@ impl Rights { (check_operator && self.contains(Rights::OPERATOR)) || self.contains(permission) } + /// Returns whether or not the Rights object has specific rights pub fn has(&self, permission: Rights, check_operator: bool) -> bool { (check_operator && self.contains(Rights::OPERATOR)) || self.contains(permission) } + /// Returns whether or not the Rights object has specific rights. + /// + /// # Notes + /// Unlike has, this returns an Error if we are missing rights + /// and Ok(true) otherwise pub fn has_throw(&self, permission: Rights) -> Result { if self.has(permission, true) { Ok(true) diff --git a/src/types/utils/snowflake.rs b/src/types/utils/snowflake.rs index 77514a1..b4e1d9e 100644 --- a/src/types/utils/snowflake.rs +++ b/src/types/utils/snowflake.rs @@ -11,13 +11,16 @@ use sqlx::Type; const EPOCH: i64 = 1420070400000; /// Unique identifier including a timestamp. -/// See https://discord.com/developers/docs/reference#snowflakes +/// +/// # Reference +/// See #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[cfg_attr(feature = "sqlx", derive(Type))] #[cfg_attr(feature = "sqlx", sqlx(transparent))] -pub struct Snowflake(u64); +pub struct Snowflake(pub u64); impl Snowflake { + /// Generates a snowflake for the current timestamp, with worker id 0 and process id 1. pub fn generate() -> Self { const WORKER_ID: u64 = 0; const PROCESS_ID: u64 = 1; @@ -31,6 +34,7 @@ impl Snowflake { Self(time as u64 | worker | process | increment) } + /// Returns the snowflake's timestamp pub fn timestamp(self) -> DateTime { Utc.timestamp_millis_opt((self.0 >> 22) as i64 + EPOCH) .unwrap() @@ -49,6 +53,15 @@ impl Display for Snowflake { } } +impl From for Snowflake +where + T: Into, +{ + fn from(item: T) -> Self { + Self(item.into()) + } +} + impl serde::Serialize for Snowflake { fn serialize(&self, serializer: S) -> Result where diff --git a/src/voice.rs b/src/voice.rs index 8b13789..c2fcaf2 100644 --- a/src/voice.rs +++ b/src/voice.rs @@ -1 +1,2 @@ - +//! Where the voice chat implementation will be, once it's finished. +//! For development on voice, see the feature/voice branch. diff --git a/tests/channels.rs b/tests/channels.rs index c8564d7..d810c10 100644 --- a/tests/channels.rs +++ b/tests/channels.rs @@ -59,8 +59,9 @@ async fn modify_channel() { PermissionFlags::MANAGE_CHANNELS, PermissionFlags::MANAGE_MESSAGES, ])); + let user_id: types::Snowflake = bundle.user.object.lock().unwrap().id; let permission_override = PermissionOverwrite { - id: bundle.user.object.id, + id: user_id, overwrite_type: "1".to_string(), allow: permission_override, deny: "0".to_string(), @@ -143,7 +144,7 @@ async fn create_dm() { let other_user = bundle.create_user("integrationtestuser2").await; let user = &mut bundle.user; let private_channel_create_schema = PrivateChannelCreateSchema { - recipients: Some(Vec::from([other_user.object.id])), + recipients: Some(Vec::from([other_user.object.lock().unwrap().id])), access_tokens: None, nicks: None, }; @@ -153,26 +154,47 @@ async fn create_dm() { .unwrap(); assert!(dm_channel.recipients.is_some()); assert_eq!( - dm_channel.recipients.as_ref().unwrap().get(0).unwrap().id, - other_user.object.id + dm_channel + .recipients + .as_ref() + .unwrap() + .get(0) + .unwrap() + .lock() + .unwrap() + .id + .clone(), + other_user.object.lock().unwrap().id ); assert_eq!( - dm_channel.recipients.as_ref().unwrap().get(1).unwrap().id, - user.object.id + dm_channel + .recipients + .as_ref() + .unwrap() + .get(1) + .unwrap() + .lock() + .unwrap() + .id + .clone(), + user.object.lock().unwrap().id.clone() ); common::teardown(bundle).await; } // #[tokio::test] -// This test currently is broken due to an issue with the Spacebar Server. +// TODO This test currently is broken due to an issue with the Spacebar Server. #[allow(dead_code)] async fn remove_add_person_from_to_dm() { let mut bundle = common::setup().await; let mut other_user = bundle.create_user("integrationtestuser2").await; let mut third_user = bundle.create_user("integrationtestuser3").await; + let third_user_id = third_user.object.lock().unwrap().id; + let other_user_id = other_user.object.lock().unwrap().id; + let user_id = bundle.user.object.lock().unwrap().id; let user = &mut bundle.user; let private_channel_create_schema = PrivateChannelCreateSchema { - recipients: Some(Vec::from([other_user.object.id, third_user.object.id])), + recipients: Some(Vec::from([other_user_id, third_user_id])), access_tokens: None, nicks: None, }; @@ -181,36 +203,52 @@ async fn remove_add_person_from_to_dm() { .await .unwrap(); // Creates the Channel and stores the response Channel object dm_channel - .remove_channel_recipient(other_user.object.id, user) + .remove_channel_recipient(other_user_id, user) .await .unwrap(); assert!(dm_channel.recipients.as_ref().unwrap().get(1).is_none()); other_user - .modify_user_relationship(user.object.id, RelationshipType::Friends) + .modify_user_relationship(user_id, RelationshipType::Friends) .await .unwrap(); - user.modify_user_relationship(other_user.object.id, RelationshipType::Friends) + user.modify_user_relationship(other_user_id, RelationshipType::Friends) .await .unwrap(); third_user - .modify_user_relationship(user.object.id, RelationshipType::Friends) + .modify_user_relationship(user_id, RelationshipType::Friends) .await .unwrap(); - user.modify_user_relationship(third_user.object.id, RelationshipType::Friends) + user.modify_user_relationship(third_user_id, RelationshipType::Friends) .await .unwrap(); // Users 1-2 and 1-3 are now friends dm_channel - .add_channel_recipient(other_user.object.id, user, None) + .add_channel_recipient(other_user_id, user, None) .await .unwrap(); assert!(dm_channel.recipients.is_some()); assert_eq!( - dm_channel.recipients.as_ref().unwrap().get(0).unwrap().id, - other_user.object.id + dm_channel + .recipients + .as_ref() + .unwrap() + .get(0) + .unwrap() + .lock() + .unwrap() + .id, + other_user_id ); assert_eq!( - dm_channel.recipients.as_ref().unwrap().get(1).unwrap().id, - user.object.id + dm_channel + .recipients + .as_ref() + .unwrap() + .get(1) + .unwrap() + .lock() + .unwrap() + .id, + user_id ); } diff --git a/tests/invites.rs b/tests/invites.rs index d19be61..e25fea5 100644 --- a/tests/invites.rs +++ b/tests/invites.rs @@ -11,7 +11,7 @@ async fn create_accept_invite() { .await .is_err()); let invite = user - .create_guild_invite(create_channel_invite_schema, channel.id) + .create_channel_invite(create_channel_invite_schema, channel.id) .await .unwrap(); diff --git a/tests/members.rs b/tests/members.rs index 9710d7f..a314be7 100644 --- a/tests/members.rs +++ b/tests/members.rs @@ -7,7 +7,7 @@ async fn add_remove_role() -> ChorusResult<()> { let mut bundle = common::setup().await; let guild = bundle.guild.id; let role = bundle.role.id; - let member_id = bundle.user.object.id; + let member_id = bundle.user.object.lock().unwrap().id; GuildMember::add_role(&mut bundle.user, guild, member_id, role).await?; let member = GuildMember::get(&mut bundle.user, guild, member_id) .await diff --git a/tests/relationships.rs b/tests/relationships.rs index 00ef9cf..2773474 100644 --- a/tests/relationships.rs +++ b/tests/relationships.rs @@ -7,15 +7,18 @@ async fn test_get_mutual_relationships() { let mut bundle = common::setup().await; let mut other_user = bundle.create_user("integrationtestuser2").await; let user = &mut bundle.user; + let username = user.object.lock().unwrap().username.clone(); + let discriminator = user.object.lock().unwrap().discriminator.clone(); + let other_user_id: types::Snowflake = other_user.object.lock().unwrap().id; let friend_request_schema = types::FriendRequestSendSchema { - username: user.object.username.clone(), - discriminator: Some(user.object.discriminator.clone()), + username, + discriminator: Some(discriminator), }; - let _ = other_user.send_friend_request(friend_request_schema).await; - let relationships = user - .get_mutual_relationships(other_user.object.id) + other_user + .send_friend_request(friend_request_schema) .await .unwrap(); + let relationships = user.get_mutual_relationships(other_user_id).await.unwrap(); println!("{:?}", relationships); common::teardown(bundle).await } @@ -25,16 +28,21 @@ async fn test_get_relationships() { let mut bundle = common::setup().await; let mut other_user = bundle.create_user("integrationtestuser2").await; let user = &mut bundle.user; + let username = user.object.lock().unwrap().username.clone(); + let discriminator = user.object.lock().unwrap().discriminator.clone(); let friend_request_schema = types::FriendRequestSendSchema { - username: user.object.username.clone(), - discriminator: Some(user.object.discriminator.clone()), + username, + discriminator: Some(discriminator), }; other_user .send_friend_request(friend_request_schema) .await .unwrap(); let relationships = user.get_relationships().await.unwrap(); - assert_eq!(relationships.get(0).unwrap().id, other_user.object.id); + assert_eq!( + relationships.get(0).unwrap().id, + other_user.object.lock().unwrap().id + ); common::teardown(bundle).await } @@ -43,23 +51,33 @@ async fn test_modify_relationship_friends() { let mut bundle = common::setup().await; let mut other_user = bundle.create_user("integrationtestuser2").await; let user = &mut bundle.user; - let _ = other_user - .modify_user_relationship(user.object.id, types::RelationshipType::Friends) - .await; + let user_id: types::Snowflake = user.object.lock().unwrap().id; + let other_user_id: types::Snowflake = other_user.object.lock().unwrap().id; + + other_user + .modify_user_relationship(user_id, types::RelationshipType::Friends) + .await + .unwrap(); let relationships = user.get_relationships().await.unwrap(); - assert_eq!(relationships.get(0).unwrap().id, other_user.object.id); + assert_eq!( + relationships.get(0).unwrap().id, + other_user.object.lock().unwrap().id + ); assert_eq!( relationships.get(0).unwrap().relationship_type, RelationshipType::Incoming ); let relationships = other_user.get_relationships().await.unwrap(); - assert_eq!(relationships.get(0).unwrap().id, user.object.id); + assert_eq!( + relationships.get(0).unwrap().id, + user.object.lock().unwrap().id + ); assert_eq!( relationships.get(0).unwrap().relationship_type, RelationshipType::Outgoing ); let _ = user - .modify_user_relationship(other_user.object.id, RelationshipType::Friends) + .modify_user_relationship(other_user_id, RelationshipType::Friends) .await; assert_eq!( other_user @@ -71,7 +89,7 @@ async fn test_modify_relationship_friends() { .relationship_type, RelationshipType::Friends ); - let _ = user.remove_relationship(other_user.object.id).await; + let _ = user.remove_relationship(other_user_id).await; assert_eq!( other_user.get_relationships().await.unwrap(), Vec::::new() @@ -84,18 +102,24 @@ async fn test_modify_relationship_block() { let mut bundle = common::setup().await; let mut other_user = bundle.create_user("integrationtestuser2").await; let user = &mut bundle.user; - let _ = other_user - .modify_user_relationship(user.object.id, types::RelationshipType::Blocked) - .await; + let user_id: types::Snowflake = user.object.lock().unwrap().id; + + other_user + .modify_user_relationship(user_id, types::RelationshipType::Blocked) + .await + .unwrap(); let relationships = user.get_relationships().await.unwrap(); assert_eq!(relationships, Vec::::new()); let relationships = other_user.get_relationships().await.unwrap(); - assert_eq!(relationships.get(0).unwrap().id, user.object.id); + assert_eq!( + relationships.get(0).unwrap().id, + user.object.lock().unwrap().id + ); assert_eq!( relationships.get(0).unwrap().relationship_type, RelationshipType::Blocked ); - let _ = other_user.remove_relationship(user.object.id).await; + other_user.remove_relationship(user_id).await.unwrap(); assert_eq!( other_user.get_relationships().await.unwrap(), Vec::::new() diff --git a/tests/roles.rs b/tests/roles.rs index 1675367..f45fb62 100644 --- a/tests/roles.rs +++ b/tests/roles.rs @@ -24,7 +24,6 @@ async fn create_and_get_roles() { let expected = types::RoleObject::get_all(&mut bundle.user, guild) .await - .unwrap() .unwrap()[2] .clone();