Merge branch 'main' into enhancement/improved-auto-updating-structs

This commit is contained in:
fowb 2023-08-12 19:04:25 +02:00
commit 7071de8412
74 changed files with 1047 additions and 715 deletions

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables
/target/ /**/target/
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk

View File

@ -11,7 +11,7 @@ client = []
[dependencies] [dependencies]
tokio = { version = "1.29.1", features = ["macros"] } tokio = { version = "1.29.1", features = ["macros"] }
serde = {version = "1.0.171", features = ["derive"]} serde = { version = "1.0.171", features = ["derive", "rc"] }
serde_json = { version = "1.0.103", features = ["raw_value"] } serde_json = { version = "1.0.103", features = ["raw_value"] }
serde-aux = "4.2.0" serde-aux = "4.2.0"
serde_with = "3.0.0" serde_with = "3.0.0"
@ -31,7 +31,15 @@ hostname = "0.3.1"
bitflags = { version = "2.3.3", features = ["serde"] } bitflags = { version = "2.3.3", features = ["serde"] }
lazy_static = "1.4.0" lazy_static = "1.4.0"
poem = { version = "1.3.56", optional = true } 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" thiserror = "1.0.43"
jsonwebtoken = "8.3.0" jsonwebtoken = "8.3.0"
log = "0.4.19" log = "0.4.19"

View File

@ -1,5 +1,6 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex};
use reqwest::Client; use reqwest::Client;
use serde_json::to_string; use serde_json::to_string;
@ -12,6 +13,10 @@ use crate::ratelimiter::ChorusRequest;
use crate::types::{GatewayIdentifyPayload, LoginResult, LoginSchema}; use crate::types::{GatewayIdentifyPayload, LoginResult, LoginSchema};
impl Instance { impl Instance {
/// Logs into an existing account on the spacebar server.
///
/// # Reference
/// See <https://docs.spacebar.chat/routes/#post-/auth/login/>
pub async fn login_account(&mut self, login_schema: &LoginSchema) -> ChorusResult<UserMeta> { pub async fn login_account(&mut self, login_schema: &LoginSchema) -> ChorusResult<UserMeta> {
let endpoint_url = self.urls.api.clone() + "/auth/login"; let endpoint_url = self.urls.api.clone() + "/auth/login";
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
@ -41,7 +46,7 @@ impl Instance {
login_result.token, login_result.token,
self.clone_limits_if_some(), self.clone_limits_if_some(),
login_result.settings, login_result.settings,
object, Arc::new(Mutex::new(object)),
gateway, gateway,
); );
Ok(user) Ok(user)

View File

@ -1,3 +1,4 @@
use std::sync::{Arc, Mutex};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use reqwest::Client; use reqwest::Client;
@ -14,15 +15,10 @@ use crate::{
}; };
impl Instance { impl Instance {
/// Registers a new user on the Spacebar server. /// Registers a new user on the server.
/// ///
/// # Arguments /// # Reference
/// /// See <https://docs.spacebar.chat/routes/#post-/auth/register/>
/// * `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.
pub async fn register_account( pub async fn register_account(
&mut self, &mut self,
register_schema: &RegisterSchema, register_schema: &RegisterSchema,
@ -56,8 +52,8 @@ impl Instance {
Rc::new(RefCell::new(self.clone())), Rc::new(RefCell::new(self.clone())),
token.clone(), token.clone(),
self.clone_limits_if_some(), self.clone_limits_if_some(),
settings, Arc::new(Mutex::new(settings)),
user_object, Arc::new(Mutex::new(user_object)),
gateway, gateway,
); );
Ok(user) Ok(user)

View File

@ -11,35 +11,33 @@ use crate::{
}; };
impl Channel { impl Channel {
/// Retrieves a channel from the server.
///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/channel#get-channel>
pub async fn get(user: &mut UserMeta, channel_id: Snowflake) -> ChorusResult<Channel> { pub async fn get(user: &mut UserMeta, channel_id: Snowflake) -> ChorusResult<Channel> {
let url = user.belongs_to.borrow().urls.api.clone(); let url = user.belongs_to.borrow().urls.api.clone();
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.get(format!("{}/channels/{}/", url, channel_id)) .get(format!("{}/channels/{}", url, channel_id))
.bearer_auth(user.token()), .bearer_auth(user.token()),
limit_type: LimitType::Channel(channel_id), limit_type: LimitType::Channel(channel_id),
}; };
chorus_request.deserialize_response::<Channel>(user).await chorus_request.deserialize_response::<Channel>(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. /// # Reference
/// * `url_api` - A string slice that holds the URL of the API. /// See <https://discord-userdoccers.vercel.app/resources/channel#delete-channel>
/// * `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.
pub async fn delete(self, user: &mut UserMeta) -> ChorusResult<()> { pub async fn delete(self, user: &mut UserMeta) -> ChorusResult<()> {
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.delete(format!( .delete(format!(
"{}/channels/{}/", "{}/channels/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
self.id self.id
)) ))
@ -49,20 +47,20 @@ impl Channel {
chorus_request.handle_request_as_result(user).await 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. /// If modifying permission overwrites, the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission is required.
/// * `token` - A string slice that holds the authorization token. /// Only permissions you have in the guild or parent channel (if applicable) can be allowed/denied
/// * `url_api` - A string slice that holds the URL of the API. /// (unless you have a [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) overwrite in the channel).
/// * `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.
/// ///
/// # 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 <https://discord-userdoccers.vercel.app/resources/channel#modify-channel>
pub async fn modify( pub async fn modify(
&self, &self,
modify_data: ChannelModifySchema, modify_data: ChannelModifySchema,
@ -72,7 +70,7 @@ impl Channel {
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.patch(format!( .patch(format!(
"{}/channels/{}/", "{}/channels/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
channel_id channel_id
)) ))
@ -83,6 +81,15 @@ impl Channel {
chorus_request.deserialize_response::<Channel>(user).await chorus_request.deserialize_response::<Channel>(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 <https://discord-userdoccers.vercel.app/resources/message#get-messages>
pub async fn messages( pub async fn messages(
range: GetChannelMessagesSchema, range: GetChannelMessagesSchema,
channel_id: Snowflake, channel_id: Snowflake,
@ -105,8 +112,10 @@ impl Channel {
.await .await
} }
/// Adds a recipient to a group DM.
///
/// # Reference: /// # Reference:
/// Read: <https://discord-userdoccers.vercel.app/resources/channel#add-channel-recipient> /// See <https://discord-userdoccers.vercel.app/resources/channel#add-channel-recipient>
pub async fn add_channel_recipient( pub async fn add_channel_recipient(
&self, &self,
recipient_id: Snowflake, recipient_id: Snowflake,
@ -115,7 +124,7 @@ impl Channel {
) -> ChorusResult<()> { ) -> ChorusResult<()> {
let mut request = Client::new() let mut request = Client::new()
.put(format!( .put(format!(
"{}/channels/{}/recipients/{}/", "{}/channels/{}/recipients/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
self.id, self.id,
recipient_id recipient_id
@ -132,8 +141,10 @@ impl Channel {
.await .await
} }
/// Removes a recipient from a group DM.
///
/// # Reference: /// # Reference:
/// Read: <https://discord-userdoccers.vercel.app/resources/channel#remove-channel-recipient> /// See <https://discord-userdoccers.vercel.app/resources/channel#remove-channel-recipient>
pub async fn remove_channel_recipient( pub async fn remove_channel_recipient(
&self, &self,
recipient_id: Snowflake, recipient_id: Snowflake,
@ -141,7 +152,7 @@ impl Channel {
) -> ChorusResult<()> { ) -> ChorusResult<()> {
let request = Client::new() let request = Client::new()
.delete(format!( .delete(format!(
"{}/channels/{}/recipients/{}/", "{}/channels/{}/recipients/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
self.id, self.id,
recipient_id recipient_id

View File

@ -4,22 +4,28 @@ use reqwest::{multipart, Client};
use serde_json::to_string; use serde_json::to_string;
use crate::api::LimitType; use crate::api::LimitType;
use crate::errors::ChorusResult;
use crate::instance::UserMeta; use crate::instance::UserMeta;
use crate::ratelimiter::ChorusRequest; use crate::ratelimiter::ChorusRequest;
use crate::types::{Message, MessageSendSchema, Snowflake}; use crate::types::{Message, MessageSendSchema, Snowflake};
impl Message { impl Message {
/// Sends a message in the channel with the provided channel_id.
/// Returns the sent message.
///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/message#create-message>
pub async fn send( pub async fn send(
user: &mut UserMeta, user: &mut UserMeta,
channel_id: Snowflake, channel_id: Snowflake,
mut message: MessageSendSchema, mut message: MessageSendSchema,
) -> Result<Message, crate::errors::ChorusError> { ) -> ChorusResult<Message> {
let url_api = user.belongs_to.borrow().urls.api.clone(); let url_api = user.belongs_to.borrow().urls.api.clone();
if message.attachments.is_none() { if message.attachments.is_none() {
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.post(format!("{}/channels/{}/messages/", url_api, channel_id)) .post(format!("{}/channels/{}/messages", url_api, channel_id))
.bearer_auth(user.token()) .bearer_auth(user.token())
.body(to_string(&message).unwrap()), .body(to_string(&message).unwrap()),
limit_type: LimitType::Channel(channel_id), limit_type: LimitType::Channel(channel_id),
@ -55,7 +61,7 @@ impl Message {
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.post(format!("{}/channels/{}/messages/", url_api, channel_id)) .post(format!("{}/channels/{}/messages", url_api, channel_id))
.bearer_auth(user.token()) .bearer_auth(user.token())
.multipart(form), .multipart(form),
limit_type: LimitType::Channel(channel_id), limit_type: LimitType::Channel(channel_id),
@ -66,11 +72,19 @@ impl Message {
} }
impl UserMeta { 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 <https://discord-userdoccers.vercel.app/resources/message#create-message>
pub async fn send_message( pub async fn send_message(
&mut self, &mut self,
message: MessageSendSchema, message: MessageSendSchema,
channel_id: Snowflake, channel_id: Snowflake,
) -> Result<Message, crate::errors::ChorusError> { ) -> ChorusResult<Message> {
Message::send(self, channel_id, message).await Message::send(self, channel_id, message).await
} }
} }

View File

@ -10,17 +10,16 @@ use crate::{
}; };
impl types::Channel { 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. /// Requires the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission.
/// * `channel_id` - A string slice representing the ID of the channel. /// Only permissions you have in the guild or parent channel (if applicable) can be allowed/denied
/// * `overwrite` - A [`PermissionOverwrite`] instance representing the new permission overwrites. /// (unless you have a [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) overwrite in the channel).
/// ///
/// # Returns /// # Reference
/// /// See <https://discord-userdoccers.vercel.app/resources/channel#modify-channel-permissions>
/// This function returns a result that is either [`Ok(())`] if the request is successful, or an [`Err(ChorusLibError)`].
pub async fn edit_permissions( pub async fn edit_permissions(
user: &mut UserMeta, user: &mut UserMeta,
channel_id: Snowflake, channel_id: Snowflake,
@ -47,17 +46,14 @@ impl types::Channel {
chorus_request.handle_request_as_result(user).await 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. /// Requires the [`MANAGE_ROLES`](crate::types::PermissionFlags::MANAGE_ROLES) permission.
/// * `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.
/// ///
/// # Returns /// # Reference
/// /// See <https://discord-userdoccers.vercel.app/resources/channel#delete-channel-permission>
/// This function returns a Result that is either [`Ok(())`] if the request is successfulm or an [`Err(ChorusLibError)`].
pub async fn delete_permission( pub async fn delete_permission(
user: &mut UserMeta, user: &mut UserMeta,
channel_id: Snowflake, channel_id: Snowflake,

View File

@ -8,9 +8,7 @@ use crate::{
types::{self, PublicUser, Snowflake}, 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 struct ReactionMeta {
pub message_id: types::Snowflake, pub message_id: types::Snowflake,
pub channel_id: types::Snowflake, pub channel_id: types::Snowflake,
@ -18,17 +16,14 @@ pub struct ReactionMeta {
impl ReactionMeta { impl ReactionMeta {
/// Deletes all reactions for a message. /// Deletes all reactions for a message.
/// This endpoint requires the `MANAGE_MESSAGES` permission to be present on the current user. ///
/// # Arguments /// This endpoint requires the [`MANAGE_MESSAGES`](crate::types::PermissionFlags::MANAGE_MESSAGES) permission.
/// * `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.
/// # Reference /// # Reference
/// See [https://discord.com/developers/docs/resources/channel#delete-all-reactions](https://discord.com/developers/docs/resources/channel#delete-all-reactions) /// See <https://discord.com/developers/docs/resources/channel#delete-all-reactions>
pub async fn delete_all(&self, user: &mut UserMeta) -> ChorusResult<()> { pub async fn delete_all(&self, user: &mut UserMeta) -> ChorusResult<()> {
let url = format!( let url = format!(
"{}/channels/{}/messages/{}/reactions/", "{}/channels/{}/messages/{}/reactions",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
self.channel_id, self.channel_id,
self.message_id self.message_id
@ -41,18 +36,15 @@ impl ReactionMeta {
} }
/// Gets a list of users that reacted with a specific emoji to a message. /// 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 emoji must be URL Encoded or the request will fail with 10014: Unknown Emoji.
/// the request will fail with 10014: Unknown Emoji. To use custom emoji, you must encode it in the /// To use custom emoji, the format of the emoji string must be name:id.
/// 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.
/// # Reference /// # Reference
/// See [https://discord.com/developers/docs/resources/channel#get-reactions](https://discord.com/developers/docs/resources/channel#get-reactions) /// See <https://discord.com/developers/docs/resources/channel#get-reactions>
pub async fn get(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<Vec<PublicUser>> { pub async fn get(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<Vec<PublicUser>> {
let url = format!( let url = format!(
"{}/channels/{}/messages/{}/reactions/{}/", "{}/channels/{}/messages/{}/reactions/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
self.channel_id, self.channel_id,
self.message_id, self.message_id,
@ -67,21 +59,18 @@ impl ReactionMeta {
.await .await
} }
/// Deletes all the reactions for a given `emoji` on a message. This endpoint requires the /// Deletes all the reactions for a given emoji on a message.
/// MANAGE_MESSAGES permission to be present on the current user. ///
/// # Arguments /// This endpoint requires the [`MANAGE_MESSAGES`](crate::types::PermissionFlags::MANAGE_MESSAGES) permission.
/// * `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 /// The emoji must be URL Encoded or the request will fail with 10014: Unknown Emoji.
/// format name:id with the emoji name and emoji id. /// To use custom emoji, the format of the emoji string must be name: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.
/// # Reference /// # 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 <https://discord.com/developers/docs/resources/channel#delete-all-reactions-for-emoji>
pub async fn delete_emoji(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<()> { pub async fn delete_emoji(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<()> {
let url = format!( let url = format!(
"{}/channels/{}/messages/{}/reactions/{}/", "{}/channels/{}/messages/{}/reactions/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
self.channel_id, self.channel_id,
self.message_id, self.message_id,
@ -94,24 +83,21 @@ impl ReactionMeta {
chorus_request.handle_request_as_result(user).await chorus_request.handle_request_as_result(user).await
} }
/// Create a reaction for the message. /// Create a reaction on a 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)
/// ///
/// 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 <https://discord.com/developers/docs/resources/channel#create-reaction>
pub async fn create(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<()> { pub async fn create(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<()> {
let url = format!( let url = format!(
"{}/channels/{}/messages/{}/reactions/{}/@me/", "{}/channels/{}/messages/{}/reactions/{}/@me",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
self.channel_id, self.channel_id,
self.message_id, self.message_id,
@ -124,20 +110,16 @@ impl ReactionMeta {
chorus_request.handle_request_as_result(user).await chorus_request.handle_request_as_result(user).await
} }
/// Delete a reaction the current user has made for the message. /// Deletes a reaction the current user has made to the message.
/// # Arguments ///
/// * `emoji` - A string slice containing the emoji to delete. The `emoji` must be URL Encoded or /// The reaction emoji must be URL Encoded or the request will fail with 10014: Unknown Emoji.
/// the request will fail with 10014: Unknown Emoji. To use custom emoji, you must encode it in the /// To use custom emoji, the format of the emoji string must be name:id.
/// 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.
/// # Reference /// # Reference
/// See [https://discord.com/developers/docs/resources/channel#delete-own-reaction](https://discord.com/developers/docs/resources/channel#delete-own-reaction) /// See <https://discord.com/developers/docs/resources/channel#delete-own-reaction>
pub async fn remove(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<()> { pub async fn remove(&self, emoji: &str, user: &mut UserMeta) -> ChorusResult<()> {
let url = format!( let url = format!(
"{}/channels/{}/messages/{}/reactions/{}/@me/", "{}/channels/{}/messages/{}/reactions/{}/@me",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
self.channel_id, self.channel_id,
self.message_id, self.message_id,
@ -150,19 +132,15 @@ impl ReactionMeta {
chorus_request.handle_request_as_result(user).await chorus_request.handle_request_as_result(user).await
} }
/// Delete a user's reaction to a message. /// Deletes a user's reaction to a message.
/// This endpoint requires the MANAGE_MESSAGES permission to be present on the current user. ///
/// # Arguments /// This endpoint requires the [`MANAGE_MESSAGES`](crate::types::PermissionFlags::MANAGE_MESSAGES) permission.
/// * `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 reaction emoji must be URL Encoded or the request will fail with 10014: Unknown Emoji.
/// the request will fail with 10014: Unknown Emoji. To use custom emoji, you must encode it in the /// To use custom emoji, the format of the emoji string must be name:id.
/// 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.
/// # Reference /// # Reference
/// See [https://discord.com/developers/docs/resources/channel#delete-own-reaction](https://discord.com/developers/docs/resources/channel#delete-own-reaction) /// See <https://discord.com/developers/docs/resources/channel#delete-user-reaction>
pub async fn delete_user( pub async fn delete_user(
&self, &self,
user_id: Snowflake, user_id: Snowflake,

View File

@ -11,27 +11,15 @@ use crate::types::Snowflake;
use crate::types::{Channel, ChannelCreateSchema, Guild, GuildCreateSchema}; use crate::types::{Channel, ChannelCreateSchema, Guild, GuildCreateSchema};
impl Guild { impl Guild {
/// Creates a new guild with the given parameters. /// Creates a new guild.
///
/// # 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<Guild>` containing the object of the newly created guild, or an error if the request fails.
///
/// # Errors
///
/// Returns an `ChorusLibError` if the request fails.
/// ///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/guild#create-guild>
pub async fn create( pub async fn create(
user: &mut UserMeta, user: &mut UserMeta,
guild_create_schema: GuildCreateSchema, guild_create_schema: GuildCreateSchema,
) -> ChorusResult<Guild> { ) -> ChorusResult<Guild> {
let url = format!("{}/guilds/", user.belongs_to.borrow().urls.api); let url = format!("{}/guilds", user.belongs_to.borrow().urls.api);
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.post(url.clone()) .post(url.clone())
@ -42,17 +30,9 @@ impl Guild {
chorus_request.deserialize_response::<Guild>(user).await chorus_request.deserialize_response::<Guild>(user).await
} }
/// Deletes a guild. /// Deletes a guild by its id.
/// ///
/// # Arguments /// User must be the owner.
///
/// * `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 `()`.
/// ///
/// # Example /// # Example
/// ///
@ -61,14 +41,17 @@ impl Guild {
/// let mut instance = Instance::new(); /// let mut instance = Instance::new();
/// let guild_id = String::from("1234567890"); /// let guild_id = String::from("1234567890");
/// ///
/// match Guild::delete(&mut user, &mut instance, guild_id) { /// match Guild::delete(&mut user, guild_id) {
/// Some(e) => println!("Error deleting guild: {:?}", e), /// Err(e) => println!("Error deleting guild: {:?}", e),
/// None => println!("Guild deleted successfully"), /// Ok(_) => println!("Guild deleted successfully"),
/// } /// }
/// ``` /// ```
///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/guild#delete-guild>
pub async fn delete(user: &mut UserMeta, guild_id: Snowflake) -> ChorusResult<()> { pub async fn delete(user: &mut UserMeta, guild_id: Snowflake) -> ChorusResult<()> {
let url = format!( let url = format!(
"{}/guilds/{}/delete/", "{}/guilds/{}/delete",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id guild_id
); );
@ -81,19 +64,15 @@ impl Guild {
chorus_request.handle_request_as_result(user).await 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. /// # Notes
/// * `token` - A Discord bot token. /// This method is a wrapper for [Channel::create].
/// * `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 /// # Reference
/// /// See <https://discord-userdoccers.vercel.app/resources/channel#create-guild-channel>
/// A `Result` containing a `reqwest::Response` if the request was successful, or an `ChorusLibError` if there was an error.
pub async fn create_channel( pub async fn create_channel(
&self, &self,
user: &mut UserMeta, user: &mut UserMeta,
@ -102,20 +81,17 @@ impl Guild {
Channel::create(user, self.id, schema).await 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 /// Doesn't include threads.
///
/// * `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.
/// ///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/channel#get-guild-channels>
pub async fn channels(&self, user: &mut UserMeta) -> ChorusResult<Vec<Channel>> { pub async fn channels(&self, user: &mut UserMeta) -> ChorusResult<Vec<Channel>> {
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.get(format!( .get(format!(
"{}/guilds/{}/channels/", "{}/guilds/{}/channels",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
self.id 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. /// Fetches a guild by its id.
///
/// # 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.
/// ///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/guild#get-guild>
pub async fn get(guild_id: Snowflake, user: &mut UserMeta) -> ChorusResult<Guild> { pub async fn get(guild_id: Snowflake, user: &mut UserMeta) -> ChorusResult<Guild> {
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.get(format!( .get(format!(
"{}/guilds/{}/", "{}/guilds/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id guild_id
)) ))
@ -168,20 +138,12 @@ impl Guild {
} }
impl Channel { 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. /// # Reference
/// * `url_api` - The base URL for the Discord API. /// See <https://discord-userdoccers.vercel.app/resources/channel#create-guild-channel>
/// * `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.
pub async fn create( pub async fn create(
user: &mut UserMeta, user: &mut UserMeta,
guild_id: Snowflake, guild_id: Snowflake,
@ -190,7 +152,7 @@ impl Channel {
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() request: Client::new()
.post(format!( .post(format!(
"{}/guilds/{}/channels/", "{}/guilds/{}/channels",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id guild_id
)) ))

View File

@ -5,28 +5,21 @@ use crate::{
errors::ChorusResult, errors::ChorusResult,
instance::UserMeta, instance::UserMeta,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{self, Snowflake}, types::{self, GuildMember, Snowflake},
}; };
impl types::GuildMember { impl types::GuildMember {
/// Retrieves a guild member by their ID. /// Retrieves a guild member.
/// ///
/// # Arguments /// # Reference
/// /// See <https://discord-userdoccers.vercel.app/resources/guild#get-guild-member>
/// * `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.
pub async fn get( pub async fn get(
user: &mut UserMeta, user: &mut UserMeta,
guild_id: Snowflake, guild_id: Snowflake,
member_id: Snowflake, member_id: Snowflake,
) -> ChorusResult<types::GuildMember> { ) -> ChorusResult<GuildMember> {
let url = format!( let url = format!(
"{}/guilds/{}/members/{}/", "{}/guilds/{}/members/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id, guild_id,
member_id member_id
@ -36,22 +29,16 @@ impl types::GuildMember {
limit_type: LimitType::Guild(guild_id), limit_type: LimitType::Guild(guild_id),
}; };
chorus_request chorus_request
.deserialize_response::<types::GuildMember>(user) .deserialize_response::<GuildMember>(user)
.await .await
} }
/// Adds a role to a guild member. /// 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. /// # Reference
/// * `guild_id` - The ID of the guild. /// See <https://discord-userdoccers.vercel.app/resources/guild#add-guild-member-role>
/// * `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.
pub async fn add_role( pub async fn add_role(
user: &mut UserMeta, user: &mut UserMeta,
guild_id: Snowflake, guild_id: Snowflake,
@ -59,7 +46,7 @@ impl types::GuildMember {
role_id: Snowflake, role_id: Snowflake,
) -> ChorusResult<()> { ) -> ChorusResult<()> {
let url = format!( let url = format!(
"{}/guilds/{}/members/{}/roles/{}/", "{}/guilds/{}/members/{}/roles/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id, guild_id,
member_id, member_id,
@ -74,16 +61,10 @@ impl types::GuildMember {
/// Removes a role from a guild member. /// 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. /// # Reference
/// * `guild_id` - The ID of the guild. /// See <https://discord-userdoccers.vercel.app/resources/guild#remove-guild-member-role>
/// * `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.
pub async fn remove_role( pub async fn remove_role(
user: &mut UserMeta, user: &mut UserMeta,
guild_id: Snowflake, guild_id: Snowflake,
@ -91,7 +72,7 @@ impl types::GuildMember {
role_id: Snowflake, role_id: Snowflake,
) -> Result<(), crate::errors::ChorusError> { ) -> Result<(), crate::errors::ChorusError> {
let url = format!( let url = format!(
"{}/guilds/{}/members/{}/roles/{}/", "{}/guilds/{}/members/{}/roles/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id, guild_id,
member_id, member_id,

View File

@ -6,30 +6,20 @@ use crate::{
errors::{ChorusError, ChorusResult}, errors::{ChorusError, ChorusResult},
instance::UserMeta, instance::UserMeta,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{self, RoleCreateModifySchema, RoleObject, Snowflake}, types::{self, RoleCreateModifySchema, RoleObject, RolePositionUpdateSchema, Snowflake},
}; };
impl types::RoleObject { impl types::RoleObject {
/// Retrieves all roles for a given guild. /// Retrieves a list of roles for a given guild.
/// ///
/// # Arguments /// # Reference
/// /// See <https://discord-userdoccers.vercel.app/resources/guild#get-guild-roles>
/// * `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.
pub async fn get_all( pub async fn get_all(
user: &mut UserMeta, user: &mut UserMeta,
guild_id: Snowflake, guild_id: Snowflake,
) -> ChorusResult<Option<Vec<RoleObject>>> { ) -> ChorusResult<Vec<RoleObject>> {
let url = format!( let url = format!(
"{}/guilds/{}/roles/", "{}/guilds/{}/roles",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id guild_id
); );
@ -41,34 +31,20 @@ impl types::RoleObject {
.deserialize_response::<Vec<RoleObject>>(user) .deserialize_response::<Vec<RoleObject>>(user)
.await .await
.unwrap(); .unwrap();
if roles.is_empty() { Ok(roles)
return Ok(None);
}
Ok(Some(roles))
} }
/// Retrieves a single role for a given guild. /// Retrieves a single role for a given guild.
/// ///
/// # Arguments /// # Reference
/// /// See <https://docs.spacebar.chat/routes/#get-/guilds/-guild_id-/roles/-role_id-/>
/// * `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.
pub async fn get( pub async fn get(
user: &mut UserMeta, user: &mut UserMeta,
guild_id: Snowflake, guild_id: Snowflake,
role_id: Snowflake, role_id: Snowflake,
) -> ChorusResult<RoleObject> { ) -> ChorusResult<RoleObject> {
let url = format!( let url = format!(
"{}/guilds/{}/roles/{}/", "{}/guilds/{}/roles/{}",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id, guild_id,
role_id role_id
@ -84,26 +60,17 @@ impl types::RoleObject {
/// Creates a new role for a given guild. /// 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. /// # Reference
/// * `guild_id` - The ID of the guild to create the role in. /// See <https://discord-userdoccers.vercel.app/resources/guild#create-guild-role>
/// * `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.
pub async fn create( pub async fn create(
user: &mut UserMeta, user: &mut UserMeta,
guild_id: Snowflake, guild_id: Snowflake,
role_create_schema: RoleCreateModifySchema, role_create_schema: RoleCreateModifySchema,
) -> ChorusResult<RoleObject> { ) -> ChorusResult<RoleObject> {
let url = format!( let url = format!(
"{}/guilds/{}/roles/", "{}/guilds/{}/roles",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id guild_id
); );
@ -121,28 +88,19 @@ impl types::RoleObject {
.await .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. /// # Reference
/// * `guild_id` - The ID of the guild to update the role position in. /// See <https://discord-userdoccers.vercel.app/resources/guild#modify-guild-role-positions>
/// * `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.
pub async fn position_update( pub async fn position_update(
user: &mut UserMeta, user: &mut UserMeta,
guild_id: Snowflake, guild_id: Snowflake,
role_position_update_schema: types::RolePositionUpdateSchema, role_position_update_schema: RolePositionUpdateSchema,
) -> ChorusResult<RoleObject> { ) -> ChorusResult<RoleObject> {
let url = format!( let url = format!(
"{}/guilds/{}/roles/", "{}/guilds/{}/roles",
user.belongs_to.borrow().urls.api, user.belongs_to.borrow().urls.api,
guild_id guild_id
); );
@ -164,20 +122,10 @@ impl types::RoleObject {
/// Updates a role in a guild. /// 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. /// # Reference
/// * `guild_id` - The ID of the guild to update the role in. /// See <https://discord-userdoccers.vercel.app/resources/guild#modify-guild-role>
/// * `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.
pub async fn update( pub async fn update(
user: &mut UserMeta, user: &mut UserMeta,
guild_id: Snowflake, guild_id: Snowflake,

View File

@ -7,12 +7,12 @@ use crate::ratelimiter::ChorusRequest;
use crate::types::{CreateChannelInviteSchema, GuildInvite, Invite, Snowflake}; use crate::types::{CreateChannelInviteSchema, GuildInvite, Invite, Snowflake};
impl UserMeta { impl UserMeta {
/// # Arguments /// Accepts an invite to a guild, group DM, or DM.
/// - invite_code: The invite code to accept the invite for. ///
/// - session_id: The session ID that is accepting the invite, required for guest invites. /// Note that the session ID is required for guest invites.
/// ///
/// # Reference: /// # Reference:
/// Read <https://discord-userdoccers.vercel.app/resources/invite#accept-invite> /// See <https://discord-userdoccers.vercel.app/resources/invite#accept-invite>
pub async fn accept_invite( pub async fn accept_invite(
&mut self, &mut self,
invite_code: &str, invite_code: &str,
@ -21,7 +21,7 @@ impl UserMeta {
let mut request = ChorusRequest { let mut request = ChorusRequest {
request: Client::new() request: Client::new()
.post(format!( .post(format!(
"{}/invites/{}/", "{}/invites/{}",
self.belongs_to.borrow().urls.api, self.belongs_to.borrow().urls.api,
invite_code invite_code
)) ))
@ -35,12 +35,18 @@ impl UserMeta {
} }
request.deserialize_response::<Invite>(self).await request.deserialize_response::<Invite>(self).await
} }
/// Creates a new friend invite.
///
/// Note: Spacebar does not yet implement this endpoint. /// Note: Spacebar does not yet implement this endpoint.
///
/// # Reference:
/// See <https://discord-userdoccers.vercel.app/resources/invite#create-user-invite>
pub async fn create_user_invite(&mut self, code: Option<&str>) -> ChorusResult<Invite> { pub async fn create_user_invite(&mut self, code: Option<&str>) -> ChorusResult<Invite> {
ChorusRequest { ChorusRequest {
request: Client::new() request: Client::new()
.post(format!( .post(format!(
"{}/users/@me/invites/", "{}/users/@me/invites",
self.belongs_to.borrow().urls.api self.belongs_to.borrow().urls.api
)) ))
.body(to_string(&code).unwrap()) .body(to_string(&code).unwrap())
@ -51,7 +57,14 @@ impl UserMeta {
.await .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 <https://discord-userdoccers.vercel.app/resources/invite#create-channel-invite>
pub async fn create_channel_invite(
&mut self, &mut self,
create_channel_invite_schema: CreateChannelInviteSchema, create_channel_invite_schema: CreateChannelInviteSchema,
channel_id: Snowflake, channel_id: Snowflake,
@ -59,7 +72,7 @@ impl UserMeta {
ChorusRequest { ChorusRequest {
request: Client::new() request: Client::new()
.post(format!( .post(format!(
"{}/channels/{}/invites/", "{}/channels/{}/invites",
self.belongs_to.borrow().urls.api, self.belongs_to.borrow().urls.api,
channel_id channel_id
)) ))

View File

@ -6,10 +6,14 @@ use crate::types::GeneralConfiguration;
impl Instance { impl Instance {
/// Gets the instance policies schema. /// Gets the instance policies schema.
/// # Errors ///
/// [`ChorusLibError`] - If the request fails. /// # Notes
/// This is a Spacebar only endpoint.
///
/// # Reference
/// See <https://docs.spacebar.chat/routes/#get-/policies/instance/>
pub async fn general_configuration_schema(&self) -> ChorusResult<GeneralConfiguration> { pub async fn general_configuration_schema(&self) -> ChorusResult<GeneralConfiguration> {
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 { let request = match self.client.get(&endpoint_url).send().await {
Ok(result) => result, Ok(result) => result,
Err(e) => { Err(e) => {

View File

@ -24,8 +24,6 @@ pub enum LimitType {
} }
/// A struct that represents the current ratelimits, either instance-wide or user-wide. /// 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 <https://discord.com/developers/docs/topics/rate-limits#rate-limits> for more information. /// See <https://discord.com/developers/docs/topics/rate-limits#rate-limits> for more information.
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Limit { pub struct Limit {

View File

@ -12,8 +12,11 @@ use crate::{
impl UserMeta { impl UserMeta {
/// Creates a DM channel or group DM channel. /// 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: /// # Reference:
/// Read <https://discord-userdoccers.vercel.app/resources/channel#create-private-channel> /// See <https://discord-userdoccers.vercel.app/resources/channel#create-private-channel>
pub async fn create_private_channel( pub async fn create_private_channel(
&mut self, &mut self,
create_private_channel_schema: PrivateChannelCreateSchema, create_private_channel_schema: PrivateChannelCreateSchema,

View File

@ -7,16 +7,18 @@ use crate::ratelimiter::ChorusRequest;
use crate::types::Snowflake; use crate::types::Snowflake;
impl UserMeta { impl UserMeta {
/// # Arguments: /// Leaves a given guild.
/// - lurking: Whether the user is lurking in the guild
/// ///
/// # Reference: /// # Reference:
/// Read <https://discord-userdoccers.vercel.app/resources/guild#leave-guild> /// See <https://discord-userdoccers.vercel.app/resources/guild#leave-guild>
// 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<()> { pub async fn leave_guild(&mut self, guild_id: &Snowflake, lurking: bool) -> ChorusResult<()> {
ChorusRequest { ChorusRequest {
request: Client::new() request: Client::new()
.delete(format!( .delete(format!(
"{}/users/@me/guilds/{}/", "{}/users/@me/guilds/{}",
self.belongs_to.borrow().urls.api, self.belongs_to.borrow().urls.api,
guild_id guild_id
)) ))

View File

@ -6,24 +6,22 @@ use crate::{
errors::ChorusResult, errors::ChorusResult,
instance::UserMeta, instance::UserMeta,
ratelimiter::ChorusRequest, ratelimiter::ChorusRequest,
types::{self, CreateUserRelationshipSchema, RelationshipType, Snowflake}, types::{
self, CreateUserRelationshipSchema, FriendRequestSendSchema, RelationshipType, Snowflake,
},
}; };
impl UserMeta { 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 /// # Reference
/// /// See <https://luna.gitlab.io/discord-unofficial-docs/relationships.html#get-users-peer-id-relationships>
/// * `user_id` - ID of the user to retrieve the mutual relationships with.
///
/// # Returns
/// This function returns a [`ChorusResult<Vec<PublicUser>>`].
pub async fn get_mutual_relationships( pub async fn get_mutual_relationships(
&mut self, &mut self,
user_id: Snowflake, user_id: Snowflake,
) -> ChorusResult<Vec<types::PublicUser>> { ) -> ChorusResult<Vec<types::PublicUser>> {
let url = format!( let url = format!(
"{}/users/{}/relationships/", "{}/users/{}/relationships",
self.belongs_to.borrow().urls.api, self.belongs_to.borrow().urls.api,
user_id user_id
); );
@ -36,13 +34,13 @@ impl UserMeta {
.await .await
} }
/// Retrieves the authenticated user's relationships. /// Retrieves the user's relationships.
/// ///
/// # Returns /// # Reference
/// This function returns a [`ChorusResult<Vec<types::Relationship>>`]. /// See <https://luna.gitlab.io/discord-unofficial-docs/relationships.html#get-users-me-relationships>
pub async fn get_relationships(&mut self) -> ChorusResult<Vec<types::Relationship>> { pub async fn get_relationships(&mut self) -> ChorusResult<Vec<types::Relationship>> {
let url = format!( let url = format!(
"{}/users/@me/relationships/", "{}/users/@me/relationships",
self.belongs_to.borrow().urls.api self.belongs_to.borrow().urls.api
); );
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
@ -56,18 +54,14 @@ impl UserMeta {
/// Sends a friend request to a user. /// Sends a friend request to a user.
/// ///
/// # Arguments /// # Reference
/// /// See <https://luna.gitlab.io/discord-unofficial-docs/relationships.html#post-users-me-relationships>
/// * `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.
pub async fn send_friend_request( pub async fn send_friend_request(
&mut self, &mut self,
schema: types::FriendRequestSendSchema, schema: FriendRequestSendSchema,
) -> ChorusResult<()> { ) -> ChorusResult<()> {
let url = format!( let url = format!(
"{}/users/@me/relationships/", "{}/users/@me/relationships",
self.belongs_to.borrow().urls.api self.belongs_to.borrow().urls.api
); );
let body = to_string(&schema).unwrap(); let body = to_string(&schema).unwrap();
@ -78,20 +72,9 @@ impl UserMeta {
chorus_request.handle_request_as_result(self).await 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 /// Can be used to unfriend users, accept or send friend requests and block or unblock users.
///
/// * `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.
pub async fn modify_user_relationship( pub async fn modify_user_relationship(
&mut self, &mut self,
user_id: Snowflake, user_id: Snowflake,
@ -102,7 +85,7 @@ impl UserMeta {
RelationshipType::None => { RelationshipType::None => {
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() 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()), .bearer_auth(self.token()),
limit_type: LimitType::Global, limit_type: LimitType::Global,
}; };
@ -116,7 +99,7 @@ impl UserMeta {
}; };
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() 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()) .bearer_auth(self.token())
.body(to_string(&body).unwrap()), .body(to_string(&body).unwrap()),
limit_type: LimitType::Global, limit_type: LimitType::Global,
@ -131,7 +114,7 @@ impl UserMeta {
}; };
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
request: Client::new() 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()) .bearer_auth(self.token())
.body(to_string(&body).unwrap()), .body(to_string(&body).unwrap()),
limit_type: LimitType::Global, 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 /// # Reference
/// /// See <https://luna.gitlab.io/discord-unofficial-docs/relationships.html#delete-users-me-relationships-peer-id>
/// * `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.
pub async fn remove_relationship(&mut self, user_id: Snowflake) -> ChorusResult<()> { pub async fn remove_relationship(&mut self, user_id: Snowflake) -> ChorusResult<()> {
let url = format!( let url = format!(
"{}/users/@me/relationships/{}/", "{}/users/@me/relationships/{}",
self.belongs_to.borrow().urls.api, self.belongs_to.borrow().urls.api,
user_id user_id
); );

View File

@ -1,3 +1,4 @@
use std::sync::{Arc, Mutex};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
use reqwest::Client; use reqwest::Client;
@ -12,22 +13,22 @@ use crate::{
}; };
impl UserMeta { 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. /// # Reference
/// * `url_api` - The URL to the API. /// See <https://discord-userdoccers.vercel.app/resources/user#get-user> and
/// * `id` - The id of the user that will be retrieved. If this is None, the current user will be retrieved. /// <https://discord-userdoccers.vercel.app/resources/user#get-current-user>
/// * `instance_limits` - The [`Limits`] of the instance.
///
/// # Errors
///
/// * [`ChorusLibError`] - If the request fails.
pub async fn get(user: &mut UserMeta, id: Option<&String>) -> ChorusResult<User> { pub async fn get(user: &mut UserMeta, id: Option<&String>) -> ChorusResult<User> {
User::get(user, id).await 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( pub async fn get_settings(
token: &String, token: &String,
url_api: &String, url_api: &String,
@ -36,15 +37,10 @@ impl UserMeta {
User::get_settings(token, url_api, instance).await User::get_settings(token, url_api, instance).await
} }
/// Modify the current user's `UserObject`. /// Modifies the current user's representation. (See [`User`])
/// ///
/// # Arguments /// # Reference
/// /// See <https://discord-userdoccers.vercel.app/resources/user#modify-current-user>
/// * `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.
pub async fn modify(&mut self, modify_schema: UserModifySchema) -> ChorusResult<User> { pub async fn modify(&mut self, modify_schema: UserModifySchema) -> ChorusResult<User> {
if modify_schema.new_password.is_some() if modify_schema.new_password.is_some()
|| modify_schema.email.is_some() || modify_schema.email.is_some()
@ -53,7 +49,7 @@ impl UserMeta {
return Err(ChorusError::PasswordRequired); return Err(ChorusError::PasswordRequired);
} }
let request = Client::new() 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()) .body(to_string(&modify_schema).unwrap())
.bearer_auth(self.token()); .bearer_auth(self.token());
let chorus_request = ChorusRequest { let chorus_request = ChorusRequest {
@ -64,23 +60,18 @@ impl UserMeta {
.deserialize_response::<User>(self) .deserialize_response::<User>(self)
.await .await
.unwrap(); .unwrap();
let _ = std::mem::replace(&mut self.object, user_updated.clone()); self.object = Arc::new(Mutex::new(user_updated.clone()));
Ok(user_updated) Ok(user_updated)
} }
/// Sends a request to the server which deletes the user from the Instance. /// Deletes the user from the Instance.
/// ///
/// # Arguments /// # Reference
/// /// See <https://discord-userdoccers.vercel.app/resources/user#disable-user>
/// * `self` - The `User` object to delete.
///
/// # Returns
///
/// Returns `()` if the user was successfully deleted, or a `ChorusLibError` if an error occurred.
pub async fn delete(mut self) -> ChorusResult<()> { pub async fn delete(mut self) -> ChorusResult<()> {
let request = Client::new() let request = Client::new()
.post(format!( .post(format!(
"{}/users/@me/delete/", "{}/users/@me/delete",
self.belongs_to.borrow().urls.api self.belongs_to.borrow().urls.api
)) ))
.bearer_auth(self.token()); .bearer_auth(self.token());
@ -93,10 +84,15 @@ impl UserMeta {
} }
impl User { impl User {
/// Gets a user by id, or if the id is None, gets the current user.
///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/user#get-user> and
/// <https://discord-userdoccers.vercel.app/resources/user#get-current-user>
pub async fn get(user: &mut UserMeta, id: Option<&String>) -> ChorusResult<User> { pub async fn get(user: &mut UserMeta, id: Option<&String>) -> ChorusResult<User> {
let url_api = user.belongs_to.borrow().urls.api.clone(); let url_api = user.belongs_to.borrow().urls.api.clone();
let url = if id.is_none() { let url = if id.is_none() {
format!("{}/users/@me/", url_api) format!("{}/users/@me", url_api)
} else { } else {
format!("{}/users/{}", url_api, id.unwrap()) format!("{}/users/{}", url_api, id.unwrap())
}; };
@ -114,13 +110,17 @@ impl User {
} }
} }
/// Gets the user's settings.
///
/// # Reference
/// See <https://luna.gitlab.io/discord-unofficial-docs/user_settings.html#get-users-me-settings>
pub async fn get_settings( pub async fn get_settings(
token: &String, token: &String,
url_api: &String, url_api: &String,
instance: &mut Instance, instance: &mut Instance,
) -> ChorusResult<UserSettings> { ) -> ChorusResult<UserSettings> {
let request: reqwest::RequestBuilder = Client::new() let request: reqwest::RequestBuilder = Client::new()
.get(format!("{}/users/@me/settings/", url_api)) .get(format!("{}/users/@me/settings", url_api))
.bearer_auth(token); .bearer_auth(token);
let mut user = let mut user =
UserMeta::shell(Rc::new(RefCell::new(instance.clone())), token.clone()).await; UserMeta::shell(Rc::new(RefCell::new(instance.clone())), token.clone()).await;
@ -141,16 +141,14 @@ impl User {
} }
impl Instance { impl Instance {
/** /// Gets a user by id, or if the id is None, gets the current user.
Get a user object by id, or get the current user. ///
# Arguments /// # Notes
* `token` - A valid access token for the API. /// This function is a wrapper around [`User::get`].
* `id` - The id of the user that will be retrieved. If this is None, the current user will be retrieved. ///
# Errors /// # Reference
* [`ChorusLibError`] - If the request fails. /// See <https://discord-userdoccers.vercel.app/resources/user#get-user> and
# Notes /// <https://discord-userdoccers.vercel.app/resources/user#get-current-user>
This function is a wrapper around [`User::get`].
*/
pub async fn get_user(&mut self, token: String, id: Option<&String>) -> ChorusResult<User> { pub async fn get_user(&mut self, token: String, id: Option<&String>) -> ChorusResult<User> {
let mut user = UserMeta::shell(Rc::new(RefCell::new(self.clone())), token).await; let mut user = UserMeta::shell(Rc::new(RefCell::new(self.clone())), token).await;
let result = User::get(&mut user, id).await; let result = User::get(&mut user, id).await;

View File

@ -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 /// The amount of time we wait for a heartbeat ack before resending our heartbeat in ms
const HEARTBEAT_ACK_TIMEOUT: u64 = 2000; 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. /// This struct is used internally when handling messages.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct GatewayMessage { pub struct GatewayMessage {
@ -150,7 +150,7 @@ impl GatewayMessage {
/// Represents a handle to a Gateway connection. A Gateway connection will create observable /// 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 /// [`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. /// Using this handle you can also send Gateway Events directly.
#[derive(Debug)] #[derive(Debug)]
pub struct GatewayHandle { pub struct GatewayHandle {

View File

@ -2,6 +2,7 @@ use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
use std::sync::{Arc, Mutex};
use reqwest::Client; use reqwest::Client;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -15,10 +16,8 @@ use crate::types::{GeneralConfiguration, User, UserSettings};
use crate::UrlBundle; use crate::UrlBundle;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
/** /// The [`Instance`]; what you will be using to perform all sorts of actions on the Spacebar server.
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.
If `limits_information` is `None`, then the instance will not be rate limited.
*/
pub struct Instance { pub struct Instance {
pub urls: UrlBundle, pub urls: UrlBundle,
pub instance_info: GeneralConfiguration, pub instance_info: GeneralConfiguration,
@ -33,12 +32,7 @@ pub struct LimitsInformation {
} }
impl Instance { impl Instance {
/// Creates a new [`Instance`]. /// Creates a new [`Instance`] from the [relevant instance urls](UrlBundle), where `limited` is whether or not to automatically use rate limits.
/// # 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.
pub async fn new(urls: UrlBundle, limited: bool) -> ChorusResult<Instance> { pub async fn new(urls: UrlBundle, limited: bool) -> ChorusResult<Instance> {
let limits_information; let limits_information;
if limited { if limited {
@ -90,12 +84,15 @@ impl fmt::Display for Token {
} }
#[derive(Debug)] #[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 struct UserMeta {
pub belongs_to: Rc<RefCell<Instance>>, pub belongs_to: Rc<RefCell<Instance>>,
pub token: String, pub token: String,
pub limits: Option<HashMap<LimitType, Limit>>, pub limits: Option<HashMap<LimitType, Limit>>,
pub settings: UserSettings, pub settings: Arc<Mutex<UserSettings>>,
pub object: User, pub object: Arc<Mutex<User>>,
pub gateway: GatewayHandle, pub gateway: GatewayHandle,
} }
@ -108,12 +105,17 @@ impl UserMeta {
self.token = token; 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( pub fn new(
belongs_to: Rc<RefCell<Instance>>, belongs_to: Rc<RefCell<Instance>>,
token: String, token: String,
limits: Option<HashMap<LimitType, Limit>>, limits: Option<HashMap<LimitType, Limit>>,
settings: UserSettings, settings: Arc<Mutex<UserSettings>>,
object: User, object: Arc<Mutex<User>>,
gateway: GatewayHandle, gateway: GatewayHandle,
) -> UserMeta { ) -> UserMeta {
UserMeta { UserMeta {
@ -132,8 +134,8 @@ impl UserMeta {
/// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify /// need to make a RateLimited request. To use the [`GatewayHandle`], you will have to identify
/// first. /// first.
pub(crate) async fn shell(instance: Rc<RefCell<Instance>>, token: String) -> UserMeta { pub(crate) async fn shell(instance: Rc<RefCell<Instance>>, token: String) -> UserMeta {
let settings = UserSettings::default(); let settings = Arc::new(Mutex::new(UserSettings::default()));
let object = User::default(); let object = Arc::new(Mutex::new(User::default()));
let wss_url = instance.borrow().urls.wss.clone(); let wss_url = instance.borrow().urls.wss.clone();
// Dummy gateway object // Dummy gateway object
let gateway = Gateway::new(wss_url).await.unwrap(); let gateway = Gateway::new(wss_url).await.unwrap();

View File

@ -16,15 +16,25 @@ pub mod types;
pub mod voice; pub mod voice;
#[derive(Clone, Default, Debug, PartialEq, Eq)] #[derive(Clone, Default, Debug, PartialEq, Eq)]
/// A URLBundle is a struct which bundles together the API-, Gateway- and CDN-URLs of a Spacebar /// A URLBundle bundles together the API-, Gateway- and CDN-URLs of a Spacebar instance.
/// instance. ///
/// # Notes
/// All the urls can be found on the /api/policies/instance/domains endpoint of a spacebar server
pub struct UrlBundle { pub struct UrlBundle {
/// The api's url.
/// Ex: `https://old.server.spacebar.chat/api`
pub api: String, 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, pub wss: String,
/// The CDN's url.
/// Ex: `https://cdn.old.server.spacebar.chat`
pub cdn: String, pub cdn: String,
} }
impl UrlBundle { impl UrlBundle {
/// Creates a new UrlBundle from the relevant urls.
pub fn new(api: String, wss: String, cdn: String) -> Self { pub fn new(api: String, wss: String, cdn: String) -> Self {
Self { Self {
api: UrlBundle::parse_url(api), 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 /// Parses a URL using the Url library and formats it in a standardized way.
/// way. If no protocol is given, HTTP (not HTTPS) is assumed. /// If no protocol is given, HTTP (not HTTPS) is assumed.
/// # Example: ///
/// # Examples:
/// ```rs /// ```rs
/// let url = parse_url("localhost:3000"); /// let url = parse_url("localhost:3000");
/// ``` /// ```

View File

@ -237,6 +237,9 @@ impl ChorusRequest {
/// reset to the rate limit limit. /// reset to the rate limit limit.
/// 2. The remaining rate limit is decreased by 1. /// 2. The remaining rate limit is decreased by 1.
fn update_rate_limits(user: &mut UserMeta, limit_type: &LimitType, response_was_err: bool) { 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 = [ let instance_dictated_limits = [
&LimitType::AuthLogin, &LimitType::AuthLogin,
&LimitType::AuthRegister, &LimitType::AuthRegister,
@ -292,6 +295,13 @@ impl ChorusRequest {
} }
} }
/// Gets the ratelimit configuration.
///
/// # Notes
/// This is a spacebar only endpoint.
///
/// # Reference
/// See <https://docs.spacebar.chat/routes/#get-/policies/instance/limits/>
pub(crate) async fn get_limits_config(url_api: &str) -> ChorusResult<LimitsConfiguration> { pub(crate) async fn get_limits_config(url_api: &str) -> ChorusResult<LimitsConfiguration> {
let request = Client::new() let request = Client::new()
.get(format!("{}/policies/instance/limits/", url_api)) .get(format!("{}/policies/instance/limits/", url_api))

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use bitflags::bitflags; use bitflags::bitflags;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
@ -6,8 +8,10 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
use crate::types::{Team, User}; use crate::types::{Team, User};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// # Reference
/// See <https://discord.com/developers/docs/resources/application#application-resource>
pub struct Application { pub struct Application {
pub id: Snowflake, pub id: Snowflake,
pub name: String, pub name: String,
@ -23,7 +27,7 @@ pub struct Application {
pub bot_require_code_grant: bool, pub bot_require_code_grant: bool,
pub verify_key: String, pub verify_key: String,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub owner: User, pub owner: Arc<Mutex<User>>,
pub flags: u64, pub flags: u64,
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub redirect_uris: Option<sqlx::types::Json<Vec<String>>>, pub redirect_uris: Option<sqlx::types::Json<Vec<String>>>,
@ -45,7 +49,7 @@ pub struct Application {
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub install_params: Option<sqlx::types::Json<InstallParams>>, pub install_params: Option<sqlx::types::Json<InstallParams>>,
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub install_params: Option<InstallParams>, pub install_params: Option<Arc<Mutex<InstallParams>>>,
pub terms_of_service_url: Option<String>, pub terms_of_service_url: Option<String>,
pub privacy_policy_url: Option<String>, pub privacy_policy_url: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
@ -93,44 +97,64 @@ impl Application {
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
/// # Reference
/// See <https://discord.com/developers/docs/resources/application#install-params-object>
pub struct InstallParams { pub struct InstallParams {
pub scopes: Vec<String>, pub scopes: Vec<String>,
pub permissions: String, pub permissions: String,
} }
bitflags! { bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
/// # Reference
/// See <https://discord.com/developers/docs/resources/application#application-object-application-flags>
pub struct ApplicationFlags: u64 { pub struct ApplicationFlags: u64 {
/// Indicates if an app uses the Auto Moderation API
const APPLICATION_AUTO_MODERATION_RULE_CREATE_BADGE = 1 << 6; 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; 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; 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; 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; const GATEWAY_GUILD_MEMBERS_LIMITED = 1 << 15;
/// Indicates unusual growth of an app that prevents verification
const VERIFICATION_PENDING_GUILD_LIMIT = 1 << 16; const VERIFICATION_PENDING_GUILD_LIMIT = 1 << 16;
/// Indicates if an app is embedded within the Discord client (currently unavailable publicly)
const EMBEDDED = 1 << 17; const EMBEDDED = 1 << 17;
/// Intent required for bots in 100 or more servers to receive message content
const GATEWAY_MESSAGE_CONTENT = 1 << 18; 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; const GATEWAY_MESSAGE_CONTENT_LIMITED = 1 << 19;
/// Indicates if an app has registered slash commands
const APPLICATION_COMMAND_BADGE = 1 << 23; const APPLICATION_COMMAND_BADGE = 1 << 23;
} }
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
/// # Reference
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-object>
pub struct ApplicationCommand { pub struct ApplicationCommand {
pub id: Snowflake, pub id: Snowflake,
pub application_id: Snowflake, pub application_id: Snowflake,
pub name: String, pub name: String,
pub description: String, pub description: String,
pub options: Vec<ApplicationCommandOption>, pub options: Vec<Arc<Mutex<ApplicationCommandOption>>>,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
/// Reference
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-option-structure>
pub struct ApplicationCommandOption { pub struct ApplicationCommandOption {
pub r#type: ApplicationCommandOptionType, pub r#type: ApplicationCommandOptionType,
pub name: String, pub name: String,
pub description: String, pub description: String,
pub required: bool, pub required: bool,
pub choices: Vec<ApplicationCommandOptionChoice>, pub choices: Vec<ApplicationCommandOptionChoice>,
pub options: Vec<ApplicationCommandOption>, pub options: Arc<Mutex<Vec<ApplicationCommandOption>>>,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@ -139,45 +163,54 @@ pub struct ApplicationCommandOptionChoice {
pub value: Value, 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))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[repr(i32)] #[repr(i32)]
/// # Reference
/// See <https://discord.com/developers/docs/interactions/application-commands#application-command-object-application-command-types>
pub enum ApplicationCommandOptionType { pub enum ApplicationCommandOptionType {
SubCommand = 1, SubCommand = 1,
SubCommandGroup = 2, SubCommandGroup = 2,
String = 3, String = 3,
/// Any integer between -2^53 and 2^53
Integer = 4, Integer = 4,
Boolean = 5, Boolean = 5,
User = 6, User = 6,
/// Includes all channel types + categories
Channel = 7, Channel = 7,
Role = 8, 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 struct ApplicationCommandInteractionData {
pub id: Snowflake, pub id: Snowflake,
pub name: String, pub name: String,
pub options: Vec<ApplicationCommandInteractionDataOption>, pub options: Vec<Arc<Mutex<ApplicationCommandInteractionDataOption>>>,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApplicationCommandInteractionDataOption { pub struct ApplicationCommandInteractionDataOption {
pub name: String, pub name: String,
pub value: Value, pub value: Value,
pub options: Vec<ApplicationCommandInteractionDataOption>, pub options: Vec<Arc<Mutex<ApplicationCommandInteractionDataOption>>>,
} }
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Default, Clone, Serialize, Deserialize)]
/// See https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure /// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure>
pub struct GuildApplicationCommandPermissions { pub struct GuildApplicationCommandPermissions {
pub id: Snowflake, pub id: Snowflake,
pub application_id: Snowflake, pub application_id: Snowflake,
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub permissions: Vec<ApplicationCommandPermission>, pub permissions: Vec<Arc<Mutex<ApplicationCommandPermission>>>,
} }
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)] #[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 <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-structure>
pub struct ApplicationCommandPermission { pub struct ApplicationCommandPermission {
pub id: Snowflake, pub id: Snowflake,
#[serde(rename = "type")] #[serde(rename = "type")]
@ -186,10 +219,10 @@ pub struct ApplicationCommandPermission {
pub permission: bool, 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")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[repr(u8)] #[repr(u8)]
/// See https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permission-type /// See <https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permission-type>
pub enum ApplicationCommandPermissionType { pub enum ApplicationCommandPermissionType {
#[default] #[default]
Role = 1, Role = 1,

View File

@ -4,9 +4,12 @@ use crate::types::utils::Snowflake;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// # Reference
/// See <https://discord.com/developers/docs/resources/channel#attachment-object>
pub struct Attachment { pub struct Attachment {
pub id: Snowflake, pub id: Snowflake,
pub filename: String, pub filename: String,
/// Max 1024 characters
pub description: Option<String>, pub description: Option<String>,
pub content_type: Option<String>, pub content_type: Option<String>,
pub size: u64, pub size: u64,
@ -15,7 +18,13 @@ pub struct Attachment {
pub height: Option<u64>, pub height: Option<u64>,
pub width: Option<u64>, pub width: Option<u64>,
pub ephemeral: Option<bool>, pub ephemeral: Option<bool>,
/// The duration of the audio file (only for voice messages)
pub duration_secs: Option<f32>, pub duration_secs: Option<f32>,
/// 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<String>, pub waveform: Option<String>,
#[serde(skip_serializing)] #[serde(skip_serializing)]
#[cfg_attr(feature = "sqlx", sqlx(default))] #[cfg_attr(feature = "sqlx", sqlx(default))]
@ -26,6 +35,7 @@ pub struct Attachment {
pub struct PartialDiscordFileAttachment { pub struct PartialDiscordFileAttachment {
pub id: Option<i16>, pub id: Option<i16>,
pub filename: String, pub filename: String,
/// Max 1024 characters
pub description: Option<String>, pub description: Option<String>,
pub content_type: Option<String>, pub content_type: Option<String>,
pub size: Option<i64>, pub size: Option<i64>,
@ -34,18 +44,20 @@ pub struct PartialDiscordFileAttachment {
pub height: Option<i32>, pub height: Option<i32>,
pub width: Option<i32>, pub width: Option<i32>,
pub ephemeral: Option<bool>, pub ephemeral: Option<bool>,
/// The duration of the audio file (only for voice messages)
pub duration_secs: Option<f32>, pub duration_secs: Option<f32>,
/// 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<String>, pub waveform: Option<String>,
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub content: Vec<u8>, pub content: Vec<u8>,
} }
impl PartialDiscordFileAttachment { impl PartialDiscordFileAttachment {
/** /// Moves `self.content` out of `self` and returns it.
Moves `self.content` out of `self` and returns it.
# Returns
Vec<u8>
*/
pub fn move_content(self) -> (Vec<u8>, PartialDiscordFileAttachment) { pub fn move_content(self) -> (Vec<u8>, PartialDiscordFileAttachment) {
let content = self.content; let content = self.content;
let updated_struct = PartialDiscordFileAttachment { let updated_struct = PartialDiscordFileAttachment {
@ -66,6 +78,7 @@ impl PartialDiscordFileAttachment {
(content, updated_struct) (content, updated_struct)
} }
/// Moves `self.filename` out of `self` and returns it.
pub fn move_filename(self) -> (String, PartialDiscordFileAttachment) { pub fn move_filename(self) -> (String, PartialDiscordFileAttachment) {
let filename = self.filename; let filename = self.filename;
let updated_struct = PartialDiscordFileAttachment { let updated_struct = PartialDiscordFileAttachment {
@ -87,6 +100,7 @@ impl PartialDiscordFileAttachment {
(filename, updated_struct) (filename, updated_struct)
} }
/// Moves `self.content_type` out of `self` and returns it.
pub fn move_content_type(self) -> (Option<String>, PartialDiscordFileAttachment) { pub fn move_content_type(self) -> (Option<String>, PartialDiscordFileAttachment) {
let content_type = self.content_type; let content_type = self.content_type;
let updated_struct = PartialDiscordFileAttachment { let updated_struct = PartialDiscordFileAttachment {

View File

@ -1,12 +1,14 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
/// See https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object /// See <https://discord.com/developers/docs/resources/audit-log#audit-log-entry-object>
pub struct AuditLogEntry { pub struct AuditLogEntry {
pub target_id: Option<String>, pub target_id: Option<String>,
pub changes: Option<Vec<AuditLogChange>>, pub changes: Option<Vec<Arc<Mutex<AuditLogChange>>>>,
pub user_id: Option<Snowflake>, pub user_id: Option<Snowflake>,
pub id: Snowflake, pub id: Snowflake,
// to:do implement an enum for these types // to:do implement an enum for these types
@ -17,7 +19,7 @@ pub struct AuditLogEntry {
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
/// See https://discord.com/developers/docs/resources/audit-log#audit-log-change-object /// See <https://discord.com/developers/docs/resources/audit-log#audit-log-change-object>
pub struct AuditLogChange { pub struct AuditLogChange {
pub new_value: Option<serde_json::Value>, pub new_value: Option<serde_json::Value>,
pub old_value: Option<serde_json::Value>, pub old_value: Option<serde_json::Value>,

View File

@ -1,10 +1,12 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object>
pub struct AutoModerationRule { pub struct AutoModerationRule {
pub id: Snowflake, pub id: Snowflake,
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -12,8 +14,8 @@ pub struct AutoModerationRule {
pub creator_id: Snowflake, pub creator_id: Snowflake,
pub event_type: AutoModerationRuleEventType, pub event_type: AutoModerationRuleEventType,
pub trigger_type: AutoModerationRuleTriggerType, pub trigger_type: AutoModerationRuleTriggerType,
pub trigger_metadata: AutoModerationRuleTriggerMetadata, pub trigger_metadata: Arc<Mutex<AutoModerationRuleTriggerMetadata>>,
pub actions: Vec<AutoModerationAction>, pub actions: Vec<Arc<Mutex<AutoModerationAction>>>,
pub enabled: bool, pub enabled: bool,
pub exempt_roles: Vec<Snowflake>, pub exempt_roles: Vec<Snowflake>,
pub exempt_channels: Vec<Snowflake>, pub exempt_channels: Vec<Snowflake>,
@ -22,7 +24,7 @@ pub struct AutoModerationRule {
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-event-types /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-event-types>
pub enum AutoModerationRuleEventType { pub enum AutoModerationRuleEventType {
#[default] #[default]
MessageSend = 1, MessageSend = 1,
@ -31,7 +33,7 @@ pub enum AutoModerationRuleEventType {
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-types>
pub enum AutoModerationRuleTriggerType { pub enum AutoModerationRuleTriggerType {
#[default] #[default]
Keyword = 1, Keyword = 1,
@ -42,7 +44,7 @@ pub enum AutoModerationRuleTriggerType {
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(untagged)] #[serde(untagged)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata>
pub enum AutoModerationRuleTriggerMetadata { pub enum AutoModerationRuleTriggerMetadata {
ForKeyword(AutoModerationRuleTriggerMetadataForKeyword), ForKeyword(AutoModerationRuleTriggerMetadataForKeyword),
ForKeywordPreset(AutoModerationRuleTriggerMetadataForKeywordPreset), ForKeywordPreset(AutoModerationRuleTriggerMetadataForKeywordPreset),
@ -52,7 +54,7 @@ pub enum AutoModerationRuleTriggerMetadata {
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata>
pub struct AutoModerationRuleTriggerMetadataForKeyword { pub struct AutoModerationRuleTriggerMetadataForKeyword {
pub keyword_filter: Vec<String>, pub keyword_filter: Vec<String>,
pub regex_patterns: Vec<String>, pub regex_patterns: Vec<String>,
@ -60,14 +62,14 @@ pub struct AutoModerationRuleTriggerMetadataForKeyword {
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata>
pub struct AutoModerationRuleTriggerMetadataForKeywordPreset { pub struct AutoModerationRuleTriggerMetadataForKeywordPreset {
pub presets: Vec<AutoModerationRuleKeywordPresetType>, pub presets: Vec<AutoModerationRuleKeywordPresetType>,
pub allow_list: Vec<String>, pub allow_list: Vec<String>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata>
pub struct AutoModerationRuleTriggerMetadataForMentionSpam { pub struct AutoModerationRuleTriggerMetadataForMentionSpam {
/// Max 50 /// Max 50
pub mention_total_limit: u8, pub mention_total_limit: u8,
@ -77,7 +79,7 @@ pub struct AutoModerationRuleTriggerMetadataForMentionSpam {
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-preset-types /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-keyword-preset-types>
pub enum AutoModerationRuleKeywordPresetType { pub enum AutoModerationRuleKeywordPresetType {
#[default] #[default]
Profanity = 1, Profanity = 1,
@ -86,17 +88,17 @@ pub enum AutoModerationRuleKeywordPresetType {
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object>
pub struct AutoModerationAction { pub struct AutoModerationAction {
#[serde(rename = "type")] #[serde(rename = "type")]
pub action_type: AutoModerationActionType, pub action_type: AutoModerationActionType,
pub metadata: Option<AutoModerationActionMetadata>, pub metadata: Option<Arc<Mutex<AutoModerationActionMetadata>>>,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-types /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-types>
pub enum AutoModerationActionType { pub enum AutoModerationActionType {
#[default] #[default]
BlockMessage = 1, BlockMessage = 1,
@ -106,7 +108,7 @@ pub enum AutoModerationActionType {
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[serde(untagged)] #[serde(untagged)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata>
pub enum AutoModerationActionMetadata { pub enum AutoModerationActionMetadata {
ForBlockMessage(AutoModerationActionMetadataForBlockMessage), ForBlockMessage(AutoModerationActionMetadataForBlockMessage),
ForSendAlertMessage(AutoModerationActionMetadataForSendAlertMessage), ForSendAlertMessage(AutoModerationActionMetadataForSendAlertMessage),
@ -116,19 +118,19 @@ pub enum AutoModerationActionMetadata {
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata>
pub struct AutoModerationActionMetadataForBlockMessage { pub struct AutoModerationActionMetadataForBlockMessage {
pub custom_message: Option<String>, pub custom_message: Option<String>,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata>
pub struct AutoModerationActionMetadataForSendAlertMessage { pub struct AutoModerationActionMetadataForSendAlertMessage {
pub channel_id: Snowflake, pub channel_id: Snowflake,
} }
#[derive(Serialize, Deserialize, Debug, Clone, Default)] #[derive(Serialize, Deserialize, Debug, Clone, Default)]
/// See https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata /// See <https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-action-object-action-metadata>
pub struct AutoModerationActionMetadataForTimeout { pub struct AutoModerationActionMetadataForTimeout {
/// Max 2419200 /// Max 2419200
pub duration_seconds: u32, pub duration_seconds: u32,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chorus_macros::Updateable; use chorus_macros::Updateable;
use chrono::Utc; use chrono::Utc;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -10,8 +12,12 @@ use crate::types::{
utils::Snowflake, 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))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// Represents a guild of private channel
///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/channel#channels-resource>
pub struct Channel { pub struct Channel {
pub application_id: Option<Snowflake>, pub application_id: Option<Snowflake>,
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
@ -42,7 +48,7 @@ pub struct Channel {
pub last_pin_timestamp: Option<String>, pub last_pin_timestamp: Option<String>,
pub managed: Option<bool>, pub managed: Option<bool>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub member: Option<ThreadMember>, pub member: Option<Arc<Mutex<ThreadMember>>>,
pub member_count: Option<i32>, pub member_count: Option<i32>,
pub message_count: Option<i32>, pub message_count: Option<i32>,
pub name: Option<String>, pub name: Option<String>,
@ -52,12 +58,12 @@ pub struct Channel {
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub permission_overwrites: Option<sqlx::types::Json<Vec<PermissionOverwrite>>>, pub permission_overwrites: Option<sqlx::types::Json<Vec<PermissionOverwrite>>>,
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub permission_overwrites: Option<Vec<PermissionOverwrite>>, pub permission_overwrites: Option<Vec<Arc<Mutex<PermissionOverwrite>>>>,
pub permissions: Option<String>, pub permissions: Option<String>,
pub position: Option<i32>, pub position: Option<i32>,
pub rate_limit_per_user: Option<i32>, pub rate_limit_per_user: Option<i32>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub recipients: Option<Vec<User>>, pub recipients: Option<Vec<Arc<Mutex<User>>>>,
pub rtc_region: Option<String>, pub rtc_region: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub thread_metadata: Option<ThreadMetadata>, pub thread_metadata: Option<ThreadMetadata>,
@ -67,10 +73,50 @@ pub struct Channel {
pub video_quality_mode: Option<i32>, pub video_quality_mode: Option<i32>,
} }
#[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 <https://discord-userdoccers.vercel.app/resources/channel#forum-tag-object>
pub struct Tag { pub struct Tag {
pub id: Snowflake, pub id: Snowflake,
/// The name of the tag (max 20 characters)
pub name: String, 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 moderated: bool,
pub emoji_id: Option<Snowflake>, pub emoji_id: Option<Snowflake>,
pub emoji_name: Option<String>, pub emoji_name: Option<String>,
@ -91,6 +137,8 @@ pub struct PermissionOverwrite {
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/channel#thread-metadata-object>
pub struct ThreadMetadata { pub struct ThreadMetadata {
pub archived: bool, pub archived: bool,
pub auto_archive_duration: i32, pub auto_archive_duration: i32,
@ -100,47 +148,81 @@ pub struct ThreadMetadata {
pub create_timestamp: Option<String>, pub create_timestamp: Option<String>,
} }
#[derive(Default, Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[derive(Default, Debug, Deserialize, Serialize, Clone)]
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/channel#thread-member-object>
pub struct ThreadMember { pub struct ThreadMember {
pub id: Option<Snowflake>, pub id: Option<Snowflake>,
pub user_id: Option<Snowflake>, pub user_id: Option<Snowflake>,
pub join_timestamp: Option<String>, pub join_timestamp: Option<String>,
pub flags: Option<u64>, pub flags: Option<u64>,
pub member: Option<GuildMember>, pub member: Option<Arc<Mutex<GuildMember>>>,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] #[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 <https://discord-userdoccers.vercel.app/resources/channel#default-reaction-object>
pub struct DefaultReaction { pub struct DefaultReaction {
#[serde(default)] #[serde(default)]
pub emoji_id: Option<Snowflake>, pub emoji_id: Option<Snowflake>,
pub emoji_name: Option<String>, pub emoji_name: Option<String>,
} }
#[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))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[repr(i32)] #[repr(i32)]
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/channel#channel-type>
pub enum ChannelType { pub enum ChannelType {
#[default] #[default]
/// A text channel within a guild
GuildText = 0, GuildText = 0,
/// A private channel between two users
Dm = 1, Dm = 1,
/// A voice channel within a guild
GuildVoice = 2, GuildVoice = 2,
/// A private channel between multiple users
GroupDm = 3, GroupDm = 3,
/// An organizational category that contains up to 50 channels
GuildCategory = 4, GuildCategory = 4,
/// Similar to [GuildText](ChannelType::GuildText), a channel that users can follow and crosspost into their own guild
GuildNews = 5, GuildNews = 5,
/// A channel in which game developers can sell their game on Discord
///
/// # Note
/// Deprecated.
GuildStore = 6, GuildStore = 6,
// FIXME userdoccers says 7 is GuildLfg, is this a spacebar specific thing?
Encrypted = 7, Encrypted = 7,
// FIXME userdoccers says 8 is LfgGuildDm, is this a spacebar specific thing?
EncryptedThreads = 8, EncryptedThreads = 8,
// FIXME userdoccers says 9 is ThreadAlpha, was this changed?
Transactional = 9, Transactional = 9,
/// A thread within a [GuildNews](ChannelType::GuildNews) channel
GuildNewsThread = 10, GuildNewsThread = 10,
/// A thread within a [GuildText](ChannelType::GuildText), [GuildForum](ChannelType::GuildForum), or [GuildMedia](ChannelType::GuildMedia) channel
GuildPublicThread = 11, 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, GuildPrivateThread = 12,
/// A voice channel for hosting events with an audience in a guild
GuildStageVoice = 13, GuildStageVoice = 13,
/// The main channel in a hub containing the listed guilds
Directory = 14, Directory = 14,
/// A channel that can only contain threads
GuildForum = 15, GuildForum = 15,
/// A channel that can only contain threads in a gallery view
GuildMedia = 16,
// TODO: Couldn't find reference
TicketTracker = 33, TicketTracker = 33,
// TODO: Couldn't find reference
Kanban = 34, Kanban = 34,
// TODO: Couldn't find reference
VoicelessWhiteboard = 35, VoicelessWhiteboard = 35,
// TODO: Couldn't find reference
CustomStart = 64, CustomStart = 64,
// TODO: Couldn't find reference
Unhandled = 255, Unhandled = 255,
} }

View File

@ -1,10 +1,14 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::entities::User; use crate::types::entities::User;
use crate::types::Snowflake; 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))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/emoji#emoji-object>
pub struct Emoji { pub struct Emoji {
pub id: Option<Snowflake>, pub id: Option<Snowflake>,
pub name: Option<String>, pub name: Option<String>,
@ -13,7 +17,7 @@ pub struct Emoji {
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub roles: Option<Vec<Snowflake>>, pub roles: Option<Vec<Snowflake>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub user: Option<User>, pub user: Option<Arc<Mutex<User>>>,
pub require_colons: Option<bool>, pub require_colons: Option<bool>,
pub managed: Option<bool>, pub managed: Option<bool>,
pub animated: Option<bool>, pub animated: Option<bool>,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
@ -9,8 +11,8 @@ use crate::types::{
utils::Snowflake, utils::Snowflake,
}; };
/// See https://discord.com/developers/docs/resources/guild /// See <https://discord.com/developers/docs/resources/guild>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Guild { pub struct Guild {
pub afk_channel_id: Option<Snowflake>, pub afk_channel_id: Option<Snowflake>,
@ -25,13 +27,13 @@ pub struct Guild {
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub bans: Option<Vec<GuildBan>>, pub bans: Option<Vec<GuildBan>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub channels: Option<Vec<Channel>>, pub channels: Option<Vec<Arc<Mutex<Channel>>>>,
pub default_message_notifications: Option<i32>, pub default_message_notifications: Option<i32>,
pub description: Option<String>, pub description: Option<String>,
pub discovery_splash: Option<String>, pub discovery_splash: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
#[serde(default)] #[serde(default)]
pub emojis: Vec<Emoji>, pub emojis: Vec<Arc<Mutex<Emoji>>>,
pub explicit_content_filter: Option<i32>, pub explicit_content_filter: Option<i32>,
//#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))]
pub features: Option<GuildFeaturesList>, pub features: Option<GuildFeaturesList>,
@ -40,7 +42,7 @@ pub struct Guild {
pub icon_hash: Option<String>, pub icon_hash: Option<String>,
pub id: Snowflake, pub id: Snowflake,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub invites: Option<Vec<GuildInvite>>, pub invites: Option<Vec<Arc<Mutex<GuildInvite>>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub joined_at: Option<String>, pub joined_at: Option<String>,
pub large: Option<bool>, pub large: Option<bool>,
@ -66,7 +68,7 @@ pub struct Guild {
pub public_updates_channel_id: Option<Snowflake>, pub public_updates_channel_id: Option<Snowflake>,
pub region: Option<String>, pub region: Option<String>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub roles: Option<Vec<RoleObject>>, pub roles: Option<Vec<Arc<Mutex<RoleObject>>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub rules_channel: Option<String>, pub rules_channel: Option<String>,
pub rules_channel_id: Option<Snowflake>, pub rules_channel_id: Option<Snowflake>,
@ -79,18 +81,18 @@ pub struct Guild {
pub vanity_url_code: Option<String>, pub vanity_url_code: Option<String>,
pub verification_level: Option<i32>, pub verification_level: Option<i32>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub voice_states: Option<Vec<VoiceState>>, pub voice_states: Option<Vec<Arc<Mutex<VoiceState>>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub webhooks: Option<Vec<Webhook>>, pub webhooks: Option<Vec<Arc<Mutex<Webhook>>>>,
#[cfg(feature = "sqlx")] #[cfg(feature = "sqlx")]
pub welcome_screen: Option<sqlx::types::Json<WelcomeScreenObject>>, pub welcome_screen: Option<sqlx::types::Json<WelcomeScreenObject>>,
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub welcome_screen: Option<WelcomeScreenObject>, pub welcome_screen: Option<Arc<Mutex<WelcomeScreenObject>>>,
pub widget_channel_id: Option<Snowflake>, pub widget_channel_id: Option<Snowflake>,
pub widget_enabled: Option<bool>, pub widget_enabled: Option<bool>,
} }
/// See https://docs.spacebar.chat/routes/#get-/guilds/-guild_id-/bans/-user- /// See <https://docs.spacebar.chat/routes/#get-/guilds/-guild_id-/bans/-user->
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct GuildBan { pub struct GuildBan {
@ -99,8 +101,8 @@ pub struct GuildBan {
pub reason: Option<String>, pub reason: Option<String>,
} }
/// See https://docs.spacebar.chat/routes/#cmp--schemas-invite /// See <https://docs.spacebar.chat/routes/#cmp--schemas-invite>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct GuildInvite { pub struct GuildInvite {
pub code: String, pub code: String,
@ -111,11 +113,11 @@ pub struct GuildInvite {
pub created_at: DateTime<Utc>, pub created_at: DateTime<Utc>,
pub expires_at: Option<DateTime<Utc>>, pub expires_at: Option<DateTime<Utc>>,
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub guild: Option<Guild>, pub guild: Option<Arc<Mutex<Guild>>>,
pub channel_id: Snowflake, pub channel_id: Snowflake,
pub channel: Option<Channel>, pub channel: Option<Arc<Mutex<Channel>>>,
pub inviter_id: Option<Snowflake>, pub inviter_id: Option<Snowflake>,
pub inviter: Option<User>, pub inviter: Option<Arc<Mutex<User>>>,
pub target_user_id: Option<Snowflake>, pub target_user_id: Option<Snowflake>,
pub target_user: Option<String>, pub target_user: Option<String>,
pub target_user_type: Option<i32>, pub target_user_type: Option<i32>,
@ -134,7 +136,7 @@ pub struct GuildCreateResponse {
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
/// See https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object /// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object>
pub struct GuildScheduledEvent { pub struct GuildScheduledEvent {
pub id: Snowflake, pub id: Snowflake,
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -149,14 +151,14 @@ pub struct GuildScheduledEvent {
pub entity_type: GuildScheduledEventEntityType, pub entity_type: GuildScheduledEventEntityType,
pub entity_id: Option<Snowflake>, pub entity_id: Option<Snowflake>,
pub entity_metadata: Option<GuildScheduledEventEntityMetadata>, pub entity_metadata: Option<GuildScheduledEventEntityMetadata>,
pub creator: Option<User>, pub creator: Option<Arc<Mutex<User>>>,
pub user_count: Option<u64>, pub user_count: Option<u64>,
pub image: Option<String>, pub image: Option<String>,
} }
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)]
#[repr(u8)] #[repr(u8)]
/// See https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-privacy-level /// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-privacy-level>
pub enum GuildScheduledEventPrivacyLevel { pub enum GuildScheduledEventPrivacyLevel {
#[default] #[default]
GuildOnly = 2, GuildOnly = 2,
@ -164,7 +166,7 @@ pub enum GuildScheduledEventPrivacyLevel {
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)]
#[repr(u8)] #[repr(u8)]
/// See https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-status /// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-status>
pub enum GuildScheduledEventStatus { pub enum GuildScheduledEventStatus {
#[default] #[default]
Scheduled = 1, Scheduled = 1,
@ -175,7 +177,7 @@ pub enum GuildScheduledEventStatus {
#[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)] #[derive(Serialize_repr, Deserialize_repr, Debug, Default, Clone)]
#[repr(u8)] #[repr(u8)]
/// See https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-types /// See <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-types>
pub enum GuildScheduledEventEntityType { pub enum GuildScheduledEventEntityType {
#[default] #[default]
StageInstance = 1, StageInstance = 1,
@ -184,7 +186,7 @@ pub enum GuildScheduledEventEntityType {
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[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 <https://discord.com/developers/docs/resources/guild-scheduled-event#guild-scheduled-event-object-guild-scheduled-event-entity-metadata>
pub struct GuildScheduledEventEntityMetadata { pub struct GuildScheduledEventEntityMetadata {
pub location: Option<String>, pub location: Option<String>,
} }

View File

@ -1,10 +1,16 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{entities::PublicUser, Snowflake}; 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 <https://discord-userdoccers.vercel.app/resources/guild#guild-member-object>
pub struct GuildMember { pub struct GuildMember {
pub user: Option<PublicUser>, pub user: Option<Arc<Mutex<PublicUser>>>,
pub nick: Option<String>, pub nick: Option<String>,
pub avatar: Option<String>, pub avatar: Option<String>,
pub roles: Vec<Snowflake>, pub roles: Vec<Snowflake>,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -8,7 +10,7 @@ use crate::types::{
#[derive(Default, Debug, Deserialize, Serialize, Clone)] #[derive(Default, Debug, Deserialize, Serialize, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// See https://discord.com/developers/docs/resources/guild#integration-object-integration-structure /// See <https://discord.com/developers/docs/resources/guild#integration-object-integration-structure>
pub struct Integration { pub struct Integration {
pub id: Snowflake, pub id: Snowflake,
pub name: String, pub name: String,
@ -21,19 +23,19 @@ pub struct Integration {
pub expire_behaviour: Option<u8>, pub expire_behaviour: Option<u8>,
pub expire_grace_period: Option<u16>, pub expire_grace_period: Option<u16>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub user: Option<User>, pub user: Option<Arc<Mutex<User>>>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub account: IntegrationAccount, pub account: IntegrationAccount,
pub synced_at: Option<DateTime<Utc>>, pub synced_at: Option<DateTime<Utc>>,
pub subscriber_count: Option<f64>, pub subscriber_count: Option<f64>,
pub revoked: Option<bool>, pub revoked: Option<bool>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub application: Option<Application>, pub application: Option<Arc<Mutex<Application>>>,
pub scopes: Option<Vec<String>>, pub scopes: Option<Vec<String>>,
} }
#[derive(Default, Debug, Deserialize, Serialize, Clone)] #[derive(Default, Debug, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/resources/guild#integration-account-object-integration-account-structure /// See <https://discord.com/developers/docs/resources/guild#integration-account-object-integration-account-structure>
pub struct IntegrationAccount { pub struct IntegrationAccount {
pub id: String, pub id: String,
pub name: String, pub name: String,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -68,7 +70,7 @@ pub enum NSFWLevel {
/// See <https://discord-userdoccers.vercel.app/resources/invite#invite-stage-instance-object> /// See <https://discord-userdoccers.vercel.app/resources/invite#invite-stage-instance-object>
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct InviteStageInstance { pub struct InviteStageInstance {
pub members: Vec<GuildMember>, pub members: Vec<Arc<Mutex<GuildMember>>>,
pub participant_count: i32, pub participant_count: i32,
pub speaker_count: i32, pub speaker_count: i32,
pub topic: String, pub topic: String,

View File

@ -8,8 +8,12 @@ use crate::types::{
utils::Snowflake, utils::Snowflake,
}; };
#[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// Represents a message sent in a channel.
///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/message#message-object>
pub struct Message { pub struct Message {
pub id: Snowflake, pub id: Snowflake,
pub channel_id: Snowflake, pub channel_id: Snowflake,
@ -64,6 +68,8 @@ pub struct Message {
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/message#message-reference-object>
pub struct MessageReference { pub struct MessageReference {
pub message_id: Snowflake, pub message_id: Snowflake,
pub channel_id: Snowflake, pub channel_id: Snowflake,
@ -71,7 +77,7 @@ pub struct MessageReference {
pub fail_if_not_exists: Option<bool>, pub fail_if_not_exists: Option<bool>,
} }
#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] #[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MessageInteraction { pub struct MessageInteraction {
pub id: Snowflake, pub id: Snowflake,
#[serde(rename = "type")] #[serde(rename = "type")]
@ -106,7 +112,7 @@ pub struct ChannelMention {
name: String, name: String,
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Embed { pub struct Embed {
title: Option<String>, title: Option<String>,
#[serde(rename = "type")] #[serde(rename = "type")]
@ -176,10 +182,13 @@ pub struct EmbedField {
inline: Option<bool>, inline: Option<bool>,
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Reaction { pub struct Reaction {
pub count: i32, pub count: u32,
pub burst_count: u32,
pub me: bool, pub me: bool,
pub burst_me: bool,
pub burst_colors: Vec<String>,
pub emoji: Emoji, pub emoji: Emoji,
} }
@ -196,6 +205,8 @@ pub enum Component {
} }
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/message#message-activity-object>
pub struct MessageActivity { pub struct MessageActivity {
#[serde(rename = "type")] #[serde(rename = "type")]
pub activity_type: i64, pub activity_type: i64,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr}; use serde_repr::{Deserialize_repr, Serialize_repr};
@ -6,20 +8,29 @@ use crate::types::Snowflake;
use super::PublicUser; use super::PublicUser;
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq, Eq)] #[derive(Debug, Deserialize, Serialize, Clone, Default)]
/// See https://discord-userdoccers.vercel.app/resources/user#relationship-structure /// See <https://discord-userdoccers.vercel.app/resources/user#relationship-structure>
pub struct Relationship { pub struct Relationship {
pub id: Snowflake, pub id: Snowflake,
#[serde(rename = "type")] #[serde(rename = "type")]
pub relationship_type: RelationshipType, pub relationship_type: RelationshipType,
pub nickname: Option<String>, pub nickname: Option<String>,
pub user: PublicUser, pub user: Arc<Mutex<PublicUser>>,
pub since: Option<DateTime<Utc>>, pub since: Option<DateTime<Utc>>,
} }
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)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default, Eq, PartialEq)]
#[repr(u8)] #[repr(u8)]
/// See https://discord-userdoccers.vercel.app/resources/user#relationship-type /// See <https://discord-userdoccers.vercel.app/resources/user#relationship-type>
pub enum RelationshipType { pub enum RelationshipType {
Suggestion = 6, Suggestion = 6,
Implicit = 5, Implicit = 5,

View File

@ -6,7 +6,7 @@ use crate::types::utils::Snowflake;
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// See https://discord.com/developers/docs/topics/permissions#role-object /// See <https://discord.com/developers/docs/topics/permissions#role-object>
pub struct RoleObject { pub struct RoleObject {
pub id: Snowflake, pub id: Snowflake,
pub name: String, pub name: String,
@ -34,8 +34,8 @@ pub struct RoleSubscriptionData {
pub is_renewal: bool, pub is_renewal: bool,
} }
#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, Hash)]
/// See https://discord.com/developers/docs/topics/permissions#role-object-role-tags-structure /// See <https://discord.com/developers/docs/topics/permissions#role-object-role-tags-structure>
pub struct RoleTags { pub struct RoleTags {
#[serde(default)] #[serde(default)]
#[serde(deserialize_with = "deserialize_option_number_from_string")] #[serde(deserialize_with = "deserialize_option_number_from_string")]
@ -53,57 +53,110 @@ pub struct RoleTags {
} }
bitflags! { 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 <https://discord.com/developers/docs/topics/permissions#permissions>
pub struct PermissionFlags: u64 { pub struct PermissionFlags: u64 {
/// Allows creation of instant invites
const CREATE_INSTANT_INVITE = 1 << 0; const CREATE_INSTANT_INVITE = 1 << 0;
/// Allows kicking members
const KICK_MEMBERS = 1 << 1; const KICK_MEMBERS = 1 << 1;
/// Allows banning members
const BAN_MEMBERS = 1 << 2; const BAN_MEMBERS = 1 << 2;
/// Allows all permissions and bypasses channel permission overwrites
const ADMINISTRATOR = 1 << 3; const ADMINISTRATOR = 1 << 3;
/// Allows management and editing of channels
const MANAGE_CHANNELS = 1 << 4; const MANAGE_CHANNELS = 1 << 4;
/// Allows management and editing of the guild and guild settings
const MANAGE_GUILD = 1 << 5; const MANAGE_GUILD = 1 << 5;
/// Allows for the addition of reactions to messages
const ADD_REACTIONS = 1 << 6; const ADD_REACTIONS = 1 << 6;
/// Allows viewing of the audit log
const VIEW_AUDIT_LOG = 1 << 7; const VIEW_AUDIT_LOG = 1 << 7;
/// Allows using priority speaker in a voice channel
const PRIORITY_SPEAKER = 1 << 8; const PRIORITY_SPEAKER = 1 << 8;
/// Allows the user to go live and share their screen
const STREAM = 1 << 9; 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; 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; const SEND_MESSAGES = 1 << 11;
/// Allows sending /tts messages
const SEND_TTS_MESSAGES = 1 << 12; const SEND_TTS_MESSAGES = 1 << 12;
/// Allows deletion of other users' messages
const MANAGE_MESSAGES = 1 << 13; const MANAGE_MESSAGES = 1 << 13;
/// Links sent by users with this permission will be auto-embedded
const EMBED_LINKS = 1 << 14; const EMBED_LINKS = 1 << 14;
/// Allows uploading images and files
const ATTACH_FILES = 1 << 15; const ATTACH_FILES = 1 << 15;
/// Allows reading of message history
const READ_MESSAGE_HISTORY = 1 << 16; 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; const MENTION_EVERYONE = 1 << 17;
/// Allows the usage of custom emojis from other servers
const USE_EXTERNAL_EMOJIS = 1 << 18; const USE_EXTERNAL_EMOJIS = 1 << 18;
/// Allows viewing guild insights
const VIEW_GUILD_INSIGHTS = 1 << 19; const VIEW_GUILD_INSIGHTS = 1 << 19;
/// Allows joining of a voice channel
const CONNECT = 1 << 20; const CONNECT = 1 << 20;
/// Allows speaking in a voice channel
const SPEAK = 1 << 21; const SPEAK = 1 << 21;
/// Allows muting members in a voice channel
const MUTE_MEMBERS = 1 << 22; const MUTE_MEMBERS = 1 << 22;
/// Allows deafening of members in a voice channel
const DEAFEN_MEMBERS = 1 << 23; const DEAFEN_MEMBERS = 1 << 23;
/// Allows moving of members between voice channels
const MOVE_MEMBERS = 1 << 24; const MOVE_MEMBERS = 1 << 24;
/// Allows using voice activity (VAD = voice-activity-detection) in a voice channel
const USE_VAD = 1 << 25; const USE_VAD = 1 << 25;
/// Allows modification of own nickname
const CHANGE_NICKNAME = 1 << 26; const CHANGE_NICKNAME = 1 << 26;
/// Allows modification of other users' nicknames
const MANAGE_NICKNAMES = 1 << 27; const MANAGE_NICKNAMES = 1 << 27;
/// Allows management and editing of roles
const MANAGE_ROLES = 1 << 28; const MANAGE_ROLES = 1 << 28;
/// Allows management and editing of webhooks
const MANAGE_WEBHOOKS = 1 << 29; const MANAGE_WEBHOOKS = 1 << 29;
/// Allows management and editing of emojis, stickers, and soundboard sounds
const MANAGE_GUILD_EXPRESSIONS = 1 << 30; 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; 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; const REQUEST_TO_SPEAK = 1 << 32;
/// Allows creating, editing, and deleting scheduled events
const MANAGE_EVENTS = 1 << 33; const MANAGE_EVENTS = 1 << 33;
/// Allows deleting and archiving threads, and viewing all private threads
const MANAGE_THREADS = 1 << 34; const MANAGE_THREADS = 1 << 34;
/// Allows creating public and announcement threads
const CREATE_PUBLIC_THREADS = 1 << 35; const CREATE_PUBLIC_THREADS = 1 << 35;
/// Allows creating private threads
const CREATE_PRIVATE_THREADS = 1 << 36; const CREATE_PRIVATE_THREADS = 1 << 36;
/// Allows the usage of custom stickers from other servers
const USE_EXTERNAL_STICKERS = 1 << 37; const USE_EXTERNAL_STICKERS = 1 << 37;
/// Allows sending messages in threads
const SEND_MESSAGES_IN_THREADS = 1 << 38; const SEND_MESSAGES_IN_THREADS = 1 << 38;
/// Allows using Activities in a voice channel
const USE_EMBEDDED_ACTIVITIES = 1 << 39; 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; const MODERATE_MEMBERS = 1 << 40;
/// Allows viewing role subscription insights
const VIEW_CREATOR_MONETIZATION_ANALYTICS = 1 << 41; const VIEW_CREATOR_MONETIZATION_ANALYTICS = 1 << 41;
/// Allows using the soundboard in a voice channel
const USE_SOUNDBOARD = 1 << 42; const USE_SOUNDBOARD = 1 << 42;
/// Allows using custom soundboard sounds from other servers
const USE_EXTERNAL_SOUNDS = 1 << 45; const USE_EXTERNAL_SOUNDS = 1 << 45;
/// Allows sending voice messages
const SEND_VOICE_MESSAGES = 1 << 46; const SEND_VOICE_MESSAGES = 1 << 46;
} }
} }
impl PermissionFlags { 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 { pub fn has_permission(&self, permission: PermissionFlags) -> bool {
self.contains(permission) || self.contains(PermissionFlags::ADMINISTRATOR) self.contains(permission) || self.contains(PermissionFlags::ADMINISTRATOR)
} }
@ -114,6 +167,7 @@ impl PermissionFlags {
} }
/// Creates a String of Permissions from a given [`Vec`] of [`PermissionFlags`]. /// Creates a String of Permissions from a given [`Vec`] of [`PermissionFlags`].
///
/// # Example: /// # Example:
/// ``` /// ```
/// use chorus::types::{PermissionFlags}; /// use chorus::types::{PermissionFlags};

View File

@ -4,12 +4,12 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::types::Snowflake; use crate::types::Snowflake;
#[derive(Serialize, Deserialize, Debug, Default, Clone)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
/// See https://discord.com/developers/docs/resources/stage-instance /// See <https://discord.com/developers/docs/resources/stage-instance>
pub struct StageInstance { pub struct StageInstance {
pub id: Snowflake, pub id: Snowflake,
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub channel_id: Snowflake, pub channel_id: Snowflake,
/// 1 - 120 chars /// 1 - 120 characters
pub topic: String, pub topic: String,
pub privacy_level: StageInstancePrivacyLevel, pub privacy_level: StageInstancePrivacyLevel,
/// deprecated, apparently /// deprecated, apparently
@ -20,7 +20,7 @@ pub struct StageInstance {
#[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)] #[derive(Serialize_repr, Deserialize_repr, Debug, Clone, Default)]
#[repr(u8)] #[repr(u8)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")] #[serde(rename_all = "SCREAMING_SNAKE_CASE")]
/// See https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level /// See <https://discord.com/developers/docs/resources/stage-instance#stage-instance-object-privacy-level>
pub enum StageInstancePrivacyLevel { pub enum StageInstancePrivacyLevel {
/// deprecated, apparently /// deprecated, apparently
Public = 1, Public = 1,

View File

@ -1,9 +1,15 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{entities::User, utils::Snowflake}; 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))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
/// Represents a sticker that can be sent in messages.
///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/sticker#sticker-object>
pub struct Sticker { pub struct Sticker {
#[serde(default)] #[serde(default)]
pub id: Snowflake, pub id: Snowflake,
@ -18,11 +24,17 @@ pub struct Sticker {
pub available: Option<bool>, pub available: Option<bool>,
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub user: Option<User>, pub user: Option<Arc<Mutex<User>>>,
pub sort_value: Option<u8>, pub sort_value: Option<u8>,
} }
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
/// A partial sticker object.
///
/// Represents the smallest amount of data required to render a sticker.
///
/// # Reference
/// See <https://discord-userdoccers.vercel.app/resources/sticker#sticker-item-object>
pub struct StickerItem { pub struct StickerItem {
pub id: Snowflake, pub id: Snowflake,
pub name: String, pub name: String,

View File

@ -1,9 +1,11 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::entities::User; use crate::types::entities::User;
use crate::types::Snowflake; use crate::types::Snowflake;
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Team { pub struct Team {
pub icon: Option<String>, pub icon: Option<String>,
@ -14,10 +16,10 @@ pub struct Team {
pub owner_user_id: Snowflake, pub owner_user_id: Snowflake,
} }
#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct TeamMember { pub struct TeamMember {
pub membership_state: u8, pub membership_state: u8,
pub permissions: Vec<String>, pub permissions: Vec<String>,
pub team_id: Snowflake, pub team_id: Snowflake,
pub user: User, pub user: Arc<Mutex<User>>,
} }

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -6,8 +8,8 @@ use crate::types::{
utils::Snowflake, utils::Snowflake,
}; };
/// See https://docs.spacebar.chat/routes/#cmp--schemas-template /// See <https://docs.spacebar.chat/routes/#cmp--schemas-template>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct GuildTemplate { pub struct GuildTemplate {
pub code: String, pub code: String,
@ -16,13 +18,13 @@ pub struct GuildTemplate {
pub usage_count: Option<u64>, pub usage_count: Option<u64>,
pub creator_id: Snowflake, pub creator_id: Snowflake,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub creator: User, pub creator: Arc<Mutex<User>>,
pub created_at: DateTime<Utc>, pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>, pub updated_at: DateTime<Utc>,
pub source_guild_id: Snowflake, pub source_guild_id: Snowflake,
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub source_guild: Vec<Guild>, pub source_guild: Vec<Arc<Mutex<Guild>>>,
// Unsure how a {recursive: Guild} looks like, might be a Vec? // Unsure how a {recursive: Guild} looks like, might be a Vec?
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub serialized_source_guild: Vec<Guild>, pub serialized_source_guild: Vec<Arc<Mutex<Guild>>>,
} }

View File

@ -91,7 +91,7 @@ impl From<User> for PublicUser {
const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32; const CUSTOM_USER_FLAG_OFFSET: u64 = 1 << 32;
bitflags::bitflags! { 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))] #[cfg_attr(feature = "sqlx", derive(sqlx::Type))]
pub struct UserFlags: u64 { pub struct UserFlags: u64 {
const DISCORD_EMPLOYEE = 1 << 0; const DISCORD_EMPLOYEE = 1 << 0;

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{serde::ts_milliseconds_option, Utc}; use chrono::{serde::ts_milliseconds_option, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -28,7 +30,7 @@ pub enum UserTheme {
Light, Light,
} }
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct UserSettings { pub struct UserSettings {
pub afk_timeout: u16, pub afk_timeout: u16,
@ -73,7 +75,7 @@ pub struct UserSettings {
#[cfg(not(feature = "sqlx"))] #[cfg(not(feature = "sqlx"))]
pub restricted_guilds: Vec<String>, pub restricted_guilds: Vec<String>,
pub show_current_game: bool, pub show_current_game: bool,
pub status: UserStatus, pub status: Arc<Mutex<UserStatus>>,
pub stream_notifications_enabled: bool, pub stream_notifications_enabled: bool,
pub theme: UserTheme, pub theme: UserTheme,
pub timezone_offset: i16, pub timezone_offset: i16,
@ -109,7 +111,7 @@ impl Default for UserSettings {
render_reactions: true, render_reactions: true,
restricted_guilds: Default::default(), restricted_guilds: Default::default(),
show_current_game: true, show_current_game: true,
status: UserStatus::Online, status: Arc::new(Mutex::new(UserStatus::Online)),
stream_notifications_enabled: false, stream_notifications_enabled: false,
theme: UserTheme::Dark, theme: UserTheme::Dark,
timezone_offset: 0, 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 struct GuildFolder {
pub color: u32, pub color: u32,
pub guild_ids: Vec<String>, pub guild_ids: Vec<String>,
@ -149,5 +151,5 @@ pub struct GuildFolder {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct LoginResult { pub struct LoginResult {
pub token: String, pub token: String,
pub settings: UserSettings, pub settings: Arc<Mutex<UserSettings>>,
} }

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -6,15 +8,15 @@ use crate::types::{
utils::Snowflake, utils::Snowflake,
}; };
/// See https://docs.spacebar.chat/routes/#cmp--schemas-voicestate /// See <https://docs.spacebar.chat/routes/#cmp--schemas-voicestate>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct VoiceState { pub struct VoiceState {
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
pub guild: Option<Guild>, pub guild: Option<Guild>,
pub channel_id: Option<Snowflake>, pub channel_id: Option<Snowflake>,
pub user_id: Snowflake, pub user_id: Snowflake,
pub member: Option<GuildMember>, pub member: Option<Arc<Mutex<GuildMember>>>,
pub session_id: Snowflake, pub session_id: Snowflake,
pub token: Option<String>, pub token: Option<String>,
pub deaf: bool, pub deaf: bool,

View File

@ -1,3 +1,5 @@
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::{ use crate::types::{
@ -5,8 +7,8 @@ use crate::types::{
utils::Snowflake, utils::Snowflake,
}; };
/// See https://docs.spacebar.chat/routes/#cmp--schemas-webhook /// See <https://docs.spacebar.chat/routes/#cmp--schemas-webhook>
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Webhook { pub struct Webhook {
pub id: Snowflake, pub id: Snowflake,
@ -20,10 +22,10 @@ pub struct Webhook {
pub application_id: Snowflake, pub application_id: Snowflake,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub user: Option<User>, pub user: Option<Arc<Mutex<User>>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
#[cfg_attr(feature = "sqlx", sqlx(skip))] #[cfg_attr(feature = "sqlx", sqlx(skip))]
pub source_guild: Option<Guild>, pub source_guild: Option<Arc<Mutex<Guild>>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>, pub url: Option<String>,
} }

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{GuildApplicationCommandPermissions, WebSocketEvent}; use crate::types::{GuildApplicationCommandPermissions, WebSocketEvent};
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#application-command-permissions-update /// See <https://discord.com/developers/docs/topics/gateway-events#application-command-permissions-update>
pub struct ApplicationCommandPermissionsUpdate { pub struct ApplicationCommandPermissionsUpdate {
#[serde(flatten)] #[serde(flatten)]
pub permissions: GuildApplicationCommandPermissions, pub permissions: GuildApplicationCommandPermissions,

View File

@ -6,7 +6,7 @@ use crate::types::{
}; };
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-create /// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-create>
pub struct AutoModerationRuleCreate { pub struct AutoModerationRuleCreate {
#[serde(flatten)] #[serde(flatten)]
pub rule: AutoModerationRule, pub rule: AutoModerationRule,
@ -15,7 +15,7 @@ pub struct AutoModerationRuleCreate {
impl WebSocketEvent for AutoModerationRuleCreate {} impl WebSocketEvent for AutoModerationRuleCreate {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update /// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-update>
pub struct AutoModerationRuleUpdate { pub struct AutoModerationRuleUpdate {
#[serde(flatten)] #[serde(flatten)]
pub rule: AutoModerationRule, pub rule: AutoModerationRule,
@ -24,7 +24,7 @@ pub struct AutoModerationRuleUpdate {
impl WebSocketEvent for AutoModerationRuleUpdate {} impl WebSocketEvent for AutoModerationRuleUpdate {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-delete /// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-rule-delete>
pub struct AutoModerationRuleDelete { pub struct AutoModerationRuleDelete {
#[serde(flatten)] #[serde(flatten)]
pub rule: AutoModerationRule, pub rule: AutoModerationRule,
@ -33,7 +33,7 @@ pub struct AutoModerationRuleDelete {
impl WebSocketEvent for AutoModerationRuleDelete {} impl WebSocketEvent for AutoModerationRuleDelete {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#auto-moderation-action-execution /// See <https://discord.com/developers/docs/topics/gateway-events#auto-moderation-action-execution>
pub struct AutoModerationActionExecution { pub struct AutoModerationActionExecution {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub action: AutoModerationAction, pub action: AutoModerationAction,

View File

@ -50,7 +50,7 @@ impl WebSocketEvent for CallDelete {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// Officially Undocumented; /// Officially Undocumented;
/// See https://unofficial-discord-docs.vercel.app/gateway/op13; /// See <https://unofficial-discord-docs.vercel.app/gateway/op13>;
/// ///
/// Ex: {"op":13,"d":{"channel_id":"837609115475771392"}} /// Ex: {"op":13,"d":{"channel_id":"837609115475771392"}}
pub struct CallSync { pub struct CallSync {

View File

@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
use super::UpdateMessage; use super::UpdateMessage;
#[derive(Debug, Default, Deserialize, Serialize)] #[derive(Debug, Default, Deserialize, Serialize)]
/// See https://discord.com/developers/docs/topics/gateway-events#channel-pins-update /// See <https://discord.com/developers/docs/topics/gateway-events#channel-pins-update>
pub struct ChannelPinsUpdate { pub struct ChannelPinsUpdate {
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
pub channel_id: Snowflake, pub channel_id: Snowflake,
@ -16,7 +16,7 @@ pub struct ChannelPinsUpdate {
impl WebSocketEvent for ChannelPinsUpdate {} impl WebSocketEvent for ChannelPinsUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#channel-create /// See <https://discord.com/developers/docs/topics/gateway-events#channel-create>
pub struct ChannelCreate { pub struct ChannelCreate {
#[serde(flatten)] #[serde(flatten)]
pub channel: Channel, pub channel: Channel,
@ -25,7 +25,7 @@ pub struct ChannelCreate {
impl WebSocketEvent for ChannelCreate {} impl WebSocketEvent for ChannelCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#channel-update /// See <https://discord.com/developers/docs/topics/gateway-events#channel-update>
pub struct ChannelUpdate { pub struct ChannelUpdate {
#[serde(flatten)] #[serde(flatten)]
pub channel: Channel, pub channel: Channel,
@ -53,7 +53,7 @@ pub struct ChannelUnreadUpdate {
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// Contains very few fields from [Channel] /// Contains very few fields from [Channel]
/// See also [ChannelUnreadUpdates] /// See also [ChannelUnreadUpdate]
pub struct ChannelUnreadUpdateObject { pub struct ChannelUnreadUpdateObject {
pub id: Snowflake, pub id: Snowflake,
pub last_message_id: Snowflake, pub last_message_id: Snowflake,
@ -63,7 +63,7 @@ pub struct ChannelUnreadUpdateObject {
impl WebSocketEvent for ChannelUnreadUpdate {} impl WebSocketEvent for ChannelUnreadUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#channel-delete /// See <https://discord.com/developers/docs/topics/gateway-events#channel-delete>
pub struct ChannelDelete { pub struct ChannelDelete {
#[serde(flatten)] #[serde(flatten)]
pub channel: Channel, pub channel: Channel,

View File

@ -10,7 +10,7 @@ use crate::types::{
use super::PresenceUpdate; use super::PresenceUpdate;
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-create; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-create>;
/// Received to give data about a guild; /// 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 // This one is particularly painful, it can be a Guild object with an extra field or an unavailable guild object
pub struct GuildCreate { pub struct GuildCreate {
@ -34,7 +34,7 @@ impl Default for GuildCreateDataOption {
impl WebSocketEvent for GuildCreate {} impl WebSocketEvent for GuildCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-ban-add-guild-ban-add-event-fields; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-ban-add-guild-ban-add-event-fields>;
/// Received to give info about a user being banned from a guild; /// Received to give info about a user being banned from a guild;
pub struct GuildBanAdd { pub struct GuildBanAdd {
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -44,7 +44,7 @@ pub struct GuildBanAdd {
impl WebSocketEvent for GuildBanAdd {} impl WebSocketEvent for GuildBanAdd {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-ban-remove; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-ban-remove>;
/// Received to give info about a user being unbanned from a guild; /// Received to give info about a user being unbanned from a guild;
pub struct GuildBanRemove { pub struct GuildBanRemove {
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -54,7 +54,7 @@ pub struct GuildBanRemove {
impl WebSocketEvent for GuildBanRemove {} impl WebSocketEvent for GuildBanRemove {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-update; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-update>;
/// Received to give info about a guild being updated; /// Received to give info about a guild being updated;
pub struct GuildUpdate { pub struct GuildUpdate {
#[serde(flatten)] #[serde(flatten)]
@ -64,7 +64,7 @@ pub struct GuildUpdate {
impl WebSocketEvent for GuildUpdate {} impl WebSocketEvent for GuildUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-delete; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-delete>;
/// Received to tell the client about a guild being deleted; /// Received to tell the client about a guild being deleted;
pub struct GuildDelete { pub struct GuildDelete {
#[serde(flatten)] #[serde(flatten)]
@ -74,7 +74,7 @@ pub struct GuildDelete {
impl WebSocketEvent for GuildDelete {} impl WebSocketEvent for GuildDelete {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-audit-log-entry-create; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-audit-log-entry-create>;
/// Received to the client about an audit log entry being added; /// Received to the client about an audit log entry being added;
pub struct GuildAuditLogEntryCreate { pub struct GuildAuditLogEntryCreate {
#[serde(flatten)] #[serde(flatten)]
@ -84,7 +84,7 @@ pub struct GuildAuditLogEntryCreate {
impl WebSocketEvent for GuildAuditLogEntryCreate {} impl WebSocketEvent for GuildAuditLogEntryCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-emojis-update; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-emojis-update>;
/// Received to tell the client about a change to a guild's emoji list; /// Received to tell the client about a change to a guild's emoji list;
pub struct GuildEmojisUpdate { pub struct GuildEmojisUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -94,7 +94,7 @@ pub struct GuildEmojisUpdate {
impl WebSocketEvent for GuildEmojisUpdate {} impl WebSocketEvent for GuildEmojisUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-stickers-update; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-stickers-update>;
/// Received to tell the client about a change to a guild's sticker list; /// Received to tell the client about a change to a guild's sticker list;
pub struct GuildStickersUpdate { pub struct GuildStickersUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -104,7 +104,7 @@ pub struct GuildStickersUpdate {
impl WebSocketEvent for GuildStickersUpdate {} impl WebSocketEvent for GuildStickersUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-integrations-update /// See <https://discord.com/developers/docs/topics/gateway-events#guild-integrations-update>
pub struct GuildIntegrationsUpdate { pub struct GuildIntegrationsUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
} }
@ -112,7 +112,7 @@ pub struct GuildIntegrationsUpdate {
impl WebSocketEvent for GuildIntegrationsUpdate {} impl WebSocketEvent for GuildIntegrationsUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-member-add; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-member-add>;
/// Received to tell the client about a user joining a guild; /// Received to tell the client about a user joining a guild;
pub struct GuildMemberAdd { pub struct GuildMemberAdd {
#[serde(flatten)] #[serde(flatten)]
@ -123,7 +123,7 @@ pub struct GuildMemberAdd {
impl WebSocketEvent for GuildMemberAdd {} impl WebSocketEvent for GuildMemberAdd {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-member-remove; /// See <https://discord.com/developers/docs/topics/gateway-events#guild-member-remove>;
/// Received to tell the client about a user leaving a guild; /// Received to tell the client about a user leaving a guild;
pub struct GuildMemberRemove { pub struct GuildMemberRemove {
pub guild_id: Snowflake, pub guild_id: Snowflake,
@ -133,7 +133,7 @@ pub struct GuildMemberRemove {
impl WebSocketEvent for GuildMemberRemove {} impl WebSocketEvent for GuildMemberRemove {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-member-update /// See <https://discord.com/developers/docs/topics/gateway-events#guild-member-update>
pub struct GuildMemberUpdate { pub struct GuildMemberUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub roles: Vec<Snowflake>, pub roles: Vec<Snowflake>,
@ -151,7 +151,7 @@ pub struct GuildMemberUpdate {
impl WebSocketEvent for GuildMemberUpdate {} impl WebSocketEvent for GuildMemberUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-members-chunk /// See <https://discord.com/developers/docs/topics/gateway-events#guild-members-chunk>
pub struct GuildMembersChunk { pub struct GuildMembersChunk {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub members: Vec<GuildMember>, pub members: Vec<GuildMember>,
@ -165,7 +165,7 @@ pub struct GuildMembersChunk {
impl WebSocketEvent for GuildMembersChunk {} impl WebSocketEvent for GuildMembersChunk {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-role-create /// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-create>
pub struct GuildRoleCreate { pub struct GuildRoleCreate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub role: RoleObject, pub role: RoleObject,
@ -174,7 +174,7 @@ pub struct GuildRoleCreate {
impl WebSocketEvent for GuildRoleCreate {} impl WebSocketEvent for GuildRoleCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-role-update /// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-update>
pub struct GuildRoleUpdate { pub struct GuildRoleUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub role: RoleObject, pub role: RoleObject,
@ -183,7 +183,7 @@ pub struct GuildRoleUpdate {
impl WebSocketEvent for GuildRoleUpdate {} impl WebSocketEvent for GuildRoleUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-role-delete /// See <https://discord.com/developers/docs/topics/gateway-events#guild-role-delete>
pub struct GuildRoleDelete { pub struct GuildRoleDelete {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub role_id: Snowflake, pub role_id: Snowflake,
@ -192,7 +192,7 @@ pub struct GuildRoleDelete {
impl WebSocketEvent for GuildRoleDelete {} impl WebSocketEvent for GuildRoleDelete {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-create /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-create>
pub struct GuildScheduledEventCreate { pub struct GuildScheduledEventCreate {
#[serde(flatten)] #[serde(flatten)]
pub event: GuildScheduledEvent, pub event: GuildScheduledEvent,
@ -201,7 +201,7 @@ pub struct GuildScheduledEventCreate {
impl WebSocketEvent for GuildScheduledEventCreate {} impl WebSocketEvent for GuildScheduledEventCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-update /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-update>
pub struct GuildScheduledEventUpdate { pub struct GuildScheduledEventUpdate {
#[serde(flatten)] #[serde(flatten)]
pub event: GuildScheduledEvent, pub event: GuildScheduledEvent,
@ -210,7 +210,7 @@ pub struct GuildScheduledEventUpdate {
impl WebSocketEvent for GuildScheduledEventUpdate {} impl WebSocketEvent for GuildScheduledEventUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-delete /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-delete>
pub struct GuildScheduledEventDelete { pub struct GuildScheduledEventDelete {
#[serde(flatten)] #[serde(flatten)]
pub event: GuildScheduledEvent, pub event: GuildScheduledEvent,
@ -219,7 +219,7 @@ pub struct GuildScheduledEventDelete {
impl WebSocketEvent for GuildScheduledEventDelete {} impl WebSocketEvent for GuildScheduledEventDelete {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-add /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-add>
pub struct GuildScheduledEventUserAdd { pub struct GuildScheduledEventUserAdd {
pub guild_scheduled_event_id: Snowflake, pub guild_scheduled_event_id: Snowflake,
pub user_id: Snowflake, pub user_id: Snowflake,
@ -229,7 +229,7 @@ pub struct GuildScheduledEventUserAdd {
impl WebSocketEvent for GuildScheduledEventUserAdd {} impl WebSocketEvent for GuildScheduledEventUserAdd {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-remove /// See <https://discord.com/developers/docs/topics/gateway-events#guild-scheduled-event-user-remove>
pub struct GuildScheduledEventUserRemove { pub struct GuildScheduledEventUserRemove {
pub guild_scheduled_event_id: Snowflake, pub guild_scheduled_event_id: Snowflake,
pub user_id: Snowflake, pub user_id: Snowflake,

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{Integration, Snowflake, WebSocketEvent}; use crate::types::{Integration, Snowflake, WebSocketEvent};
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#integration-create /// See <https://discord.com/developers/docs/topics/gateway-events#integration-create>
pub struct IntegrationCreate { pub struct IntegrationCreate {
#[serde(flatten)] #[serde(flatten)]
pub integration: Integration, pub integration: Integration,
@ -13,7 +13,7 @@ pub struct IntegrationCreate {
impl WebSocketEvent for IntegrationCreate {} impl WebSocketEvent for IntegrationCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#integration-update /// See <https://discord.com/developers/docs/topics/gateway-events#integration-update>
pub struct IntegrationUpdate { pub struct IntegrationUpdate {
#[serde(flatten)] #[serde(flatten)]
pub integration: Integration, pub integration: Integration,
@ -23,7 +23,7 @@ pub struct IntegrationUpdate {
impl WebSocketEvent for IntegrationUpdate {} impl WebSocketEvent for IntegrationUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#integration-delete /// See <https://discord.com/developers/docs/topics/gateway-events#integration-delete>
pub struct IntegrationDelete { pub struct IntegrationDelete {
pub id: Snowflake, pub id: Snowflake,
pub guild_id: Snowflake, pub guild_id: Snowflake,

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{Interaction, WebSocketEvent}; use crate::types::{Interaction, WebSocketEvent};
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#interaction-create /// See <https://discord.com/developers/docs/topics/gateway-events#interaction-create>
pub struct InteractionCreate { pub struct InteractionCreate {
#[serde(flatten)] #[serde(flatten)]
pub interaction: Interaction, pub interaction: Interaction,

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{GuildInvite, Snowflake, WebSocketEvent}; use crate::types::{GuildInvite, Snowflake, WebSocketEvent};
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#invite-create /// See <https://discord.com/developers/docs/topics/gateway-events#invite-create>
pub struct InviteCreate { pub struct InviteCreate {
#[serde(flatten)] #[serde(flatten)]
pub invite: GuildInvite, pub invite: GuildInvite,
@ -12,7 +12,7 @@ pub struct InviteCreate {
impl WebSocketEvent for InviteCreate {} impl WebSocketEvent for InviteCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#invite-delete /// See <https://discord.com/developers/docs/topics/gateway-events#invite-delete>
pub struct InviteDelete { pub struct InviteDelete {
pub channel_id: Snowflake, pub channel_id: Snowflake,
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,

View File

@ -13,7 +13,7 @@ use super::WebSocketEvent;
/// Sent by the official client when switching to a guild or channel; /// Sent by the official client when switching to a guild or channel;
/// After this, you should recieve message updates /// After this, you should recieve message updates
/// ///
/// See https://luna.gitlab.io/discord-unofficial-docs/lazy_guilds.html#op-14-lazy-request /// See <https://luna.gitlab.io/discord-unofficial-docs/lazy_guilds.html#op-14-lazy-request>
/// ///
/// {"op":14,"d":{"guild_id":"848582562217590824","typing":true,"activities":true,"threads":true}} /// {"op":14,"d":{"guild_id":"848582562217590824","typing":true,"activities":true,"threads":true}}
pub struct LazyRequest { pub struct LazyRequest {

View File

@ -8,6 +8,8 @@ use crate::types::{
use super::WebSocketEvent; use super::WebSocketEvent;
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#typing-start>
pub struct TypingStartEvent { pub struct TypingStartEvent {
pub channel_id: Snowflake, pub channel_id: Snowflake,
pub guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
@ -19,92 +21,106 @@ pub struct TypingStartEvent {
impl WebSocketEvent for TypingStartEvent {} impl WebSocketEvent for TypingStartEvent {}
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#message-create /// See <https://discord.com/developers/docs/topics/gateway-events#message-create>
pub struct MessageCreate { pub struct MessageCreate {
#[serde(flatten)] #[serde(flatten)]
message: Message, pub message: Message,
guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
member: Option<GuildMember>, pub member: Option<GuildMember>,
mentions: Option<Vec<MessageCreateUser>>, pub mentions: Option<Vec<MessageCreateUser>>,
} }
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#message-create-message-create-extra-fields /// See <https://discord.com/developers/docs/topics/gateway-events#message-create-message-create-extra-fields>
pub struct MessageCreateUser { pub struct MessageCreateUser {
#[serde(flatten)] #[serde(flatten)]
user: PublicUser, pub user: PublicUser,
member: Option<GuildMember>, pub member: Option<GuildMember>,
} }
impl WebSocketEvent for MessageCreate {} impl WebSocketEvent for MessageCreate {}
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
/// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-update>
pub struct MessageUpdate { pub struct MessageUpdate {
#[serde(flatten)] #[serde(flatten)]
message: Message, pub message: Message,
guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
member: Option<GuildMember>, pub member: Option<GuildMember>,
mentions: Option<Vec<MessageCreateUser>>, pub mentions: Option<Vec<MessageCreateUser>>,
} }
impl WebSocketEvent for MessageUpdate {} impl WebSocketEvent for MessageUpdate {}
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
/// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-delete>
pub struct MessageDelete { pub struct MessageDelete {
id: Snowflake, pub id: Snowflake,
channel_id: Snowflake, pub channel_id: Snowflake,
guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
} }
impl WebSocketEvent for MessageDelete {} impl WebSocketEvent for MessageDelete {}
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
/// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-delete-bulk>
pub struct MessageDeleteBulk { pub struct MessageDeleteBulk {
ids: Vec<Snowflake>, pub ids: Vec<Snowflake>,
channel_id: Snowflake, pub channel_id: Snowflake,
guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
} }
impl WebSocketEvent for MessageDeleteBulk {} impl WebSocketEvent for MessageDeleteBulk {}
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
/// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-reaction-add>
pub struct MessageReactionAdd { pub struct MessageReactionAdd {
user_id: Snowflake, pub user_id: Snowflake,
channel_id: Snowflake, pub channel_id: Snowflake,
message_id: Snowflake, pub message_id: Snowflake,
guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
member: Option<GuildMember>, pub member: Option<GuildMember>,
emoji: Emoji, pub emoji: Emoji,
} }
impl WebSocketEvent for MessageReactionAdd {} impl WebSocketEvent for MessageReactionAdd {}
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
/// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove>
pub struct MessageReactionRemove { pub struct MessageReactionRemove {
user_id: Snowflake, pub user_id: Snowflake,
channel_id: Snowflake, pub channel_id: Snowflake,
message_id: Snowflake, pub message_id: Snowflake,
guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
emoji: Emoji, pub emoji: Emoji,
} }
impl WebSocketEvent for MessageReactionRemove {} impl WebSocketEvent for MessageReactionRemove {}
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
/// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-all>
pub struct MessageReactionRemoveAll { pub struct MessageReactionRemoveAll {
channel_id: Snowflake, pub channel_id: Snowflake,
message_id: Snowflake, pub message_id: Snowflake,
guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
} }
impl WebSocketEvent for MessageReactionRemoveAll {} impl WebSocketEvent for MessageReactionRemoveAll {}
#[derive(Debug, Serialize, Deserialize, Default, Clone)] #[derive(Debug, Serialize, Deserialize, Default, Clone)]
/// # Reference
/// See <https://discord.com/developers/docs/topics/gateway-events#message-reaction-remove-emoji>
pub struct MessageReactionRemoveEmoji { pub struct MessageReactionRemoveEmoji {
channel_id: Snowflake, pub channel_id: Snowflake,
message_id: Snowflake, pub message_id: Snowflake,
guild_id: Option<Snowflake>, pub guild_id: Option<Snowflake>,
emoji: Emoji, pub emoji: Emoji,
} }
impl WebSocketEvent for MessageReactionRemoveEmoji {} impl WebSocketEvent for MessageReactionRemoveEmoji {}
@ -114,7 +130,7 @@ impl WebSocketEvent for MessageReactionRemoveEmoji {}
/// ///
/// Not documented anywhere unofficially /// 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." (<https://github.com/Rapptz/discord.py/issues/1851>)
/// I suspect this is sent and recieved from the gateway to let clients on other devices know the user has read a message /// 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"}} /// {"t":"MESSAGE_ACK","s":3,"op":0,"d":{"version":52,"message_id":"1107236673638633472","last_viewed":null,"flags":null,"channel_id":"967363950217936897"}}

View File

@ -61,7 +61,7 @@ pub trait WebSocketEvent {}
#[derive(Debug, Default, Serialize, Clone)] #[derive(Debug, Default, Serialize, Clone)]
/// The payload used for sending events to the gateway /// 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 /// Also, we never need to send the event name
pub struct GatewaySendPayload { pub struct GatewaySendPayload {
#[serde(rename = "op")] #[serde(rename = "op")]
@ -80,9 +80,6 @@ impl WebSocketEvent for GatewaySendPayload {}
#[derive(Debug, Default, Deserialize, Clone)] #[derive(Debug, Default, Deserialize, Clone)]
/// The payload used for receiving events from the gateway /// 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> { pub struct GatewayReceivePayload<'a> {
#[serde(rename = "op")] #[serde(rename = "op")]
pub op_code: u8, pub op_code: u8,

View File

@ -4,9 +4,9 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// Sent by the client to update its status and presence; /// Sent by the client to update its status and presence;
/// See https://discord.com/developers/docs/topics/gateway-events#update-presence /// See <https://discord.com/developers/docs/topics/gateway-events#update-presence>
pub struct UpdatePresence { 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<u128>, pub since: Option<u128>,
/// the client's status (online, invisible, offline, dnd, idle..) /// the client's status (online, invisible, offline, dnd, idle..)
pub status: UserStatus, pub status: UserStatus,
@ -16,7 +16,7 @@ pub struct UpdatePresence {
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// Received to tell the client that a user updated their presence / status /// 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 <https://discord.com/developers/docs/topics/gateway-events#presence-update-presence-update-event-fields>
pub struct PresenceUpdate { pub struct PresenceUpdate {
pub user: PublicUser, pub user: PublicUser,
#[serde(default)] #[serde(default)]

View File

@ -8,7 +8,7 @@ use crate::types::{Activity, GuildMember, PresenceUpdate, VoiceState};
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// 1/2 half documented; /// 1/2 half documented;
/// Received after identifying, provides initial user info; /// Received after identifying, provides initial user info;
/// See https://discord.com/developers/docs/topics/gateway-events#ready; /// See <https://discord.com/developers/docs/topics/gateway-events#ready;>
pub struct GatewayReady { pub struct GatewayReady {
pub analytics_token: Option<String>, pub analytics_token: Option<String>,
pub auth_session_id_hash: Option<String>, pub auth_session_id_hash: Option<String>,
@ -16,7 +16,7 @@ pub struct GatewayReady {
pub v: u8, pub v: u8,
pub user: User, 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<Guild>, pub guilds: Vec<Guild>,
pub presences: Option<Vec<PresenceUpdate>>, pub presences: Option<Vec<PresenceUpdate>>,
pub sessions: Option<Vec<Session>>, pub sessions: Option<Vec<Session>>,

View File

@ -2,7 +2,7 @@ use crate::types::{events::WebSocketEvent, Relationship, RelationshipType, Snowf
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Default)] #[derive(Debug, Deserialize, Serialize, Default)]
/// See https://github.com/spacebarchat/server/issues/204 /// See <https://github.com/spacebarchat/server/issues/204>
pub struct RelationshipAdd { pub struct RelationshipAdd {
#[serde(flatten)] #[serde(flatten)]
pub relationship: Relationship, pub relationship: Relationship,
@ -12,7 +12,7 @@ pub struct RelationshipAdd {
impl WebSocketEvent for RelationshipAdd {} impl WebSocketEvent for RelationshipAdd {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://github.com/spacebarchat/server/issues/203 /// See <https://github.com/spacebarchat/server/issues/203>
pub struct RelationshipRemove { pub struct RelationshipRemove {
pub id: Snowflake, pub id: Snowflake,
#[serde(rename = "type")] #[serde(rename = "type")]

View File

@ -2,7 +2,7 @@ use crate::types::{events::WebSocketEvent, Snowflake};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Default)] #[derive(Debug, Deserialize, Serialize, Default)]
/// See https://discord.com/developers/docs/topics/gateway-events#request-guild-members-request-guild-members-structure /// See <https://discord.com/developers/docs/topics/gateway-events#request-guild-members-request-guild-members-structure>
pub struct GatewayRequestGuildMembers { pub struct GatewayRequestGuildMembers {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub query: Option<String>, pub query: Option<String>,

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::types::{StageInstance, WebSocketEvent}; use crate::types::{StageInstance, WebSocketEvent};
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#stage-instance-create /// See <https://discord.com/developers/docs/topics/gateway-events#stage-instance-create>
pub struct StageInstanceCreate { pub struct StageInstanceCreate {
#[serde(flatten)] #[serde(flatten)]
pub stage_instance: StageInstance, pub stage_instance: StageInstance,
@ -12,7 +12,7 @@ pub struct StageInstanceCreate {
impl WebSocketEvent for StageInstanceCreate {} impl WebSocketEvent for StageInstanceCreate {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#stage-instance-update /// See <https://discord.com/developers/docs/topics/gateway-events#stage-instance-update>
pub struct StageInstanceUpdate { pub struct StageInstanceUpdate {
#[serde(flatten)] #[serde(flatten)]
pub stage_instance: StageInstance, pub stage_instance: StageInstance,
@ -21,7 +21,7 @@ pub struct StageInstanceUpdate {
impl WebSocketEvent for StageInstanceUpdate {} impl WebSocketEvent for StageInstanceUpdate {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#stage-instance-delete /// See <https://discord.com/developers/docs/topics/gateway-events#stage-instance-delete>
pub struct StageInstanceDelete { pub struct StageInstanceDelete {
#[serde(flatten)] #[serde(flatten)]
pub stage_instance: StageInstance, pub stage_instance: StageInstance,

View File

@ -5,7 +5,7 @@ use crate::types::events::WebSocketEvent;
use crate::types::Snowflake; use crate::types::Snowflake;
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#thread-create /// See <https://discord.com/developers/docs/topics/gateway-events#thread-create>
pub struct ThreadCreate { pub struct ThreadCreate {
#[serde(flatten)] #[serde(flatten)]
pub thread: Channel, pub thread: Channel,
@ -14,7 +14,7 @@ pub struct ThreadCreate {
impl WebSocketEvent for ThreadCreate {} impl WebSocketEvent for ThreadCreate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#thread-update /// See <https://discord.com/developers/docs/topics/gateway-events#thread-update>
pub struct ThreadUpdate { pub struct ThreadUpdate {
#[serde(flatten)] #[serde(flatten)]
pub thread: Channel, pub thread: Channel,
@ -23,7 +23,7 @@ pub struct ThreadUpdate {
impl WebSocketEvent for ThreadUpdate {} impl WebSocketEvent for ThreadUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#thread-delete /// See <https://discord.com/developers/docs/topics/gateway-events#thread-delete>
pub struct ThreadDelete { pub struct ThreadDelete {
#[serde(flatten)] #[serde(flatten)]
pub thread: Channel, pub thread: Channel,
@ -32,7 +32,7 @@ pub struct ThreadDelete {
impl WebSocketEvent for ThreadDelete {} impl WebSocketEvent for ThreadDelete {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#thread-list-sync /// See <https://discord.com/developers/docs/topics/gateway-events#thread-list-sync>
pub struct ThreadListSync { pub struct ThreadListSync {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub channel_ids: Option<Vec<Snowflake>>, pub channel_ids: Option<Vec<Snowflake>>,
@ -43,7 +43,7 @@ pub struct ThreadListSync {
impl WebSocketEvent for ThreadListSync {} impl WebSocketEvent for ThreadListSync {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#thread-member-update /// See <https://discord.com/developers/docs/topics/gateway-events#thread-member-update>
/// The inner payload is a thread member object with an extra field. /// The inner payload is a thread member object with an extra field.
pub struct ThreadMemberUpdate { pub struct ThreadMemberUpdate {
#[serde(flatten)] #[serde(flatten)]
@ -54,7 +54,7 @@ pub struct ThreadMemberUpdate {
impl WebSocketEvent for ThreadMemberUpdate {} impl WebSocketEvent for ThreadMemberUpdate {}
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#thread-members-update /// See <https://discord.com/developers/docs/topics/gateway-events#thread-members-update>
pub struct ThreadMembersUpdate { pub struct ThreadMembersUpdate {
pub id: Snowflake, pub id: Snowflake,
pub guild_id: Snowflake, pub guild_id: Snowflake,

View File

@ -5,7 +5,7 @@ use crate::types::events::WebSocketEvent;
use crate::types::utils::Snowflake; use crate::types::utils::Snowflake;
#[derive(Debug, Default, Deserialize, Serialize, Clone)] #[derive(Debug, Default, Deserialize, Serialize, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#user-update; /// See <https://discord.com/developers/docs/topics/gateway-events#user-update>;
/// Sent to indicate updates to a user object; (name changes, discriminator changes, etc); /// Sent to indicate updates to a user object; (name changes, discriminator changes, etc);
pub struct UserUpdate { pub struct UserUpdate {
#[serde(flatten)] #[serde(flatten)]

View File

@ -16,7 +16,7 @@ pub struct UpdateVoiceState {
impl WebSocketEvent for UpdateVoiceState {} impl WebSocketEvent for UpdateVoiceState {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#voice-state-update; /// See <https://discord.com/developers/docs/topics/gateway-events#voice-state-update>;
/// ///
/// Received from the server to indicate an update in a user's voice state (leave voice channel, join voice channel, mute, deafen, etc); /// 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 {} impl WebSocketEvent for VoiceStateUpdate {}
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#voice-server-update; /// See <https://discord.com/developers/docs/topics/gateway-events#voice-server-update>;
/// ///
/// Received to indicate which voice endpoint, token and guild_id to use; /// Received to indicate which voice endpoint, token and guild_id to use;
pub struct VoiceServerUpdate { pub struct VoiceServerUpdate {

View File

@ -5,7 +5,7 @@ use crate::types::Snowflake;
use super::WebSocketEvent; use super::WebSocketEvent;
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#webhooks-update /// See <https://discord.com/developers/docs/topics/gateway-events#webhooks-update>
pub struct WebhooksUpdate { pub struct WebhooksUpdate {
pub guild_id: Snowflake, pub guild_id: Snowflake,
pub channel_id: Snowflake, pub channel_id: Snowflake,

View File

@ -1,7 +1,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Default, Clone)] #[derive(Debug, Deserialize, Serialize, Default, Clone)]
/// See https://discord.com/developers/docs/topics/gateway-events#client-status-object /// See <https://discord.com/developers/docs/topics/gateway-events#client-status-object>
pub struct ClientStatusObject { pub struct ClientStatusObject {
pub desktop: Option<String>, pub desktop: Option<String>,
pub mobile: Option<String>, pub mobile: Option<String>,

View File

@ -6,6 +6,7 @@ use crate::types::Snowflake;
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
/// A schema used to modify a user.
pub struct UserModifySchema { pub struct UserModifySchema {
pub username: Option<String>, pub username: Option<String>,
pub avatar: Option<String>, pub avatar: Option<String>,
@ -19,6 +20,8 @@ pub struct UserModifySchema {
pub discriminator: Option<i16>, pub discriminator: Option<i16>,
} }
/// A schema used to create a private channel.
///
/// # Attributes: /// # Attributes:
/// - recipients: The users to include in the private channel /// - 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). /// - 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).

View File

@ -1,8 +1,7 @@
use crate::types::utils::Snowflake;
use jsonwebtoken::{encode, EncodingKey, Header}; use jsonwebtoken::{encode, EncodingKey, Header};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::types::utils::Snowflake;
pub fn generate_token(id: &Snowflake, email: String, jwt_key: &str) -> String { pub fn generate_token(id: &Snowflake, email: String, jwt_key: &str) -> String {
let claims = Claims::new(&email, id); 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)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Claims { pub struct Claims {
/// When the token expires, unix epoch
pub exp: i64, pub exp: i64,
/// When the token was issued
pub iat: i64, pub iat: i64,
pub email: String, pub email: String,
pub id: String, pub id: String,

View File

@ -1,56 +1,124 @@
use bitflags::bitflags; use bitflags::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 <https://docs.spacebar.chat/setup/server/security/rights/>
pub struct Rights: u64 { pub struct Rights: u64 {
/// All rights
const OPERATOR = 1 << 0; const OPERATOR = 1 << 0;
/// Ability to alter or remove others' applications
const MANAGE_APPLICATIONS = 1 << 1; 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; const MANAGE_GUILDS = 1 << 2;
/// Can delete or edit any message they can read
const MANAGE_MESSAGES = 1 << 3; 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; 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; const MANAGE_ROUTING = 1 << 5;
/// Respond to or resolve other users' support tickets
const MANAGE_TICKETS = 1 << 6; 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; const MANAGE_USERS = 1 << 7;
/// Can manually add members into their guilds and group DMs
const ADD_MEMBERS = 1 << 8; const ADD_MEMBERS = 1 << 8;
/// Makes the user exempt from all rate limits
const BYPASS_RATE_LIMITS = 1 << 9; const BYPASS_RATE_LIMITS = 1 << 9;
/// Can create, edit and remove own applications
const CREATE_APPLICATIONS = 1 << 10; const CREATE_APPLICATIONS = 1 << 10;
/// Can create guild channels and custom channels
const CREATE_CHANNELS = 1 << 11; 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; 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; const CREATE_DM_GROUPS = 1 << 13;
/// Can create guilds
const CREATE_GUILDS = 1 << 14; const CREATE_GUILDS = 1 << 14;
/// Can create mass invites in guilds where they have [CREATE_INSTANT_INVITE]
const CREATE_INVITES = 1 << 15; 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; const CREATE_ROLES = 1 << 16;
/// Can create templates for guilds, custom channels and channels with custom routing
const CREATE_TEMPLATES = 1 << 17; const CREATE_TEMPLATES = 1 << 17;
/// Can create webhooks in the guilds that they have permissions
const CREATE_WEBHOOKS = 1 << 18; const CREATE_WEBHOOKS = 1 << 18;
/// Can join guilds by using invites or vanity names
const JOIN_GUILDS = 1 << 19; const JOIN_GUILDS = 1 << 19;
/// Can modify the pinned messages in the guilds that they have permission
const PIN_MESSAGES = 1 << 20; const PIN_MESSAGES = 1 << 20;
/// Can react to messages, subject to permissions
const SELF_ADD_REACTIONS = 1 << 21; const SELF_ADD_REACTIONS = 1 << 21;
/// Can delete own messages
const SELF_DELETE_MESSAGES = 1 << 22; const SELF_DELETE_MESSAGES = 1 << 22;
/// Can edit own messages
const SELF_EDIT_MESSAGES = 1 << 23; const SELF_EDIT_MESSAGES = 1 << 23;
/// Can edit own username, nickname and avatar
const SELF_EDIT_NAME = 1 << 24; const SELF_EDIT_NAME = 1 << 24;
/// Can send messages in the channels that they have permissions
const SEND_MESSAGES = 1 << 25; const SEND_MESSAGES = 1 << 25;
/// Can use voice activities, such as watch together or whiteboard
const USE_ACTIVITIES = 1 << 26; const USE_ACTIVITIES = 1 << 26;
/// Can use video and screenshare in guilds/channels that they have permissions
const USE_VIDEO = 1 << 27; const USE_VIDEO = 1 << 27;
/// Can use voice in guilds/channels that they have permissions
const USE_VOICE = 1 << 28; 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; const INVITE_USERS = 1 << 29;
/// Can delete/disable own account
const SELF_DELETE_DISABLE = 1 << 30; const SELF_DELETE_DISABLE = 1 << 30;
/// Can use pay-to-use features once paid
const DEBTABLE = 1 << 31; 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; 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; 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; 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; const PRESENCE = 1 << 35;
/// Can mark discoverable guilds where they have permissions to mark as discoverable
const SELF_ADD_DISCOVERABLE = 1 << 36; const SELF_ADD_DISCOVERABLE = 1 << 36;
/// Can change anything in the primary guild directory
const MANAGE_GUILD_DIRECTORY = 1 << 37; const MANAGE_GUILD_DIRECTORY = 1 << 37;
/// Can send confetti, screenshake and use the random user mention (@someone)
const POGGERS = 1 << 38; const POGGERS = 1 << 38;
/// Can use achievements and cheers
const USE_ACHIEVEMENTS = 1 << 39; const USE_ACHIEVEMENTS = 1 << 39;
/// Can initiate interactions
const INITIATE_INTERACTIONS = 1 << 40; const INITIATE_INTERACTIONS = 1 << 40;
/// Can respond to interactions
const RESPOND_TO_INTERACTIONS = 1 << 41; const RESPOND_TO_INTERACTIONS = 1 << 41;
/// Can send backdated events
const SEND_BACKDATED_EVENTS = 1 << 42; const SEND_BACKDATED_EVENTS = 1 << 42;
/// Can accept mass (guild) invites
const USE_MASS_INVITES = 1 << 43; const USE_MASS_INVITES = 1 << 43;
/// Can accept user-specific invites and DM requests
const ACCEPT_INVITES = 1 << 44; const ACCEPT_INVITES = 1 << 44;
/// Can modify own flags
const SELF_EDIT_FLAGS = 1 << 45; const SELF_EDIT_FLAGS = 1 << 45;
/// Can modify other's flags
const EDIT_FLAGS = 1 << 46; const EDIT_FLAGS = 1 << 46;
/// Can manage other's groups
const MANAGE_GROUPS = 1 << 47; const MANAGE_GROUPS = 1 << 47;
/// Can view server stats at /api/policies/stats
const VIEW_SERVER_STATS = 1 << 48; const VIEW_SERVER_STATS = 1 << 48;
/// Can resend verification emails using /auth/verify/resend
const RESEND_VERIFICATION_EMAIL = 1 << 49; const RESEND_VERIFICATION_EMAIL = 1 << 49;
} }
} }
@ -60,10 +128,16 @@ impl Rights {
(check_operator && self.contains(Rights::OPERATOR)) || self.contains(permission) (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 { pub fn has(&self, permission: Rights, check_operator: bool) -> bool {
(check_operator && self.contains(Rights::OPERATOR)) || self.contains(permission) (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<bool, &'static str> { pub fn has_throw(&self, permission: Rights) -> Result<bool, &'static str> {
if self.has(permission, true) { if self.has(permission, true) {
Ok(true) Ok(true)

View File

@ -11,13 +11,16 @@ use sqlx::Type;
const EPOCH: i64 = 1420070400000; const EPOCH: i64 = 1420070400000;
/// Unique identifier including a timestamp. /// Unique identifier including a timestamp.
/// See https://discord.com/developers/docs/reference#snowflakes ///
/// # Reference
/// See <https://discord.com/developers/docs/reference#snowflakes>
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "sqlx", derive(Type))] #[cfg_attr(feature = "sqlx", derive(Type))]
#[cfg_attr(feature = "sqlx", sqlx(transparent))] #[cfg_attr(feature = "sqlx", sqlx(transparent))]
pub struct Snowflake(u64); pub struct Snowflake(pub u64);
impl Snowflake { impl Snowflake {
/// Generates a snowflake for the current timestamp, with worker id 0 and process id 1.
pub fn generate() -> Self { pub fn generate() -> Self {
const WORKER_ID: u64 = 0; const WORKER_ID: u64 = 0;
const PROCESS_ID: u64 = 1; const PROCESS_ID: u64 = 1;
@ -31,6 +34,7 @@ impl Snowflake {
Self(time as u64 | worker | process | increment) Self(time as u64 | worker | process | increment)
} }
/// Returns the snowflake's timestamp
pub fn timestamp(self) -> DateTime<Utc> { pub fn timestamp(self) -> DateTime<Utc> {
Utc.timestamp_millis_opt((self.0 >> 22) as i64 + EPOCH) Utc.timestamp_millis_opt((self.0 >> 22) as i64 + EPOCH)
.unwrap() .unwrap()
@ -49,6 +53,15 @@ impl Display for Snowflake {
} }
} }
impl<T> From<T> for Snowflake
where
T: Into<u64>,
{
fn from(item: T) -> Self {
Self(item.into())
}
}
impl serde::Serialize for Snowflake { impl serde::Serialize for Snowflake {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where

View File

@ -1 +1,2 @@
//! Where the voice chat implementation will be, once it's finished.
//! For development on voice, see the feature/voice branch.

View File

@ -59,8 +59,9 @@ async fn modify_channel() {
PermissionFlags::MANAGE_CHANNELS, PermissionFlags::MANAGE_CHANNELS,
PermissionFlags::MANAGE_MESSAGES, PermissionFlags::MANAGE_MESSAGES,
])); ]));
let user_id: types::Snowflake = bundle.user.object.lock().unwrap().id;
let permission_override = PermissionOverwrite { let permission_override = PermissionOverwrite {
id: bundle.user.object.id, id: user_id,
overwrite_type: "1".to_string(), overwrite_type: "1".to_string(),
allow: permission_override, allow: permission_override,
deny: "0".to_string(), deny: "0".to_string(),
@ -143,7 +144,7 @@ async fn create_dm() {
let other_user = bundle.create_user("integrationtestuser2").await; let other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; let user = &mut bundle.user;
let private_channel_create_schema = PrivateChannelCreateSchema { 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, access_tokens: None,
nicks: None, nicks: None,
}; };
@ -153,26 +154,47 @@ async fn create_dm() {
.unwrap(); .unwrap();
assert!(dm_channel.recipients.is_some()); assert!(dm_channel.recipients.is_some());
assert_eq!( assert_eq!(
dm_channel.recipients.as_ref().unwrap().get(0).unwrap().id, dm_channel
other_user.object.id .recipients
.as_ref()
.unwrap()
.get(0)
.unwrap()
.lock()
.unwrap()
.id
.clone(),
other_user.object.lock().unwrap().id
); );
assert_eq!( assert_eq!(
dm_channel.recipients.as_ref().unwrap().get(1).unwrap().id, dm_channel
user.object.id .recipients
.as_ref()
.unwrap()
.get(1)
.unwrap()
.lock()
.unwrap()
.id
.clone(),
user.object.lock().unwrap().id.clone()
); );
common::teardown(bundle).await; common::teardown(bundle).await;
} }
// #[tokio::test] // #[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)] #[allow(dead_code)]
async fn remove_add_person_from_to_dm() { async fn remove_add_person_from_to_dm() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let mut third_user = bundle.create_user("integrationtestuser3").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 user = &mut bundle.user;
let private_channel_create_schema = PrivateChannelCreateSchema { 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, access_tokens: None,
nicks: None, nicks: None,
}; };
@ -181,36 +203,52 @@ async fn remove_add_person_from_to_dm() {
.await .await
.unwrap(); // Creates the Channel and stores the response Channel object .unwrap(); // Creates the Channel and stores the response Channel object
dm_channel dm_channel
.remove_channel_recipient(other_user.object.id, user) .remove_channel_recipient(other_user_id, user)
.await .await
.unwrap(); .unwrap();
assert!(dm_channel.recipients.as_ref().unwrap().get(1).is_none()); assert!(dm_channel.recipients.as_ref().unwrap().get(1).is_none());
other_user other_user
.modify_user_relationship(user.object.id, RelationshipType::Friends) .modify_user_relationship(user_id, RelationshipType::Friends)
.await .await
.unwrap(); .unwrap();
user.modify_user_relationship(other_user.object.id, RelationshipType::Friends) user.modify_user_relationship(other_user_id, RelationshipType::Friends)
.await .await
.unwrap(); .unwrap();
third_user third_user
.modify_user_relationship(user.object.id, RelationshipType::Friends) .modify_user_relationship(user_id, RelationshipType::Friends)
.await .await
.unwrap(); .unwrap();
user.modify_user_relationship(third_user.object.id, RelationshipType::Friends) user.modify_user_relationship(third_user_id, RelationshipType::Friends)
.await .await
.unwrap(); .unwrap();
// Users 1-2 and 1-3 are now friends // Users 1-2 and 1-3 are now friends
dm_channel dm_channel
.add_channel_recipient(other_user.object.id, user, None) .add_channel_recipient(other_user_id, user, None)
.await .await
.unwrap(); .unwrap();
assert!(dm_channel.recipients.is_some()); assert!(dm_channel.recipients.is_some());
assert_eq!( assert_eq!(
dm_channel.recipients.as_ref().unwrap().get(0).unwrap().id, dm_channel
other_user.object.id .recipients
.as_ref()
.unwrap()
.get(0)
.unwrap()
.lock()
.unwrap()
.id,
other_user_id
); );
assert_eq!( assert_eq!(
dm_channel.recipients.as_ref().unwrap().get(1).unwrap().id, dm_channel
user.object.id .recipients
.as_ref()
.unwrap()
.get(1)
.unwrap()
.lock()
.unwrap()
.id,
user_id
); );
} }

View File

@ -11,7 +11,7 @@ async fn create_accept_invite() {
.await .await
.is_err()); .is_err());
let invite = user let invite = user
.create_guild_invite(create_channel_invite_schema, channel.id) .create_channel_invite(create_channel_invite_schema, channel.id)
.await .await
.unwrap(); .unwrap();

View File

@ -7,7 +7,7 @@ async fn add_remove_role() -> ChorusResult<()> {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let guild = bundle.guild.id; let guild = bundle.guild.id;
let role = bundle.role.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?; GuildMember::add_role(&mut bundle.user, guild, member_id, role).await?;
let member = GuildMember::get(&mut bundle.user, guild, member_id) let member = GuildMember::get(&mut bundle.user, guild, member_id)
.await .await

View File

@ -7,15 +7,18 @@ async fn test_get_mutual_relationships() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; 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 { let friend_request_schema = types::FriendRequestSendSchema {
username: user.object.username.clone(), username,
discriminator: Some(user.object.discriminator.clone()), discriminator: Some(discriminator),
}; };
let _ = other_user.send_friend_request(friend_request_schema).await; other_user
let relationships = user .send_friend_request(friend_request_schema)
.get_mutual_relationships(other_user.object.id)
.await .await
.unwrap(); .unwrap();
let relationships = user.get_mutual_relationships(other_user_id).await.unwrap();
println!("{:?}", relationships); println!("{:?}", relationships);
common::teardown(bundle).await common::teardown(bundle).await
} }
@ -25,16 +28,21 @@ async fn test_get_relationships() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; 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 { let friend_request_schema = types::FriendRequestSendSchema {
username: user.object.username.clone(), username,
discriminator: Some(user.object.discriminator.clone()), discriminator: Some(discriminator),
}; };
other_user other_user
.send_friend_request(friend_request_schema) .send_friend_request(friend_request_schema)
.await .await
.unwrap(); .unwrap();
let relationships = user.get_relationships().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 common::teardown(bundle).await
} }
@ -43,23 +51,33 @@ async fn test_modify_relationship_friends() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; let user = &mut bundle.user;
let _ = other_user let user_id: types::Snowflake = user.object.lock().unwrap().id;
.modify_user_relationship(user.object.id, types::RelationshipType::Friends) let other_user_id: types::Snowflake = other_user.object.lock().unwrap().id;
.await;
other_user
.modify_user_relationship(user_id, types::RelationshipType::Friends)
.await
.unwrap();
let relationships = user.get_relationships().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!( assert_eq!(
relationships.get(0).unwrap().relationship_type, relationships.get(0).unwrap().relationship_type,
RelationshipType::Incoming RelationshipType::Incoming
); );
let relationships = other_user.get_relationships().await.unwrap(); 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!( assert_eq!(
relationships.get(0).unwrap().relationship_type, relationships.get(0).unwrap().relationship_type,
RelationshipType::Outgoing RelationshipType::Outgoing
); );
let _ = user let _ = user
.modify_user_relationship(other_user.object.id, RelationshipType::Friends) .modify_user_relationship(other_user_id, RelationshipType::Friends)
.await; .await;
assert_eq!( assert_eq!(
other_user other_user
@ -71,7 +89,7 @@ async fn test_modify_relationship_friends() {
.relationship_type, .relationship_type,
RelationshipType::Friends RelationshipType::Friends
); );
let _ = user.remove_relationship(other_user.object.id).await; let _ = user.remove_relationship(other_user_id).await;
assert_eq!( assert_eq!(
other_user.get_relationships().await.unwrap(), other_user.get_relationships().await.unwrap(),
Vec::<Relationship>::new() Vec::<Relationship>::new()
@ -84,18 +102,24 @@ async fn test_modify_relationship_block() {
let mut bundle = common::setup().await; let mut bundle = common::setup().await;
let mut other_user = bundle.create_user("integrationtestuser2").await; let mut other_user = bundle.create_user("integrationtestuser2").await;
let user = &mut bundle.user; let user = &mut bundle.user;
let _ = other_user let user_id: types::Snowflake = user.object.lock().unwrap().id;
.modify_user_relationship(user.object.id, types::RelationshipType::Blocked)
.await; other_user
.modify_user_relationship(user_id, types::RelationshipType::Blocked)
.await
.unwrap();
let relationships = user.get_relationships().await.unwrap(); let relationships = user.get_relationships().await.unwrap();
assert_eq!(relationships, Vec::<Relationship>::new()); assert_eq!(relationships, Vec::<Relationship>::new());
let relationships = other_user.get_relationships().await.unwrap(); 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!( assert_eq!(
relationships.get(0).unwrap().relationship_type, relationships.get(0).unwrap().relationship_type,
RelationshipType::Blocked RelationshipType::Blocked
); );
let _ = other_user.remove_relationship(user.object.id).await; other_user.remove_relationship(user_id).await.unwrap();
assert_eq!( assert_eq!(
other_user.get_relationships().await.unwrap(), other_user.get_relationships().await.unwrap(),
Vec::<Relationship>::new() Vec::<Relationship>::new()

View File

@ -24,7 +24,6 @@ async fn create_and_get_roles() {
let expected = types::RoleObject::get_all(&mut bundle.user, guild) let expected = types::RoleObject::get_all(&mut bundle.user, guild)
.await .await
.unwrap()
.unwrap()[2] .unwrap()[2]
.clone(); .clone();