diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs new file mode 100644 index 0000000..51552a1 --- /dev/null +++ b/src/api/channels/channels.rs @@ -0,0 +1,43 @@ +use reqwest::Client; +use serde_json::from_str; + +use crate::{ + api::{limits::Limits, types}, + errors::InstanceServerError, + limit::LimitedRequester, +}; + +impl types::Channel { + pub async fn get( + token: &str, + url_api: &str, + channel_id: &str, + limits_user: &mut Limits, + limits_instance: &mut Limits, + ) -> Result { + let request = Client::new() + .get(format!("{}/channels/{}/", url_api, channel_id)) + .bearer_auth(token); + let mut requester = LimitedRequester::new().await; + let result = match requester + .send_request( + request, + crate::api::limits::LimitType::Guild, + limits_instance, + limits_user, + ) + .await + { + Ok(result) => result, + Err(e) => return Err(e), + }; + let result_text = result.text().await.unwrap(); + match from_str::(&result_text) { + Ok(object) => Ok(object), + Err(e) => Err(InstanceServerError::RequestErrorError { + url: format!("{}/channels/{}/", url_api, channel_id), + error: e.to_string(), + }), + } + } +} diff --git a/src/api/channels/mod.rs b/src/api/channels/mod.rs index 8f05488..72f4e3e 100644 --- a/src/api/channels/mod.rs +++ b/src/api/channels/mod.rs @@ -1,3 +1,5 @@ +pub mod channels; pub mod messages; +pub use channels::*; pub use messages::*; diff --git a/src/api/guilds/guilds.rs b/src/api/guilds/guilds.rs index 5bbbd23..21140f1 100644 --- a/src/api/guilds/guilds.rs +++ b/src/api/guilds/guilds.rs @@ -1,11 +1,14 @@ +use reqwest::Client; use serde_json::from_str; use serde_json::to_string; +use crate::api::limits::Limits; use crate::api::schemas; use crate::api::types; use crate::errors::InstanceServerError; +use crate::limit::LimitedRequester; -impl<'a> types::Guild { +impl types::Guild { /// Creates a new guild with the given parameters. /// /// # Arguments @@ -113,4 +116,86 @@ impl<'a> types::Guild { None } } + + /// Sends a request to create a new channel in the guild. + /// + /// # Arguments + /// + /// * `url_api` - The base URL for the Discord API. + /// * `token` - A Discord bot token. + /// * `schema` - A `ChannelCreateSchema` struct containing the properties of the new channel. + /// * `limits_user` - A mutable reference to a `Limits` struct containing the user's rate limits. + /// * `limits_instance` - A mutable reference to a `Limits` struct containing the instance's rate limits. + /// + /// # Returns + /// + /// A `Result` containing a `reqwest::Response` if the request was successful, or an `InstanceServerError` if there was an error. + pub async fn create_channel( + &self, + url_api: &str, + token: &str, + schema: schemas::ChannelCreateSchema, + limits_user: &mut Limits, + limits_instance: &mut Limits, + ) -> Result { + types::Channel::create( + token, + url_api, + &self.id, + schema, + limits_user, + limits_instance, + ) + .await + } +} + +impl types::Channel { + /// Sends a request to create a new channel in a guild. + /// + /// # Arguments + /// + /// * `token` - A Discord bot token. + /// * `url_api` - The base URL for the Discord API. + /// * `guild_id` - The ID of the guild where the channel will be created. + /// * `schema` - A `ChannelCreateSchema` struct containing the properties of the new channel. + /// * `limits_user` - A mutable reference to a `Limits` struct containing the user's rate limits. + /// * `limits_instance` - A mutable reference to a `Limits` struct containing the instance's rate limits. + /// + /// # Returns + /// + /// A `Result` containing a `reqwest::Response` if the request was successful, or an `InstanceServerError` if there was an error. + pub async fn create( + token: &str, + url_api: &str, + guild_id: &str, + schema: schemas::ChannelCreateSchema, + limits_user: &mut Limits, + limits_instance: &mut Limits, + ) -> Result { + let request = Client::new() + .post(format!("{}/guilds/{}/channels/", url_api, guild_id)) + .bearer_auth(token) + .body(to_string(&schema).unwrap()); + let mut requester = LimitedRequester::new().await; + let result = match requester + .send_request( + request, + crate::api::limits::LimitType::Guild, + limits_instance, + limits_user, + ) + .await + { + Ok(result) => result, + Err(e) => return Err(e), + }; + match from_str::(&result.text().await.unwrap()) { + Ok(object) => Ok(object), + Err(e) => Err(InstanceServerError::RequestErrorError { + url: format!("{}/guilds/{}/channels/", url_api, guild_id), + error: e.to_string(), + }), + } + } } diff --git a/src/api/schemas.rs b/src/api/schemas.rs index e84abdf..fb1a14f 100644 --- a/src/api/schemas.rs +++ b/src/api/schemas.rs @@ -314,6 +314,31 @@ pub struct UserModifySchema { pub discriminator: Option, } +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "snake_case")] +// TODO: Implement in polyphony/types +pub struct ChannelCreateSchema { + pub name: String, + #[serde(rename = "type")] + pub channel_type: Option, + pub topic: Option, + pub icon: Option, + pub bitrate: Option, + pub user_limit: Option, + pub rate_limit_per_user: Option, + pub position: Option, + pub permission_overwrites: Option>, + pub parent_id: Option, + pub id: Option, + pub nsfw: Option, + pub rtc_region: Option, + pub default_auto_archive_duration: Option, + pub default_reaction_emoji: Option, + pub flags: Option, + pub default_thread_rate_limit_per_user: Option, + pub video_quality_mode: Option, +} + // I know that some of these tests are... really really basic and unneccessary, but sometimes, I // just feel like writing tests, so there you go :) -@bitfl0wer #[cfg(test)] diff --git a/src/api/types.rs b/src/api/types.rs index 5631130..f040dd2 100644 --- a/src/api/types.rs +++ b/src/api/types.rs @@ -319,7 +319,7 @@ pub struct RoleObject { //pub tags: Option } -#[derive(Serialize, Deserialize, Debug, Default, Clone)] +#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)] pub struct UserObject { pub id: String, username: String, @@ -722,7 +722,7 @@ pub struct MessageInteraction { pub member: Option, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)] pub struct GuildMember { pub user: Option, pub nick: Option, @@ -738,7 +738,7 @@ pub struct GuildMember { pub communication_disabled_until: Option, } -#[derive(Default, Debug, Serialize, Deserialize, Clone)] +#[derive(Default, Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct Channel { pub id: String, #[serde(rename = "type")] @@ -777,7 +777,7 @@ pub struct Channel { pub default_forum_layout: Option, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)] pub struct Tag { pub id: u64, pub name: String, @@ -786,7 +786,7 @@ pub struct Tag { pub emoji_name: Option, } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] pub struct PermissionOverwrite { pub id: String, #[serde(rename = "type")] @@ -795,7 +795,7 @@ pub struct PermissionOverwrite { pub deny: String, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)] pub struct ThreadMetadata { pub archived: bool, pub auto_archive_duration: i32, @@ -805,7 +805,7 @@ pub struct ThreadMetadata { pub create_timestamp: Option, } -#[derive(Default, Debug, Deserialize, Serialize, Clone)] +#[derive(Default, Debug, Deserialize, Serialize, Clone, Eq, PartialEq)] pub struct ThreadMember { pub id: Option, pub user_id: Option, @@ -855,7 +855,7 @@ pub struct StageInstance { pub guild_scheduled_event_id: Option, } -#[derive(Debug, Deserialize, Serialize, Clone)] +#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)] pub struct DefaultReaction { pub emoji_id: Option, pub emoji_name: Option, diff --git a/tests/integration.rs b/tests/integration.rs index e004496..045dc08 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -1,5 +1,6 @@ use chorus::{ - api::{AuthUsername, RegisterSchema, User}, + api::schemas, + api::{AuthUsername, Channel, Guild, GuildCreateSchema, RegisterSchema, User}, instance::Instance, URLBundle, }; @@ -8,6 +9,9 @@ use chorus::{ struct TestBundle { urls: URLBundle, user: User, + instance: Instance, + guild_id: String, + channel: Channel, } // Set up a test by creating an Instance and a User. Reduces Test boilerplate. @@ -32,18 +36,72 @@ async fn setup() -> TestBundle { None, ) .unwrap(); - let user = instance.register_account(®).await.unwrap(); + let guild_create_schema = GuildCreateSchema { + name: Some("Test-Guild!".to_string()), + region: None, + icon: None, + channels: None, + guild_template_code: None, + system_channel_id: None, + rules_channel_id: None, + }; + let channel_create_schema = schemas::ChannelCreateSchema { + name: "testchannel".to_string(), + channel_type: Some(0), + topic: None, + icon: None, + bitrate: None, + user_limit: None, + rate_limit_per_user: None, + position: None, + permission_overwrites: None, + parent_id: None, + id: None, + nsfw: Some(false), + rtc_region: None, + default_auto_archive_duration: None, + default_reaction_emoji: None, + flags: Some(0), + default_thread_rate_limit_per_user: Some(0), + video_quality_mode: None, + }; + let mut user = instance.register_account(®).await.unwrap(); + let guild_id = Guild::create(&mut user, urls.get_api(), guild_create_schema) + .await + .unwrap(); + let channel = Channel::create( + &user.token, + urls.get_api(), + guild_id.as_str(), + channel_create_schema, + &mut user.limits, + &mut instance.limits, + ) + .await + .unwrap(); - TestBundle { urls, user } + TestBundle { + urls, + user, + instance, + guild_id, + channel, + } } // Teardown method to clean up after a test. -async fn teardown(bundle: TestBundle) { +async fn teardown(mut bundle: TestBundle) { + Guild::delete( + &mut bundle.user, + bundle.instance.urls.get_api(), + bundle.guild_id, + ) + .await; bundle.user.delete().await; } mod guild { - use chorus::api::{schemas, types}; + use chorus::api::{schemas, types, Channel}; #[tokio::test] async fn guild_creation_deletion() { @@ -70,5 +128,27 @@ mod guild { None => assert!(true), Some(_) => assert!(false), } + crate::teardown(bundle).await + } + + #[tokio::test] + async fn get_channel() { + let mut bundle = crate::setup().await; + let bundle_channel = bundle.channel.clone(); + let bundle_user = &mut bundle.user; + + assert_eq!( + bundle_channel, + Channel::get( + bundle_user.token.as_str(), + bundle.instance.urls.get_api(), + &bundle_channel.id, + &mut bundle_user.limits, + &mut bundle.instance.limits + ) + .await + .unwrap() + ); + crate::teardown(bundle).await } }