-[![Rust]][Rust-url]
+[![Discord]][Discord-invite]
[![Build][build-shield]][build-url]
[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
-[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
-[![GPL3 License][license-shield]][license-url]
-
+
Chorus
@@ -54,15 +52,17 @@ Core functionality:
[Rust]: https://img.shields.io/badge/Rust-orange?style=plastic&logo=rust
[Rust-url]: https://www.rust-lang.org/
-[build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/rust.yml?style=plastic
+[build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/rust.yml?style=flat
[build-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/rust.yml
-[contributors-shield]: https://img.shields.io/github/contributors/polyphony-chat/chorus.svg?style=plastic
+[contributors-shield]: https://img.shields.io/github/contributors/polyphony-chat/chorus.svg?style=flat
[contributors-url]: https://github.com/polyphony-chat/chorus/graphs/contributors
-[forks-shield]: https://img.shields.io/github/forks/polyphony-chat/chorus.svg?style=plastic
+[forks-shield]: https://img.shields.io/github/forks/polyphony-chat/chorus.svg?style=flat
[forks-url]: https://github.com/polyphony-chat/chorus/network/members
-[stars-shield]: https://img.shields.io/github/stars/polyphony-chat/chorus.svg?style=plastic
+[stars-shield]: https://img.shields.io/github/stars/polyphony-chat/chorus.svg?style=flat
[stars-url]: https://github.com/polyphony-chat/chorus/stargazers
-[issues-shield]: https://img.shields.io/github/issues/polyphony-chat/chorus.svg?style=plastic
+[issues-shield]: https://img.shields.io/github/issues/polyphony-chat/chorus.svg?style=flat
[issues-url]: https://github.com/polyphony-chat/chorus/issues
-[license-shield]: https://img.shields.io/github/license/polyphony-chat/chorus.svg?style=plastic
+[license-shield]: https://img.shields.io/github/license/polyphony-chat/chorus.svg?style=f;at
[license-url]: https://github.com/polyphony-chat/chorus/blob/master/LICENSE
+[Discord]: https://dcbadge.vercel.app/api/server/m3FpcapGDD?style=flat
+[Discord-invite]: https://discord.com/invite/m3FpcapGDD
diff --git a/images/polyphony-chorus-round-light.png b/images/polyphony-chorus-round-light.png
deleted file mode 100644
index 000cbf0..0000000
Binary files a/images/polyphony-chorus-round-light.png and /dev/null differ
diff --git a/images/polyphony-chorus-round.png b/images/polyphony-chorus-round.png
deleted file mode 100644
index 65d8b19..0000000
Binary files a/images/polyphony-chorus-round.png and /dev/null differ
diff --git a/images/polyphony-chorus.png b/images/polyphony-chorus.png
deleted file mode 100644
index 4587385..0000000
Binary files a/images/polyphony-chorus.png and /dev/null differ
diff --git a/images/polyphony-chorus8bit.png b/images/polyphony-chorus8bit.png
deleted file mode 100644
index 2d8b987..0000000
Binary files a/images/polyphony-chorus8bit.png and /dev/null differ
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 9433150..56b035d 100644
--- a/src/api/types.rs
+++ b/src/api/types.rs
@@ -341,7 +341,7 @@ pub struct RoleObject {
pub tags: Option,
}
-#[derive(Serialize, Deserialize, Debug, Default, Clone)]
+#[derive(Serialize, Deserialize, Debug, Default, Clone, Eq, PartialEq)]
/// See https://discord.com/developers/docs/topics/permissions#role-object-role-tags-structure
pub struct RoleTags {
#[serde(default)]
@@ -799,7 +799,7 @@ pub struct MessageInteraction {
pub member: Option,
}
-#[derive(Debug, Deserialize, Serialize, Clone, Default)]
+#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct GuildMember {
pub user: Option,
pub nick: Option,
@@ -815,7 +815,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")]
@@ -854,7 +854,7 @@ pub struct Channel {
pub default_forum_layout: Option,
}
-#[derive(Debug, Deserialize, Serialize, Clone)]
+#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)]
pub struct Tag {
#[serde(default)]
#[serde(deserialize_with = "deserialize_number_from_string")]
@@ -867,7 +867,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")]
@@ -881,7 +881,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,
@@ -891,7 +891,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,
@@ -941,7 +941,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 {
#[serde(default)]
#[serde(deserialize_with = "deserialize_option_number_from_string")]
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
}
}