From 5b7bfa4a5d150bb29f02b346ce516576870e0cff Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 7 Jun 2023 10:39:05 +0200 Subject: [PATCH 01/19] Make enum into bitflags struct --- src/types/entities/role.rs | 120 +++++++++++++++---------------------- 1 file changed, 48 insertions(+), 72 deletions(-) diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 6293698..d993a7e 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -1,3 +1,4 @@ +use bitflags::bitflags; use serde::{Deserialize, Serialize}; use serde_aux::prelude::{deserialize_option_number_from_string, deserialize_string_from_number}; @@ -51,77 +52,52 @@ pub struct RoleTags { // guild_connections: bool, } -#[derive(Debug)] -#[repr(u64)] -pub enum PermissionFlags { - CreateInstantInvite = 0x0000000000000001, - KickMembers = 0x0000000000000002, - BanMembers = 0x0000000000000004, - Administrator = 0x0000000000000008, - ManageChannels = 0x0000000000000010, - ManageGuild = 0x0000000000000020, - AddReactions = 0x0000000000000040, - ViewAuditLog = 0x0000000000000080, - PrioritySpeaker = 0x0000000000000100, - Stream = 0x0000000000000200, - ViewChannel = 0x0000000000000400, - SendMessages = 0x0000000000000800, - SendTtsMessages = 0x0000000000001000, - ManageMessages = 0x0000000000002000, - EmbedLinks = 0x0000000000004000, - AttachFiles = 0x0000000000008000, - ReadMessageHistory = 0x0000000000010000, - MentionEveryone = 0x0000000000020000, - UseExternalEmojis = 0x0000000000040000, - ViewGuildInsights = 0x0000000000080000, - Connect = 0x0000000000100000, - Speak = 0x0000000000200000, - MuteMembers = 0x0000000000400000, - DeafenMembers = 0x0000000000800000, - MoveMembers = 0x0000000001000000, - UseVad = 0x0000000002000000, - ChangeNickname = 0x0000000004000000, - ManageNicknames = 0x0000000008000000, - ManageRoles = 0x0000000010000000, - ManageWebhooks = 0x0000000020000000, - ManageGuildExpressions = 0x0000000040000000, - UseApplicationCommands = 0x0000000080000000, - RequestToSpeak = 0x0000000100000000, - ManageEvents = 0x0000000200000000, - ManageThreads = 0x0000000400000000, - CreatePublicThreads = 0x0000000800000000, - CreatePrivateThreads = 0x0000001000000000, - UseExternalStickers = 0x0000002000000000, - SendMessagesInThreads = 0x0000004000000000, - UseEmbeddedActivities = 0x0000008000000000, - ModerateMembers = 0x0000010000000000, - ViewCreatorMonetizationAnalytics = 0x0000020000000000, - UseSoundboard = 0x0000040000000000, - UseExternalSounds = 0x0000200000000000, - SendVoiceMessages = 0x0000400000000000, -} - -impl RoleObject { - /// Checks if the role has a specific permission. - /// - /// # Arguments - /// - /// * `permission` - The permission to check for. - /// - /// # Example - /// - /// ``` - /// use chorus::types; - /// let mut role = types::RoleObject::default(); - /// let permission = types::PermissionFlags::ModerateMembers as u64 | types::PermissionFlags::UseSoundboard as u64; - /// role.permissions = permission.to_string(); - /// assert_eq!(true, role.has_permission(types::PermissionFlags::ModerateMembers)); - /// assert_eq!(true, role.has_permission(types::PermissionFlags::UseSoundboard)); - /// ``` - pub fn has_permission(&self, permission: PermissionFlags) -> bool { - if self.permissions.parse::().unwrap() & permission as u64 != 0 { - return true; - } - false +bitflags! { + pub struct PermissionFlags: u64 { + const CREATE_INSTANT_INVITE = 1 << 0; + const KICK_MEMBERS = 1 << 1; + const BAN_MEMBERS = 1 << 2; + const ADMINISTRATOR = 1 << 3; + const MANAGE_CHANNELS = 1 << 4; + const MANAGE_GUILD = 1 << 5; + const ADD_REACTIONS = 1 << 6; + const VIEW_AUDIT_LOG = 1 << 7; + const PRIORITY_SPEAKER = 1 << 8; + const STREAM = 1 << 9; + const VIEW_CHANNEL = 1 << 10; + const SEND_MESSAGES = 1 << 11; + const SEND_TTS_MESSAGES = 1 << 12; + const MANAGE_MESSAGES = 1 << 13; + const EMBED_LINKS = 1 << 14; + const ATTACH_FILES = 1 << 15; + const READ_MESSAGE_HISTORY = 1 << 16; + const MENTION_EVERYONE = 1 << 17; + const USE_EXTERNAL_EMOJIS = 1 << 18; + const VIEW_GUILD_INSIGHTS = 1 << 19; + const CONNECT = 1 << 20; + const SPEAK = 1 << 21; + const MUTE_MEMBERS = 1 << 22; + const DEAFEN_MEMBERS = 1 << 23; + const MOVE_MEMBERS = 1 << 24; + const USE_VAD = 1 << 25; + const CHANGE_NICKNAME = 1 << 26; + const MANAGE_NICKNAMES = 1 << 27; + const MANAGE_ROLES = 1 << 28; + const MANAGE_WEBHOOKS = 1 << 29; + const MANAGE_GUILD_EXPRESSIONS = 1 << 30; + const USE_APPLICATION_COMMANDS = 1 << 31; + const REQUEST_TO_SPEAK = 1 << 32; + const MANAGE_EVENTS = 1 << 33; + const MANAGE_THREADS = 1 << 34; + const CREATE_PUBLIC_THREADS = 1 << 35; + const CREATE_PRIVATE_THREADS = 1 << 36; + const USE_EXTERNAL_STICKERS = 1 << 37; + const SEND_MESSAGES_IN_THREADS = 1 << 38; + const USE_EMBEDDED_ACTIVITIES = 1 << 39; + const MODERATE_MEMBERS = 1 << 40; + const VIEW_CREATOR_MONETIZATION_ANALYTICS = 1 << 41; + const USE_SOUNDBOARD = 1 << 42; + const USE_EXTERNAL_SOUNDS = 1 << 45; + const SEND_VOICE_MESSAGES = 1 << 46; } } From 6c0d21867cc65e65c5671586c72c8d30327897c1 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 7 Jun 2023 22:40:48 +0200 Subject: [PATCH 02/19] Sort fields on Guild alphabetically --- src/types/entities/guild.rs | 113 ++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 56 deletions(-) diff --git a/src/types/entities/guild.rs b/src/types/entities/guild.rs index 1b4d641..f9fa2e2 100644 --- a/src/types/entities/guild.rs +++ b/src/types/entities/guild.rs @@ -13,80 +13,81 @@ use crate::types::{ #[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)] #[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))] pub struct Guild { - pub id: Snowflake, - pub name: Option, - pub icon: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub icon_hash: Option, - pub splash: Option, - pub discovery_splash: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub owner: Option, // True if requesting user is owner - pub owner_id: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub permissions: Option, pub afk_channel_id: Option, pub afk_timeout: Option, - pub widget_enabled: Option, - pub widget_channel_id: Option, - pub verification_level: Option, - pub default_message_notifications: Option, - pub explicit_content_filter: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub roles: Option>, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - #[serde(default)] - pub emojis: Vec, - //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] - pub features: GuildFeaturesList, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub application_id: Option, - pub system_channel_id: Option, - pub system_channel_flags: Option, - pub rules_channel_id: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub rules_channel: Option, - pub max_presences: Option, - pub max_members: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub vanity_url_code: Option, - pub description: Option, - pub banner: Option, - pub premium_tier: Option, - pub premium_subscription_count: Option, - pub preferred_locale: Option, - pub public_updates_channel_id: Option, - pub max_video_channel_users: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub max_stage_video_channel_users: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub approximate_member_count: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub approximate_presence_count: Option, - #[cfg(feature = "sqlx")] - pub welcome_screen: Option>, - #[cfg(not(feature = "sqlx"))] - pub welcome_screen: Option, - pub nsfw_level: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub stickers: Option>, - pub premium_progress_bar_enabled: Option, - #[cfg_attr(feature = "sqlx", sqlx(skip))] - pub joined_at: Option, + pub banner: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub bans: Option>, - pub primary_category_id: Option, - pub large: Option, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub channels: Option>, + pub default_message_notifications: Option, + pub description: Option, + pub discovery_splash: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] + #[serde(default)] + pub emojis: Vec, + pub explicit_content_filter: Option, + //#[cfg_attr(feature = "sqlx", sqlx(try_from = "String"))] + pub features: GuildFeaturesList, + pub icon: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] + pub icon_hash: Option, + pub id: Snowflake, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub invites: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] + pub joined_at: Option, + pub large: Option, + pub max_members: Option, + pub max_presences: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] + pub max_stage_video_channel_users: Option, + pub max_video_channel_users: Option, + pub mfa_level: Option, + pub name: Option, + pub nsfw_level: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] + pub owner: Option, + // True if requesting user is owner + pub owner_id: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] + pub permissions: Option, + pub preferred_locale: Option, + pub premium_progress_bar_enabled: Option, + pub premium_subscription_count: Option, + pub premium_tier: Option, + pub primary_category_id: Option, + pub public_updates_channel_id: Option, + pub region: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] + pub roles: Option>, + #[cfg_attr(feature = "sqlx", sqlx(skip))] + pub rules_channel: Option, + pub rules_channel_id: Option, + pub splash: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] + pub stickers: Option>, + pub system_channel_flags: Option, + pub system_channel_id: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] + pub vanity_url_code: Option, + pub verification_level: Option, + #[cfg_attr(feature = "sqlx", sqlx(skip))] pub voice_states: Option>, #[cfg_attr(feature = "sqlx", sqlx(skip))] pub webhooks: Option>, - pub mfa_level: Option, - pub region: Option, + #[cfg(feature = "sqlx")] + pub welcome_screen: Option>, + #[cfg(not(feature = "sqlx"))] + pub welcome_screen: Option, + pub widget_channel_id: Option, + pub widget_enabled: Option, } /// See https://docs.spacebar.chat/routes/#get-/guilds/-guild_id-/bans/-user- From 97ca0c17eb7db3754f9ce750147a0fe916b4bc3e Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 7 Jun 2023 22:44:16 +0200 Subject: [PATCH 03/19] Try making permissions to PermissionFlags --- src/types/entities/role.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index d993a7e..d315511 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -16,8 +16,7 @@ pub struct RoleObject { pub unicode_emoji: Option, pub position: u16, #[serde(default)] - #[serde(deserialize_with = "deserialize_string_from_number")] - pub permissions: String, + pub permissions: PermissionFlags, pub managed: bool, pub mentionable: bool, #[cfg(feature = "sqlx")] @@ -53,6 +52,7 @@ pub struct RoleTags { } bitflags! { + #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] pub struct PermissionFlags: u64 { const CREATE_INSTANT_INVITE = 1 << 0; const KICK_MEMBERS = 1 << 1; @@ -101,3 +101,9 @@ bitflags! { const SEND_VOICE_MESSAGES = 1 << 46; } } + +impl PermissionFlags { + pub fn has_permission(&self, permission: PermissionFlags) -> bool { + self.contains(permission) || self.contains(PermissionFlags::ADMINISTRATOR) + } +} From afe9663dedf5af2ca4b1f1759de39976fd2e114b Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 7 Jun 2023 23:03:07 +0200 Subject: [PATCH 04/19] Create roles.rs --- src/api/guilds/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/api/guilds/mod.rs b/src/api/guilds/mod.rs index 7108ef7..b06487d 100644 --- a/src/api/guilds/mod.rs +++ b/src/api/guilds/mod.rs @@ -1 +1,5 @@ pub mod guilds; +pub mod roles; + +pub use guilds::*; +pub use roles::*; From 32503078d791e2505f16f46adc6ce70acf7b8cbf Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 7 Jun 2023 23:03:24 +0200 Subject: [PATCH 05/19] Implement RoleObject::get_all() --- src/api/guilds/roles.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/api/guilds/roles.rs diff --git a/src/api/guilds/roles.rs b/src/api/guilds/roles.rs new file mode 100644 index 0000000..91d0923 --- /dev/null +++ b/src/api/guilds/roles.rs @@ -0,0 +1,39 @@ +use reqwest::Client; +use serde_json::from_str; + +use crate::{ + instance::UserMeta, + limit::LimitedRequester, + types::{self, RoleObject}, +}; + +impl types::RoleObject { + pub async fn get_all( + user: &mut UserMeta, + guild_id: &str, + ) -> Result>, crate::errors::InstanceServerError> { + let mut belongs_to = user.belongs_to.borrow_mut(); + let url = format!("{}/guilds/{}/roles/", belongs_to.urls.get_api(), guild_id); + let request = Client::new().get(url).bearer_auth(user.token()); + let requester = match LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Guild, + &mut belongs_to.limits, + &mut user.limits, + ) + .await + { + Ok(request) => request, + Err(e) => return Err(e), + }; + let roles: Vec = from_str(&requester.text().await.unwrap()).unwrap(); + + if roles.is_empty() { + return Ok(None); + } + + Ok(Some(roles)) + } +} From 00978090493388b4f0f1d44fec287c54fb29cf84 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 7 Jun 2023 23:03:37 +0200 Subject: [PATCH 06/19] Remove unnecessary imports --- src/types/entities/role.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index d315511..8d9eab1 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -1,6 +1,6 @@ use bitflags::bitflags; use serde::{Deserialize, Serialize}; -use serde_aux::prelude::{deserialize_option_number_from_string, deserialize_string_from_number}; +use serde_aux::prelude::deserialize_option_number_from_string; use crate::types::utils::Snowflake; From b33de14c256c5bcf050e4ec330f239ac66ea0c89 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 7 Jun 2023 23:06:47 +0200 Subject: [PATCH 07/19] cargo fix --- examples/gateway_observers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gateway_observers.rs b/examples/gateway_observers.rs index e4c78e1..0920d61 100644 --- a/examples/gateway_observers.rs +++ b/examples/gateway_observers.rs @@ -17,7 +17,7 @@ pub struct ExampleObserver {} // One struct can be an observer of multiple websocketevents, if needed impl Observer for ExampleObserver { // After we subscribe to an event this function is called every time we receive it - fn update(&self, data: &GatewayReady) { + fn update(&self, _data: &GatewayReady) { println!("Observed Ready!"); } } From 429db9332b2f2035f52eed0a9608eb6d62ce879f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Wed, 7 Jun 2023 23:06:52 +0200 Subject: [PATCH 08/19] cargo fix --- src/api/channels/channels.rs | 1 - src/api/channels/reactions.rs | 2 +- src/types/events/message.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs index 690ec28..ef5139d 100644 --- a/src/api/channels/channels.rs +++ b/src/api/channels/channels.rs @@ -2,7 +2,6 @@ use reqwest::Client; use serde_json::{from_str, to_string}; use crate::{ - api::limits::Limits, errors::InstanceServerError, instance::UserMeta, limit::LimitedRequester, diff --git a/src/api/channels/reactions.rs b/src/api/channels/reactions.rs index 0ca8e26..a1906c2 100644 --- a/src/api/channels/reactions.rs +++ b/src/api/channels/reactions.rs @@ -3,7 +3,7 @@ use reqwest::Client; use crate::{ instance::UserMeta, limit::LimitedRequester, - types::{self, Snowflake}, + types::{self}, }; /** diff --git a/src/types/events/message.rs b/src/types/events/message.rs index 3b8d8b1..ef3e900 100644 --- a/src/types/events/message.rs +++ b/src/types/events/message.rs @@ -1,4 +1,3 @@ -use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use crate::types::entities::{Emoji, GuildMember, Message, PublicUser}; From c31d2aa76d91a63c50697db3fd7566b8c1d0726b Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 8 Jun 2023 20:40:36 +0200 Subject: [PATCH 09/19] Add RoleCreateSchema --- src/types/schema/guild.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index 4b8b524..437b029 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -12,3 +12,15 @@ pub struct GuildCreateSchema { pub system_channel_id: Option, pub rules_channel_id: Option, } + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub struct RoleCreateSchema { + pub name: Option, + pub permissions: Option, + pub color: Option, + pub hoist: Option, + pub icon: Option>, + pub unicode_emoji: Option, + pub mentionable: Option, +} From a1a4532b57948c775b184ea74b466a6def51f596 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 8 Jun 2023 20:42:40 +0200 Subject: [PATCH 10/19] Add misssing attribute --- src/types/schema/guild.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index 437b029..594f7df 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -23,4 +23,5 @@ pub struct RoleCreateSchema { pub icon: Option>, pub unicode_emoji: Option, pub mentionable: Option, + pub position: Option, } From 4993b7bac8b3126e79f4e986bfeda03d522f3dd2 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 8 Jun 2023 20:43:29 +0200 Subject: [PATCH 11/19] Change struct name This schema is being used as a RoleModifySchema AND as a RoleCreationSchema. --- src/types/schema/guild.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index 594f7df..f7b2f1c 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -15,7 +15,7 @@ pub struct GuildCreateSchema { #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] -pub struct RoleCreateSchema { +pub struct RoleCreateModifySchema { pub name: Option, pub permissions: Option, pub color: Option, From bac097fb2ee39108d09452ff7beedf508b0b78b9 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 8 Jun 2023 20:45:56 +0200 Subject: [PATCH 12/19] Add RolePositionUpdateSchema --- src/types/schema/guild.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index f7b2f1c..03996ed 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -1,4 +1,4 @@ -use crate::types::entities::Channel; +use crate::types::{entities::Channel, Snowflake}; use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize)] @@ -25,3 +25,10 @@ pub struct RoleCreateModifySchema { pub mentionable: Option, pub position: Option, } + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +pub struct RolePositionUpdateSchema { + pub id: Snowflake, + pub position: i32, +} From ea69d51574a8286c749c4005e6f71befebaaa763 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 8 Jun 2023 21:53:34 +0200 Subject: [PATCH 13/19] Add some documentation --- tests/roles.rs | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/roles.rs diff --git a/tests/roles.rs b/tests/roles.rs new file mode 100644 index 0000000..3b7bcde --- /dev/null +++ b/tests/roles.rs @@ -0,0 +1,3 @@ +mod common; + +use chorus::types; From 9f21c064929ebd1bbee49608d47863d18ec19d17 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 8 Jun 2023 22:16:23 +0200 Subject: [PATCH 14/19] Change InstanceServerError to ChorusLibError The name InstanceServerError was chosen without thinking about it too much, very early in development. The new name suits this custom Error type way better, in my opinion. --- src/api/auth/login.rs | 8 +++--- src/api/auth/register.rs | 10 ++++---- src/api/channels/channels.rs | 17 ++++++------- src/api/channels/messages.rs | 8 +++--- src/api/channels/reactions.rs | 24 +++++++++--------- src/api/guilds/guilds.rs | 36 +++++++++++++-------------- src/api/guilds/roles.rs | 20 ++++++++++++--- src/api/policies/instance/instance.rs | 10 ++++---- src/api/users/users.rs | 34 +++++++++++-------------- src/errors.rs | 2 +- src/instance.rs | 6 ++--- src/limit.rs | 18 +++++++------- src/types/schema/guild.rs | 6 +++++ 13 files changed, 105 insertions(+), 94 deletions(-) diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 7ecc4de..2481cd6 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -6,7 +6,7 @@ pub mod login { use serde_json::{from_str, json}; use crate::api::limits::LimitType; - use crate::errors::InstanceServerError; + use crate::errors::ChorusLibError; use crate::instance::{Instance, UserMeta}; use crate::limit::LimitedRequester; use crate::types::{ErrorResponse, LoginResult, LoginSchema}; @@ -15,7 +15,7 @@ pub mod login { pub async fn login_account( &mut self, login_schema: &LoginSchema, - ) -> Result { + ) -> Result { let mut requester = LimitedRequester::new().await; let json_schema = json!(login_schema); let client = Client::new(); @@ -34,7 +34,7 @@ pub mod login { ) .await; if response.is_err() { - return Err(InstanceServerError::NoResponse); + return Err(ChorusLibError::NoResponse); } let response_unwrap = response.unwrap(); @@ -49,7 +49,7 @@ pub mod login { error += &(error_item.message.to_string() + " (" + &error_item.code + ")"); } } - return Err(InstanceServerError::InvalidFormBodyError { error_type, error }); + return Err(ChorusLibError::InvalidFormBodyError { error_type, error }); } let cloned_limits = self.limits.clone(); diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index 2c8f3f9..8ca4735 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -6,7 +6,7 @@ pub mod register { use crate::{ api::limits::LimitType, - errors::InstanceServerError, + errors::ChorusLibError, instance::{Instance, Token, UserMeta}, limit::LimitedRequester, types::{ErrorResponse, RegisterSchema}, @@ -18,12 +18,12 @@ pub mod register { # Arguments * `register_schema` - The [`RegisterSchema`] that contains all the information that is needed to register a new user. # Errors - * [`InstanceServerError`] - If the server does not respond. + * [`ChorusLibError`] - If the server does not respond. */ pub async fn register_account( &mut self, register_schema: &RegisterSchema, - ) -> Result { + ) -> Result { let json_schema = json!(register_schema); let mut limited_requester = LimitedRequester::new().await; let client = Client::new(); @@ -42,7 +42,7 @@ pub mod register { ) .await; if response.is_err() { - return Err(InstanceServerError::NoResponse); + return Err(ChorusLibError::NoResponse); } let response_unwrap = response.unwrap(); @@ -59,7 +59,7 @@ pub mod register { error += &(error_item.message.to_string() + " (" + &error_item.code + ")"); } } - return Err(InstanceServerError::InvalidFormBodyError { error_type, error }); + return Err(ChorusLibError::InvalidFormBodyError { error_type, error }); } let user_object = self.get_user(token.clone(), None).await.unwrap(); let settings = diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs index ef5139d..7ed9fc7 100644 --- a/src/api/channels/channels.rs +++ b/src/api/channels/channels.rs @@ -2,17 +2,14 @@ use reqwest::Client; use serde_json::{from_str, to_string}; use crate::{ - errors::InstanceServerError, + errors::ChorusLibError, instance::UserMeta, limit::LimitedRequester, types::{Channel, ChannelModifySchema}, }; impl Channel { - pub async fn get( - user: &mut UserMeta, - channel_id: &str, - ) -> Result { + pub async fn get(user: &mut UserMeta, channel_id: &str) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let request = Client::new() .get(format!( @@ -37,7 +34,7 @@ impl Channel { let result_text = result.text().await.unwrap(); match from_str::(&result_text) { Ok(object) => Ok(object), - Err(e) => Err(InstanceServerError::RequestErrorError { + Err(e) => Err(ChorusLibError::RequestErrorError { url: format!("{}/channels/{}/", belongs_to.urls.get_api(), channel_id), error: e.to_string(), }), @@ -56,8 +53,8 @@ impl Channel { /// /// # Returns /// - /// An `Option` that contains an `InstanceServerError` if an error occurred during the request, or `None` if the request was successful. - pub async fn delete(self, user: &mut UserMeta) -> Option { + /// An `Option` that contains an `ChorusLibError` if an error occurred during the request, or `None` if the request was successful. + pub async fn delete(self, user: &mut UserMeta) -> Option { let mut belongs_to = user.belongs_to.borrow_mut(); let request = Client::new() .delete(format!( @@ -94,12 +91,12 @@ impl Channel { /// /// # Returns /// - /// A `Result` that contains a `Channel` object if the request was successful, or an `InstanceServerError` if an error occurred during the request. + /// A `Result` that contains a `Channel` object if the request was successful, or an `ChorusLibError` if an error occurred during the request. pub async fn modify( modify_data: ChannelModifySchema, channel_id: &str, user: &mut UserMeta, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let request = Client::new() .patch(format!( diff --git a/src/api/channels/messages.rs b/src/api/channels/messages.rs index a181784..d511e24 100644 --- a/src/api/channels/messages.rs +++ b/src/api/channels/messages.rs @@ -17,14 +17,14 @@ impl Message { * `limits_instance` - The [`Limits`] of the instance. * `requester` - The [`LimitedRequester`] that will be used to make requests to the Spacebar server. # Errors - * [`InstanceServerError`] - If the message cannot be sent. + * [`ChorusLibError`] - If the message cannot be sent. */ pub async fn send( user: &mut UserMeta, channel_id: String, message: &mut MessageSendSchema, files: Option>, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let url_api = belongs_to.urls.get_api(); let mut requester = LimitedRequester::new().await; @@ -98,14 +98,14 @@ impl UserMeta { * `limits_instance` - The [`Limits`] of the instance. * `requester` - The [`LimitedRequester`] that will be used to make requests to the Spacebar server. # Errors - * [`InstanceServerError`] - If the message cannot be sent. + * [`ChorusLibError`] - If the message cannot be sent. */ pub async fn send_message( &mut self, message: &mut MessageSendSchema, channel_id: String, files: Option>, - ) -> Result { + ) -> Result { Message::send(self, channel_id, message, files).await } } diff --git a/src/api/channels/reactions.rs b/src/api/channels/reactions.rs index a1906c2..9bd7adc 100644 --- a/src/api/channels/reactions.rs +++ b/src/api/channels/reactions.rs @@ -23,7 +23,7 @@ impl ReactionMeta { * `user` - A mutable reference to a [`UserMeta`] instance. # Returns - A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::ChorusLibError`]. Fires a `Message Reaction Remove All` Gateway event. # Reference @@ -32,7 +32,7 @@ impl ReactionMeta { pub async fn delete_all( &self, user: &mut UserMeta, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!( "{}/channels/{}/messages/{}/reactions/", @@ -62,7 +62,7 @@ impl ReactionMeta { * `user` - A mutable reference to a [`UserMeta`] instance. # Returns - A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::ChorusLibError`]. # Reference See [https://discord.com/developers/docs/resources/channel#get-reactions](https://discord.com/developers/docs/resources/channel#get-reactions) @@ -71,7 +71,7 @@ impl ReactionMeta { &self, emoji: &str, user: &mut UserMeta, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!( "{}/channels/{}/messages/{}/reactions/{}/", @@ -103,7 +103,7 @@ impl ReactionMeta { * `user` - A mutable reference to a [`UserMeta`] instance. # Returns - A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::ChorusLibError`]. Fires a `Message Reaction Remove Emoji` Gateway event. # Reference @@ -113,7 +113,7 @@ impl ReactionMeta { &self, emoji: &str, user: &mut UserMeta, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!( "{}/channels/{}/messages/{}/reactions/{}/", @@ -148,7 +148,7 @@ impl ReactionMeta { * `user` - A mutable reference to a [`UserMeta`] instance. # Returns - A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::ChorusLibError`]. Returns a 204 empty response on success. Fires a Message Reaction Add Gateway event. @@ -159,7 +159,7 @@ impl ReactionMeta { &self, emoji: &str, user: &mut UserMeta, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!( "{}/channels/{}/messages/{}/reactions/{}/@me/", @@ -190,7 +190,7 @@ impl ReactionMeta { * `user` - A mutable reference to a [`UserMeta`] instance. # Returns - A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::ChorusLibError`]. Returns a 204 empty response on success. Fires a `Message Reaction Remove` Gateway event. @@ -201,7 +201,7 @@ impl ReactionMeta { &self, emoji: &str, user: &mut UserMeta, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!( "{}/channels/{}/messages/{}/reactions/{}/@me/", @@ -235,7 +235,7 @@ impl ReactionMeta { * `user` - A mutable reference to a [`UserMeta`] instance. # Returns - A `Result` containing a [`reqwest::Response`] or a [`crate::errors::InstanceServerError`]. + A `Result` containing a [`reqwest::Response`] or a [`crate::errors::ChorusLibError`]. Returns a 204 empty response on success. Fires a Message Reaction Remove Gateway event. @@ -247,7 +247,7 @@ impl ReactionMeta { user_id: &str, emoji: &str, user: &mut UserMeta, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!( "{}/channels/{}/messages/{}/reactions/{}/{}", diff --git a/src/api/guilds/guilds.rs b/src/api/guilds/guilds.rs index f267e55..56912e7 100644 --- a/src/api/guilds/guilds.rs +++ b/src/api/guilds/guilds.rs @@ -3,7 +3,7 @@ use serde_json::from_str; use serde_json::to_string; use crate::api::limits::Limits; -use crate::errors::InstanceServerError; +use crate::errors::ChorusLibError; use crate::instance::UserMeta; use crate::limit::LimitedRequester; use crate::types::{Channel, ChannelCreateSchema, Guild, GuildCreateResponse, GuildCreateSchema}; @@ -23,12 +23,12 @@ impl Guild { /// /// # Errors /// - /// Returns an `InstanceServerError` if the request fails. + /// Returns an `ChorusLibError` if the request fails. /// pub async fn create( user: &mut UserMeta, guild_create_schema: GuildCreateSchema, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!("{}/guilds/", belongs_to.urls.get_api()); let request = reqwest::Client::new() @@ -71,7 +71,7 @@ impl Guild { /// /// # Returns /// - /// An `Option` containing an `InstanceServerError` if an error occurred during the request, otherwise `None`. + /// An `Option` containing an `ChorusLibError` if an error occurred during the request, otherwise `None`. /// /// # Example /// @@ -85,7 +85,7 @@ impl Guild { /// None => println!("Guild deleted successfully"), /// } /// ``` - pub async fn delete(user: &mut UserMeta, guild_id: &str) -> Option { + pub async fn delete(user: &mut UserMeta, guild_id: &str) -> Option { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!("{}/guilds/{}/delete/", belongs_to.urls.get_api(), guild_id); let request = reqwest::Client::new() @@ -119,12 +119,12 @@ impl Guild { /// /// # Returns /// - /// A `Result` containing a `reqwest::Response` if the request was successful, or an `InstanceServerError` if there was an error. + /// A `Result` containing a `reqwest::Response` if the request was successful, or an `ChorusLibError` if there was an error. pub async fn create_channel( &self, user: &mut UserMeta, schema: ChannelCreateSchema, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); Channel::_create( &user.token, @@ -137,7 +137,7 @@ impl Guild { .await } - /// Returns a `Result` containing a vector of `Channel` structs if the request was successful, or an `InstanceServerError` if there was an error. + /// Returns a `Result` containing a vector of `Channel` structs if the request was successful, or an `ChorusLibError` if there was an error. /// /// # Arguments /// @@ -146,7 +146,7 @@ impl Guild { /// * `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. /// - pub async fn channels(&self, user: &mut UserMeta) -> Result, InstanceServerError> { + pub async fn channels(&self, user: &mut UserMeta) -> Result, ChorusLibError> { let mut belongs_to = user.belongs_to.borrow_mut(); let request = Client::new() .get(format!( @@ -171,7 +171,7 @@ impl Guild { let stringed_response = match result.text().await { Ok(value) => value, Err(e) => { - return Err(InstanceServerError::InvalidResponseError { + return Err(ChorusLibError::InvalidResponseError { error: e.to_string(), }) } @@ -179,14 +179,14 @@ impl Guild { let _: Vec = match from_str(&stringed_response) { Ok(result) => return Ok(result), Err(e) => { - return Err(InstanceServerError::InvalidResponseError { + return Err(ChorusLibError::InvalidResponseError { error: e.to_string(), }) } }; } - /// Returns a `Result` containing a `Guild` struct if the request was successful, or an `InstanceServerError` if there was an error. + /// Returns a `Result` containing a `Guild` struct if the request was successful, or an `ChorusLibError` if there was an error. /// /// # Arguments /// @@ -196,7 +196,7 @@ impl Guild { /// * `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. /// - pub async fn get(user: &mut UserMeta, guild_id: &str) -> Result { + pub async fn get(user: &mut UserMeta, guild_id: &str) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); Guild::_get( &format!("{}", belongs_to.urls.get_api()), @@ -216,7 +216,7 @@ impl Guild { token: &str, limits_user: &mut Limits, limits_instance: &mut Limits, - ) -> Result { + ) -> Result { let request = Client::new() .get(format!("{}/guilds/{}/", url_api, guild_id)) .bearer_auth(token); @@ -252,12 +252,12 @@ impl Channel { /// /// # Returns /// - /// A `Result` containing a `reqwest::Response` if the request was successful, or an `InstanceServerError` if there was an error. + /// A `Result` containing a `reqwest::Response` if the request was successful, or an `ChorusLibError` if there was an error. pub async fn create( user: &mut UserMeta, guild_id: &str, schema: ChannelCreateSchema, - ) -> Result { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); Channel::_create( &user.token, @@ -277,7 +277,7 @@ impl Channel { schema: ChannelCreateSchema, limits_user: &mut Limits, limits_instance: &mut Limits, - ) -> Result { + ) -> Result { let request = Client::new() .post(format!("{}/guilds/{}/channels/", url_api, guild_id)) .bearer_auth(token) @@ -297,7 +297,7 @@ impl Channel { }; match from_str::(&result.text().await.unwrap()) { Ok(object) => Ok(object), - Err(e) => Err(InstanceServerError::RequestErrorError { + Err(e) => Err(ChorusLibError::RequestErrorError { url: format!("{}/guilds/{}/channels/", url_api, guild_id), error: e.to_string(), }), diff --git a/src/api/guilds/roles.rs b/src/api/guilds/roles.rs index 91d0923..86444bb 100644 --- a/src/api/guilds/roles.rs +++ b/src/api/guilds/roles.rs @@ -1,17 +1,17 @@ use reqwest::Client; -use serde_json::from_str; +use serde_json::{from_str, to_string}; use crate::{ instance::UserMeta, limit::LimitedRequester, - types::{self, RoleObject}, + types::{self, RoleCreateModifySchema, RoleObject}, }; impl types::RoleObject { pub async fn get_all( user: &mut UserMeta, guild_id: &str, - ) -> Result>, crate::errors::InstanceServerError> { + ) -> Result>, crate::errors::ChorusLibError> { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!("{}/guilds/{}/roles/", belongs_to.urls.get_api(), guild_id); let request = Client::new().get(url).bearer_auth(user.token()); @@ -36,4 +36,18 @@ impl types::RoleObject { Ok(Some(roles)) } + + pub async fn create( + user: &mut UserMeta, + guild_id: &str, + role_create_schema: RoleCreateModifySchema, + ) { + let mut belongs_to = user.belongs_to.borrow_mut(); + let url = format!("{}/guilds/{}/roles/", belongs_to.urls.get_api(), guild_id); + let body = match to_string::(&role_create_schema) { + Ok(string) => string, + Err(e) => + }; + let request = Client::new().post(url).bearer_auth(user.token()).body() + } } diff --git a/src/api/policies/instance/instance.rs b/src/api/policies/instance/instance.rs index f183e11..055568f 100644 --- a/src/api/policies/instance/instance.rs +++ b/src/api/policies/instance/instance.rs @@ -1,7 +1,7 @@ use reqwest::Client; use serde_json::from_str; -use crate::errors::InstanceServerError; +use crate::errors::ChorusLibError; use crate::instance::Instance; use crate::types::GeneralConfiguration; @@ -9,17 +9,17 @@ impl Instance { /** Gets the instance policies schema. # Errors - [`InstanceServerError`] - If the request fails. + [`ChorusLibError`] - If the request fails. */ pub async fn general_configuration_schema( &self, - ) -> Result { + ) -> Result { let client = Client::new(); let endpoint_url = self.urls.get_api().to_string() + "/policies/instance/"; let request = match client.get(&endpoint_url).send().await { Ok(result) => result, Err(e) => { - return Err(InstanceServerError::RequestErrorError { + return Err(ChorusLibError::RequestErrorError { url: endpoint_url, error: e.to_string(), }); @@ -27,7 +27,7 @@ impl Instance { }; if !request.status().as_str().starts_with('2') { - return Err(InstanceServerError::ReceivedErrorCodeError { + return Err(ChorusLibError::ReceivedErrorCodeError { error_code: request.status().to_string(), }); } diff --git a/src/api/users/users.rs b/src/api/users/users.rs index 2cdaa74..ffabd3f 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -3,7 +3,7 @@ use serde_json::{from_str, to_string}; use crate::{ api::limits::Limits, - errors::InstanceServerError, + errors::ChorusLibError, instance::{Instance, UserMeta}, limit::LimitedRequester, types::{User, UserModifySchema, UserSettings}, @@ -18,12 +18,9 @@ impl UserMeta { * `id` - The id of the user that will be retrieved. If this is None, the current user will be retrieved. * `instance_limits` - The [`Limits`] of the instance. # Errors - * [`InstanceServerError`] - If the request fails. + * [`ChorusLibError`] - If the request fails. */ - pub async fn get( - user: &mut UserMeta, - id: Option<&String>, - ) -> Result { + pub async fn get(user: &mut UserMeta, id: Option<&String>) -> Result { User::get(user, id).await } @@ -31,7 +28,7 @@ impl UserMeta { token: &String, url_api: &String, instance_limits: &mut Limits, - ) -> Result { + ) -> Result { User::get_settings(token, url_api, instance_limits).await } @@ -43,16 +40,16 @@ impl UserMeta { /// /// # Errors /// - /// Returns an `InstanceServerError` if the request fails or if a password is required but not provided. + /// 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, - ) -> Result { + ) -> Result { if modify_schema.new_password.is_some() || modify_schema.email.is_some() || modify_schema.code.is_some() { - return Err(InstanceServerError::PasswordRequiredError); + return Err(ChorusLibError::PasswordRequiredError); } let request = Client::new() .patch(format!( @@ -90,8 +87,8 @@ impl UserMeta { /// /// # Returns /// - /// Returns `None` if the user was successfully deleted, or an `InstanceServerError` if an error occurred. - pub async fn delete(mut self) -> Option { + /// Returns `None` if the user was successfully deleted, or an `ChorusLibError` if an error occurred. + pub async fn delete(mut self) -> Option { let mut belongs_to = self.belongs_to.borrow_mut(); let request = Client::new() .post(format!("{}/users/@me/delete/", belongs_to.urls.get_api())) @@ -113,10 +110,7 @@ impl UserMeta { } impl User { - pub async fn get( - user: &mut UserMeta, - id: Option<&String>, - ) -> Result { + pub async fn get(user: &mut UserMeta, id: Option<&String>) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); User::_get( &user.token(), @@ -132,7 +126,7 @@ impl User { url_api: &str, limits_instance: &mut Limits, id: Option<&String>, - ) -> Result { + ) -> Result { let url: String; if id.is_none() { url = format!("{}/users/@me/", url_api); @@ -163,7 +157,7 @@ impl User { token: &String, url_api: &String, instance_limits: &mut Limits, - ) -> Result { + ) -> Result { let request: reqwest::RequestBuilder = Client::new() .get(format!("{}/users/@me/settings/", url_api)) .bearer_auth(token); @@ -191,7 +185,7 @@ impl Instance { * `token` - A valid access token for the API. * `id` - The id of the user that will be retrieved. If this is None, the current user will be retrieved. # Errors - * [`InstanceServerError`] - If the request fails. + * [`ChorusLibError`] - If the request fails. # Notes This function is a wrapper around [`User::get`]. */ @@ -199,7 +193,7 @@ impl Instance { &mut self, token: String, id: Option<&String>, - ) -> Result { + ) -> Result { User::_get( &token, &self.urls.get_api().to_string(), diff --git a/src/errors.rs b/src/errors.rs index 749c8f7..07cae43 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -11,7 +11,7 @@ custom_error! { custom_error! { #[derive(PartialEq, Eq)] - pub InstanceServerError + pub ChorusLibError NoResponse = "Did not receive a response from the Server.", RequestErrorError{url:String, error:String} = "An error occured while trying to GET from {url}: {error}", ReceivedErrorCodeError{error_code:String} = "Received the following error code while requesting from the route: {error_code}", diff --git a/src/instance.rs b/src/instance.rs index ce8849d..6121c65 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use crate::api::limits::Limits; -use crate::errors::{FieldFormatError, InstanceServerError}; +use crate::errors::{ChorusLibError, FieldFormatError}; use crate::types::{GeneralConfiguration, User, UserSettings}; use crate::URLBundle; @@ -26,7 +26,7 @@ impl Instance { /// * `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) -> Result { + pub async fn new(urls: URLBundle) -> Result { let mut instance = Instance { urls: urls.clone(), instance_info: GeneralConfiguration::new( @@ -45,7 +45,7 @@ impl Instance { instance.instance_info = match instance.general_configuration_schema().await { Ok(schema) => schema, Err(e) => { - return Err(InstanceServerError::CantGetInfoError { + return Err(ChorusLibError::CantGetInfoError { error: e.to_string(), }) } diff --git a/src/limit.rs b/src/limit.rs index cc058b6..70f5c06 100644 --- a/src/limit.rs +++ b/src/limit.rs @@ -1,6 +1,6 @@ use crate::{ api::limits::{Limit, LimitType, Limits, LimitsMutRef}, - errors::InstanceServerError, + errors::ChorusLibError, }; use reqwest::{Client, RequestBuilder, Response}; @@ -71,12 +71,12 @@ impl LimitedRequester { limit_type: LimitType, instance_rate_limits: &mut Limits, user_rate_limits: &mut Limits, - ) -> Result { + ) -> Result { if self.can_send_request(limit_type, instance_rate_limits, user_rate_limits) { let built_request = match request.build() { Ok(request) => request, Err(e) => { - return Err(InstanceServerError::RequestErrorError { + return Err(ChorusLibError::RequestErrorError { url: "".to_string(), error: e.to_string(), }) @@ -86,7 +86,7 @@ impl LimitedRequester { let response = match result { Ok(is_response) => is_response, Err(e) => { - return Err(InstanceServerError::ReceivedErrorCodeError { + return Err(ChorusLibError::ReceivedErrorCodeError { error_code: e.to_string(), }) } @@ -99,10 +99,10 @@ impl LimitedRequester { ); if !response.status().is_success() { match response.status().as_u16() { - 401 => return Err(InstanceServerError::TokenExpired), - 403 => return Err(InstanceServerError::TokenExpired), + 401 => return Err(ChorusLibError::TokenExpired), + 403 => return Err(ChorusLibError::TokenExpired), _ => { - return Err(InstanceServerError::ReceivedErrorCodeError { + return Err(ChorusLibError::ReceivedErrorCodeError { error_code: response.status().as_str().to_string(), }) } @@ -115,7 +115,7 @@ impl LimitedRequester { request, limit_type, }); - Err(InstanceServerError::RateLimited { + Err(ChorusLibError::RateLimited { bucket: limit_type.to_string(), }) } @@ -302,7 +302,7 @@ mod rate_limit { String::from("http://localhost:3001/cdn"), ); let mut requester = LimitedRequester::new().await; - let mut request: Option> = None; + let mut request: Option> = None; let mut instance_rate_limits = Limits::check_limits(urls.api.clone()).await; let mut user_rate_limits = Limits::check_limits(urls.api.clone()).await; diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index 03996ed..a607123 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -3,6 +3,8 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] +/// Represents the schema which needs to be sent to create a Guild. +/// See: [https://docs.spacebar.chat/routes/#cmp--schemas-guildcreateschema](https://docs.spacebar.chat/routes/#cmp--schemas-guildcreateschema) pub struct GuildCreateSchema { pub name: Option, pub region: Option, @@ -15,6 +17,8 @@ pub struct GuildCreateSchema { #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] +/// Represents the schema which needs to be sent to create or modify a Role. +/// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolemodifyschema) pub struct RoleCreateModifySchema { pub name: Option, pub permissions: Option, @@ -28,6 +32,8 @@ pub struct RoleCreateModifySchema { #[derive(Debug, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] +/// Represents the schema which needs to be sent to update a roles' position. +/// See: [https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema](https://docs.spacebar.chat/routes/#cmp--schemas-rolepositionupdateschema) pub struct RolePositionUpdateSchema { pub id: Snowflake, pub position: i32, From 1c5be5693e32d03755277ab596c9ee11f24906aa Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 8 Jun 2023 22:26:08 +0200 Subject: [PATCH 15/19] Add FormCreationError --- src/errors.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/errors.rs b/src/errors.rs index 07cae43..e0789e3 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -19,6 +19,7 @@ custom_error! { InvalidFormBodyError{error_type: String, error:String} = "The server responded with: {error_type}: {error}", RateLimited{bucket:String} = "Ratelimited on Bucket {bucket}", MultipartCreationError{error: String} = "Got an error whilst creating the form: {}", + FormCreationError{error: String} = "Got an error whilst creating the form: {}", TokenExpired = "Token expired, invalid or not found.", NoPermission = "You do not have the permissions needed to perform this action.", NotFound{error: String} = "The provided resource hasn't been found: {}", From 30cfb3b744f761cb0bcc82bbb520a7ea42206623 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 8 Jun 2023 22:26:24 +0200 Subject: [PATCH 16/19] Implement RoleObject::create() --- src/api/guilds/roles.rs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/api/guilds/roles.rs b/src/api/guilds/roles.rs index 86444bb..e246efe 100644 --- a/src/api/guilds/roles.rs +++ b/src/api/guilds/roles.rs @@ -2,6 +2,7 @@ use reqwest::Client; use serde_json::{from_str, to_string}; use crate::{ + errors::ChorusLibError, instance::UserMeta, limit::LimitedRequester, types::{self, RoleCreateModifySchema, RoleObject}, @@ -41,13 +42,39 @@ impl types::RoleObject { user: &mut UserMeta, guild_id: &str, role_create_schema: RoleCreateModifySchema, - ) { + ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); let url = format!("{}/guilds/{}/roles/", belongs_to.urls.get_api(), guild_id); let body = match to_string::(&role_create_schema) { Ok(string) => string, - Err(e) => + Err(e) => { + return Err(ChorusLibError::FormCreationError { + error: e.to_string(), + }) + } }; - let request = Client::new().post(url).bearer_auth(user.token()).body() + let request = Client::new().post(url).bearer_auth(user.token()).body(body); + let result = match LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Guild, + &mut belongs_to.limits, + &mut user.limits, + ) + .await + { + Ok(request) => request, + Err(e) => return Err(e), + }; + let role: RoleObject = match from_str(&result.text().await.unwrap()) { + Ok(role) => role, + Err(e) => { + return Err(ChorusLibError::InvalidResponseError { + error: e.to_string(), + }) + } + }; + Ok(role) } } From fc660366747491473f9bb22a0657701a80bc1f5c Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Thu, 8 Jun 2023 22:39:06 +0200 Subject: [PATCH 17/19] Add documentation --- src/api/guilds/roles.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/api/guilds/roles.rs b/src/api/guilds/roles.rs index e246efe..482a859 100644 --- a/src/api/guilds/roles.rs +++ b/src/api/guilds/roles.rs @@ -9,6 +9,20 @@ use crate::{ }; impl types::RoleObject { + /// Retrieves all roles for a given guild. + /// + /// # Arguments + /// + /// * `user` - A mutable reference to a [`UserMeta`] instance. + /// * `guild_id` - The ID of the guild to retrieve roles from. + /// + /// # Returns + /// + /// An `Option` containing a `Vec` of [`RoleObject`]s if roles were found, or `None` if no roles were found. + /// + /// # Errors + /// + /// Returns a [`ChorusLibError`] if the request fails or if the response is invalid. pub async fn get_all( user: &mut UserMeta, guild_id: &str, @@ -38,6 +52,21 @@ impl types::RoleObject { Ok(Some(roles)) } + /// Creates a new role for a given guild. + /// + /// # Arguments + /// + /// * `user` - A mutable reference to a [`UserMeta`] instance. + /// * `guild_id` - The ID of the guild to create the role in. + /// * `role_create_schema` - A [`RoleCreateModifySchema`] instance containing the properties of the role to be created. + /// + /// # Returns + /// + /// A `Result` containing the newly created [`RoleObject`] if successful, or a [`ChorusLibError`] if the request fails or if the response is invalid. + /// + /// # Errors + /// + /// Returns a [`ChorusLibError`] if the request fails or if the response is invalid. pub async fn create( user: &mut UserMeta, guild_id: &str, From f44e1f58566318e7df489fc61af49b8a6f5c853a Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 9 Jun 2023 12:03:56 +0200 Subject: [PATCH 18/19] Test RoleObject::create() and ::get_all() --- tests/roles.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/tests/roles.rs b/tests/roles.rs index 3b7bcde..b34bdd7 100644 --- a/tests/roles.rs +++ b/tests/roles.rs @@ -1,3 +1,34 @@ mod common; -use chorus::types; +use chorus::types::{self, RoleCreateModifySchema}; + +#[tokio::test] +async fn create_and_get_roles() { + let mut bundle = common::setup().await; + let role_create_schema: types::RoleCreateModifySchema = RoleCreateModifySchema { + name: Some("cool person".to_string()), + permissions: Some("2251804225".to_string()), + hoist: Some(true), + icon: None, + unicode_emoji: Some("".to_string()), + mentionable: Some(true), + position: None, + color: None, + }; + let guild_id = bundle.guild.id.clone().to_string(); + let role = types::RoleObject::create(&mut bundle.user, &guild_id, role_create_schema) + .await + .unwrap(); + + let expected = types::RoleObject::get_all(&mut bundle.user, &guild_id) + .await + .unwrap() + .unwrap() + .iter() + .nth(1) + .unwrap() + .clone(); + + assert_eq!(role, expected); + common::teardown(bundle).await +} From 9bf968c7e0c9ac26dc625cf50dc59dcbb4d7362d Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 9 Jun 2023 12:04:49 +0200 Subject: [PATCH 19/19] Change Role to have String over PermissionFlags PermissionFlags implementation needs to be figured out a bit better before we can use it here. --- src/types/entities/role.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 8d9eab1..ba4a2fe 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -16,7 +16,7 @@ pub struct RoleObject { pub unicode_emoji: Option, pub position: u16, #[serde(default)] - pub permissions: PermissionFlags, + pub permissions: String, pub managed: bool, pub mentionable: bool, #[cfg(feature = "sqlx")]