From 6ed9eaf2fcc8b1ac1c529cbfde4de9dd98fa6674 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 9 Jun 2023 16:50:03 +0200 Subject: [PATCH 01/12] Implement RoleObject::position_update() --- src/api/guilds/roles.rs | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/api/guilds/roles.rs b/src/api/guilds/roles.rs index 482a859..a65b36d 100644 --- a/src/api/guilds/roles.rs +++ b/src/api/guilds/roles.rs @@ -106,4 +106,59 @@ impl types::RoleObject { }; Ok(role) } + + /// Updates the position of a role in the guild's hierarchy. + /// + /// # Arguments + /// + /// * `user` - A mutable reference to a [`UserMeta`] instance. + /// * `guild_id` - The ID of the guild to update the role position in. + /// * `role_position_update_schema` - A [`RolePositionUpdateSchema`] instance containing the new position of the role. + /// + /// # Returns + /// + /// A `Result` containing the updated [`RoleObject`] if successful, or a [`ChorusLibError`] if the request fails or if the response is invalid. + /// + /// # Errors + /// + /// Returns a [`ChorusLibError`] if the request fails or if the response is invalid. + pub async fn position_update( + user: &mut UserMeta, + guild_id: &str, + role_position_update_schema: types::RolePositionUpdateSchema, + ) -> 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_position_update_schema) { + Ok(body) => body, + Err(e) => { + return Err(ChorusLibError::FormCreationError { + error: e.to_string(), + }) + } + }; + let request = Client::new() + .patch(url) + .bearer_auth(user.token()) + .body(body); + let response = LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Guild, + &mut belongs_to.limits, + &mut user.limits, + ) + .await + .unwrap(); + let role: RoleObject = match from_str(&response.text().await.unwrap()) { + Ok(role) => role, + Err(e) => { + return Err(ChorusLibError::InvalidResponseError { + error: e.to_string(), + }) + } + }; + Ok(role) + } } From 2d828f2fdba5f63af610ca577e648741b094ea38 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 9 Jun 2023 20:47:45 +0200 Subject: [PATCH 02/12] Move role schemas to own file --- src/types/schema/guild.rs | 24 ------------------------ src/types/schema/mod.rs | 2 ++ src/types/schema/role.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 24 deletions(-) create mode 100644 src/types/schema/role.rs diff --git a/src/types/schema/guild.rs b/src/types/schema/guild.rs index a607123..c0c4224 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -14,27 +14,3 @@ pub struct GuildCreateSchema { pub system_channel_id: Option, pub rules_channel_id: Option, } - -#[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, - pub color: Option, - pub hoist: Option, - pub icon: Option>, - pub unicode_emoji: Option, - pub mentionable: Option, - pub position: Option, -} - -#[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, -} diff --git a/src/types/schema/mod.rs b/src/types/schema/mod.rs index 6fe3e37..2e5c4f0 100644 --- a/src/types/schema/mod.rs +++ b/src/types/schema/mod.rs @@ -3,6 +3,7 @@ mod auth; mod channel; mod guild; mod message; +mod role; mod user; pub use apierror::*; @@ -10,6 +11,7 @@ pub use auth::*; pub use channel::*; pub use guild::*; pub use message::*; +pub use role::*; pub use user::*; #[cfg(test)] diff --git a/src/types/schema/role.rs b/src/types/schema/role.rs new file mode 100644 index 0000000..97ab248 --- /dev/null +++ b/src/types/schema/role.rs @@ -0,0 +1,26 @@ +use crate::types::Snowflake; +use serde::{Deserialize, Serialize}; + +#[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, + pub color: Option, + pub hoist: Option, + pub icon: Option>, + pub unicode_emoji: Option, + pub mentionable: Option, + pub position: Option, +} + +#[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 76e038b103da924e700c3ceaa8d01e04edd90da8 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 9 Jun 2023 20:49:02 +0200 Subject: [PATCH 03/12] Remove unused import --- 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 c0c4224..835f6ad 100644 --- a/src/types/schema/guild.rs +++ b/src/types/schema/guild.rs @@ -1,4 +1,4 @@ -use crate::types::{entities::Channel, Snowflake}; +use crate::types::entities::Channel; use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize)] From 777746bc0040f98c4c71e4b7ae7a3a6187ca343f Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 9 Jun 2023 21:34:54 +0200 Subject: [PATCH 04/12] Add from_vec() Calculates a PermissionFlags Stirng from a Vec. --- src/types/entities/role.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index ba4a2fe..3cbf0ea 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -106,4 +106,30 @@ impl PermissionFlags { pub fn has_permission(&self, permission: PermissionFlags) -> bool { self.contains(permission) || self.contains(PermissionFlags::ADMINISTRATOR) } + + pub fn to_string(&self) -> String { + self.bits().to_string() + } + + /// Creates a String of Permissions from a given [`Vec`] of [`PermissionFlags`]. + /// # Example: + /// ``` + /// use chorus::types::{PermissionFlags}; + /// + /// let mut vector: Vec = Vec::new(); + /// vector.push(PermissionFlags::MUTE_MEMBERS); + /// vector.push(PermissionFlags::DEAFEN_MEMBERS); + /// + /// let permissions: String = PermissionFlags::from_vec(vector); + /// + /// println!("The permissions string is {}.", permissions); + /// assert_eq!(permissions, "12582912".to_string()); + /// ``` + pub fn from_vec(flags: Vec) -> String { + let mut permissions: PermissionFlags = Default::default(); + for flag in flags.iter() { + permissions = permissions | flag.clone(); + } + permissions.to_string() + } } From affa1ed259d0bcbfcbfd16e6c77936a3f94f3285 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 9 Jun 2023 21:35:15 +0200 Subject: [PATCH 05/12] Update test --- tests/roles.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/roles.rs b/tests/roles.rs index b34bdd7..4a21964 100644 --- a/tests/roles.rs +++ b/tests/roles.rs @@ -5,9 +5,11 @@ use chorus::types::{self, RoleCreateModifySchema}; #[tokio::test] async fn create_and_get_roles() { let mut bundle = common::setup().await; + let permissions = types::PermissionFlags::CONNECT | types::PermissionFlags::MANAGE_EVENTS; + let permissions = Some(permissions.to_string()); let role_create_schema: types::RoleCreateModifySchema = RoleCreateModifySchema { name: Some("cool person".to_string()), - permissions: Some("2251804225".to_string()), + permissions, hoist: Some(true), icon: None, unicode_emoji: Some("".to_string()), From ce59beab3a35a1d466f8817433eaaacb7decaed4 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Fri, 9 Jun 2023 23:41:40 +0200 Subject: [PATCH 06/12] create member.rs --- src/api/guilds/member.rs | 1 + src/api/guilds/mod.rs | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 src/api/guilds/member.rs diff --git a/src/api/guilds/member.rs b/src/api/guilds/member.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/api/guilds/member.rs @@ -0,0 +1 @@ + diff --git a/src/api/guilds/mod.rs b/src/api/guilds/mod.rs index b06487d..1138a50 100644 --- a/src/api/guilds/mod.rs +++ b/src/api/guilds/mod.rs @@ -1,5 +1,7 @@ pub mod guilds; +pub mod member; pub mod roles; pub use guilds::*; pub use roles::*; +pub use roles::*; From e4fb36d91425c7f50bac37aed5d7f36478cfe6fa Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 10 Jun 2023 00:03:31 +0200 Subject: [PATCH 07/12] Implement GuildMember::add_role() --- src/api/guilds/member.rs | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/api/guilds/member.rs b/src/api/guilds/member.rs index 8b13789..56aaedb 100644 --- a/src/api/guilds/member.rs +++ b/src/api/guilds/member.rs @@ -1 +1,48 @@ +use reqwest::Client; +use crate::{instance::UserMeta, limit::LimitedRequester, types}; + +impl types::GuildMember { + /// Adds a role to a guild member. + /// + /// # Arguments + /// + /// * `user` - A mutable reference to a `UserMeta` instance. + /// * `guild_id` - The ID of the guild. + /// * `member_id` - The ID of the member. + /// * `role_id` - The ID of the role to add. + /// + /// # Returns + /// + /// An `Option` containing a `ChorusLibError` if the request fails, or `None` if the request succeeds. + pub async fn add_role( + user: &mut UserMeta, + guild_id: &str, + member_id: &str, + role_id: &str, + ) -> Option { + let mut belongs_to = user.belongs_to.borrow_mut(); + let url = format!( + "{}/guilds/{}/members/{}/roles/{}/", + belongs_to.urls.get_api(), + guild_id, + member_id, + role_id + ); + let request = Client::new().put(url).bearer_auth(user.token()); + let response = LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Guild, + &mut belongs_to.limits, + &mut user.limits, + ) + .await; + if response.is_err() { + return Some(response.err().unwrap()); + } else { + return None; + } + } +} From 9fb6c8c6f98dbff48bdfb98e766819c16ff6ea29 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 10 Jun 2023 00:10:12 +0200 Subject: [PATCH 08/12] implement GuildMember::remove_role() --- src/api/guilds/member.rs | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/api/guilds/member.rs b/src/api/guilds/member.rs index 56aaedb..b301b99 100644 --- a/src/api/guilds/member.rs +++ b/src/api/guilds/member.rs @@ -45,4 +45,47 @@ impl types::GuildMember { return None; } } + + /// Removes a role from a guild member. + /// + /// # Arguments + /// + /// * `user` - A mutable reference to a `UserMeta` instance. + /// * `guild_id` - The ID of the guild. + /// * `member_id` - The ID of the member. + /// * `role_id` - The ID of the role to remove. + /// + /// # Returns + /// + /// An `Option` containing a `ChorusLibError` if the request fails, or `None` if the request succeeds. + pub async fn remove_role( + user: &mut UserMeta, + guild_id: &str, + member_id: &str, + role_id: &str, + ) -> Option { + let mut belongs_to = user.belongs_to.borrow_mut(); + let url = format!( + "{}/guilds/{}/members/{}/roles/{}/", + belongs_to.urls.get_api(), + guild_id, + member_id, + role_id + ); + let request = Client::new().delete(url).bearer_auth(user.token()); + let response = LimitedRequester::new() + .await + .send_request( + request, + crate::api::limits::LimitType::Guild, + &mut belongs_to.limits, + &mut user.limits, + ) + .await; + if response.is_err() { + return Some(response.err().unwrap()); + } else { + return None; + } + } } From 0887ba1019f0eb3a463cb8ec52ec1eec9562d0e8 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 10 Jun 2023 00:23:49 +0200 Subject: [PATCH 09/12] Add role to test bundle --- tests/common/mod.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 4b20399..c58c79a 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,6 +1,9 @@ use chorus::{ instance::{Instance, UserMeta}, - types::{Channel, ChannelCreateSchema, Guild, GuildCreateSchema, RegisterSchema}, + types::{ + Channel, ChannelCreateSchema, Guild, GuildCreateSchema, RegisterSchema, + RoleCreateModifySchema, RoleObject, + }, URLBundle, }; @@ -10,6 +13,7 @@ pub struct TestBundle { pub user: UserMeta, pub instance: Instance, pub guild: Guild, + pub role: RoleObject, pub channel: Channel, } @@ -70,11 +74,27 @@ pub async fn setup() -> TestBundle { .await .unwrap(); + let role_create_schema: chorus::types::RoleCreateModifySchema = RoleCreateModifySchema { + name: Some("Bundle role".to_string()), + permissions: Some("8".to_string()), // Administrator permissions + hoist: Some(true), + icon: None, + unicode_emoji: Some("".to_string()), + mentionable: Some(true), + position: None, + color: None, + }; + let guild_id = guild.id.clone().to_string(); + let role = chorus::types::RoleObject::create(&mut user, &guild_id, role_create_schema) + .await + .unwrap(); + TestBundle { urls, user, instance, guild, + role, channel, } } From dde43d9752a70f6eb67690527f54f7b06cef1769 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 10 Jun 2023 00:24:08 +0200 Subject: [PATCH 10/12] Change test due to common.rs changing --- tests/roles.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/roles.rs b/tests/roles.rs index 4a21964..3eee2b8 100644 --- a/tests/roles.rs +++ b/tests/roles.rs @@ -27,7 +27,7 @@ async fn create_and_get_roles() { .unwrap() .unwrap() .iter() - .nth(1) + .nth(2) .unwrap() .clone(); From 972100af65f086cb5728da0e36fb7834361a7692 Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 10 Jun 2023 00:35:51 +0200 Subject: [PATCH 11/12] Change UserMeta: User instead of Option I do not know why I have made it optional in the first place. hm --- src/api/auth/login.rs | 2 +- src/api/auth/register.rs | 2 +- src/api/users/users.rs | 5 +---- src/instance.rs | 4 ++-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/api/auth/login.rs b/src/api/auth/login.rs index 2481cd6..55d7799 100644 --- a/src/api/auth/login.rs +++ b/src/api/auth/login.rs @@ -63,7 +63,7 @@ pub mod login { login_result.token, cloned_limits, login_result.settings, - Some(object), + object, ); Ok(user) diff --git a/src/api/auth/register.rs b/src/api/auth/register.rs index 8ca4735..d961fbf 100644 --- a/src/api/auth/register.rs +++ b/src/api/auth/register.rs @@ -71,7 +71,7 @@ pub mod register { token.clone(), cloned_limits, settings, - Some(user_object), + user_object, ); Ok(user) } diff --git a/src/api/users/users.rs b/src/api/users/users.rs index ffabd3f..1d35f32 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -72,10 +72,7 @@ impl UserMeta { Err(e) => return Err(e), }; let user_updated: User = from_str(&result.text().await.unwrap()).unwrap(); - let _ = std::mem::replace( - &mut self.object.as_mut().unwrap(), - &mut user_updated.clone(), - ); + let _ = std::mem::replace(&mut self.object, user_updated.clone()); Ok(user_updated) } diff --git a/src/instance.rs b/src/instance.rs index 6121c65..524735b 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -90,7 +90,7 @@ pub struct UserMeta { pub token: String, pub limits: Limits, pub settings: UserSettings, - pub object: Option, + pub object: User, } impl UserMeta { @@ -107,7 +107,7 @@ impl UserMeta { token: String, limits: Limits, settings: UserSettings, - object: Option, + object: User, ) -> UserMeta { UserMeta { belongs_to, From a7040647fbd87bed7627e6d1ed579997c74b71dd Mon Sep 17 00:00:00 2001 From: bitfl0wer Date: Sat, 10 Jun 2023 00:39:04 +0200 Subject: [PATCH 12/12] Add incomplete add_remove_role test --- tests/member.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/member.rs diff --git a/tests/member.rs b/tests/member.rs new file mode 100644 index 0000000..f4b22fd --- /dev/null +++ b/tests/member.rs @@ -0,0 +1,13 @@ +mod common; + +#[tokio::test] +async fn add_remove_role() { + let mut bundle = common::setup().await; + let guild_id = &bundle.guild.id.to_string(); + let role_id = &bundle.role.id.to_string(); + let user_id = &bundle.user.object.id.to_string(); + chorus::types::GuildMember::add_role(&mut bundle.user, guild_id, user_id, role_id).await; + chorus::types::GuildMember::remove_role(&mut bundle.user, guild_id, user_id, role_id).await; + // TODO: Implement /guilds/{guild_id}/members/{member_id}/ GET route. + common::teardown(bundle).await +}