diff --git a/.github/workflows/rust.yml b/.github/workflows/build_and_test.yml similarity index 96% rename from .github/workflows/rust.yml rename to .github/workflows/build_and_test.yml index 9b39ddf..4e98355 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/build_and_test.yml @@ -1,4 +1,4 @@ -name: Rust +name: Build and Test on: push: @@ -10,7 +10,7 @@ env: CARGO_TERM_COLOR: always jobs: - build_and_test: + rust: runs-on: ubuntu-latest diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml new file mode 100644 index 0000000..ba12407 --- /dev/null +++ b/.github/workflows/clippy.yml @@ -0,0 +1,20 @@ +name: Clippy check + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + + +# Make sure CI fails on all warnings, including Clippy lints +env: + RUSTFLAGS: "-Dwarnings" + +jobs: + clippy_check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Run Clippy + run: cargo clippy --all-targets --all-features \ No newline at end of file diff --git a/README.md b/README.md index b239410..206d7f9 100644 --- a/README.md +++ b/README.md @@ -93,9 +93,6 @@ - [x] Sending rich content in messages (links, images, videos) - [ ] Customizing embed appearance (title, description, color, fields) -### Notifications and Push Notifications -- [ ] Notification settings management - ### Webhooks - [ ] Webhook creation and management - [ ] Handling incoming webhook events @@ -107,8 +104,10 @@ [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=flat -[build-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/rust.yml +[build-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/build_and_test.yml?style=flat +[build-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/build_and_test.yml +[clippy-shield]: https://img.shields.io/github/actions/workflow/status/polyphony-chat/chorus/clippy.yml?style=flat +[clippy-url]: https://github.com/polyphony-chat/chorus/blob/main/.github/workflows/clippy.yml [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=flat diff --git a/examples/gateway_observers.rs b/examples/gateway_observers.rs index 166b84a..6e71751 100644 --- a/examples/gateway_observers.rs +++ b/examples/gateway_observers.rs @@ -3,8 +3,8 @@ use chorus::{ gateway::{Gateway, Observer}, types::{GatewayIdentifyPayload, GatewayReady}, }; -use std::sync::Arc; -use tokio::{self, sync::Mutex}; +use std::{sync::Arc, time::Duration}; +use tokio::{self, sync::Mutex, time::sleep}; // This example creates a simple gateway connection and a basic observer struct @@ -54,5 +54,7 @@ async fn main() { gateway.send_identify(identify).await; // Do something on the main thread so we don't quit - loop {} + loop { + sleep(Duration::MAX).await; + } } diff --git a/examples/gateway_simple.rs b/examples/gateway_simple.rs index c346839..26e8416 100644 --- a/examples/gateway_simple.rs +++ b/examples/gateway_simple.rs @@ -1,4 +1,7 @@ +use std::time::Duration; + use chorus::{self, gateway::Gateway, types::GatewayIdentifyPayload}; +use tokio::time::sleep; /// This example creates a simple gateway connection and a session with an Identify event #[tokio::main] @@ -26,5 +29,7 @@ async fn main() { gateway.send_identify(identify).await; // Do something on the main thread so we don't quit - loop {} + loop { + sleep(Duration::MAX).await; + } } diff --git a/src/api/channels/channels.rs b/src/api/channels/channels.rs index 32d9c3a..391f5f1 100644 --- a/src/api/channels/channels.rs +++ b/src/api/channels/channels.rs @@ -57,11 +57,7 @@ impl Channel { drop(belongs_to); let response = common::handle_request(request, user, crate::api::limits::LimitType::Channel).await; - if response.is_err() { - return Some(response.err().unwrap()); - } else { - return None; - } + response.err() } /// Modifies a channel. diff --git a/src/api/common.rs b/src/api/common.rs index 0ca9063..60fd263 100644 --- a/src/api/common.rs +++ b/src/api/common.rs @@ -13,17 +13,13 @@ pub async fn handle_request( limit_type: LimitType, ) -> Result { let mut belongs_to = user.belongs_to.borrow_mut(); - match LimitedRequester::send_request( + LimitedRequester::send_request( request, limit_type, &mut belongs_to.limits, &mut user.limits, ) .await - { - Ok(response) => return Ok(response), - Err(e) => return Err(e), - } } /// Sends a request to wherever it needs to go. Returns [`None`] on success and diff --git a/src/api/policies/instance/limits.rs b/src/api/policies/instance/limits.rs index 98e0fc8..4ab17f5 100644 --- a/src/api/policies/instance/limits.rs +++ b/src/api/policies/instance/limits.rs @@ -195,31 +195,31 @@ pub mod limits { pub fn get_limit_ref(&self, limit_type: &LimitType) -> &Limit { match limit_type { - &LimitType::AbsoluteMessage => self.limit_absolute_messages, - &LimitType::AbsoluteRegister => self.limit_absolute_register, - &LimitType::AuthLogin => self.limit_auth_login, - &LimitType::AuthRegister => self.limit_auth_register, - &LimitType::Channel => self.limit_channel, - &LimitType::Error => self.limit_error, - &LimitType::Global => self.limit_global, - &LimitType::Guild => self.limit_guild, - &LimitType::Ip => self.limit_ip, - &LimitType::Webhook => self.limit_webhook, + LimitType::AbsoluteMessage => self.limit_absolute_messages, + LimitType::AbsoluteRegister => self.limit_absolute_register, + LimitType::AuthLogin => self.limit_auth_login, + LimitType::AuthRegister => self.limit_auth_register, + LimitType::Channel => self.limit_channel, + LimitType::Error => self.limit_error, + LimitType::Global => self.limit_global, + LimitType::Guild => self.limit_guild, + LimitType::Ip => self.limit_ip, + LimitType::Webhook => self.limit_webhook, } } pub fn get_limit_mut_ref(&mut self, limit_type: &LimitType) -> &mut Limit { match limit_type { - &LimitType::AbsoluteMessage => self.limit_absolute_messages, - &LimitType::AbsoluteRegister => self.limit_absolute_register, - &LimitType::AuthLogin => self.limit_auth_login, - &LimitType::AuthRegister => self.limit_auth_register, - &LimitType::Channel => self.limit_channel, - &LimitType::Error => self.limit_error, - &LimitType::Global => self.limit_global, - &LimitType::Guild => self.limit_guild, - &LimitType::Ip => self.limit_ip, - &LimitType::Webhook => self.limit_webhook, + LimitType::AbsoluteMessage => self.limit_absolute_messages, + LimitType::AbsoluteRegister => self.limit_absolute_register, + LimitType::AuthLogin => self.limit_auth_login, + LimitType::AuthRegister => self.limit_auth_register, + LimitType::Channel => self.limit_channel, + LimitType::Error => self.limit_error, + LimitType::Global => self.limit_global, + LimitType::Guild => self.limit_guild, + LimitType::Ip => self.limit_ip, + LimitType::Webhook => self.limit_webhook, } } } @@ -256,31 +256,31 @@ pub mod limits { pub fn get_limit_ref(&self, limit_type: &LimitType) -> &Limit { match limit_type { - &LimitType::AbsoluteMessage => &self.limit_absolute_messages, - &LimitType::AbsoluteRegister => &self.limit_absolute_register, - &LimitType::AuthLogin => &self.limit_auth_login, - &LimitType::AuthRegister => &self.limit_auth_register, - &LimitType::Channel => &self.limit_channel, - &LimitType::Error => &self.limit_error, - &LimitType::Global => &self.limit_global, - &LimitType::Guild => &self.limit_guild, - &LimitType::Ip => &self.limit_ip, - &LimitType::Webhook => &self.limit_webhook, + LimitType::AbsoluteMessage => &self.limit_absolute_messages, + LimitType::AbsoluteRegister => &self.limit_absolute_register, + LimitType::AuthLogin => &self.limit_auth_login, + LimitType::AuthRegister => &self.limit_auth_register, + LimitType::Channel => &self.limit_channel, + LimitType::Error => &self.limit_error, + LimitType::Global => &self.limit_global, + LimitType::Guild => &self.limit_guild, + LimitType::Ip => &self.limit_ip, + LimitType::Webhook => &self.limit_webhook, } } pub fn get_limit_mut_ref(&mut self, limit_type: &LimitType) -> &mut Limit { match limit_type { - &LimitType::AbsoluteMessage => &mut self.limit_absolute_messages, - &LimitType::AbsoluteRegister => &mut self.limit_absolute_register, - &LimitType::AuthLogin => &mut self.limit_auth_login, - &LimitType::AuthRegister => &mut self.limit_auth_register, - &LimitType::Channel => &mut self.limit_channel, - &LimitType::Error => &mut self.limit_error, - &LimitType::Global => &mut self.limit_global, - &LimitType::Guild => &mut self.limit_guild, - &LimitType::Ip => &mut self.limit_ip, - &LimitType::Webhook => &mut self.limit_webhook, + LimitType::AbsoluteMessage => &mut self.limit_absolute_messages, + LimitType::AbsoluteRegister => &mut self.limit_absolute_register, + LimitType::AuthLogin => &mut self.limit_auth_login, + LimitType::AuthRegister => &mut self.limit_auth_register, + LimitType::Channel => &mut self.limit_channel, + LimitType::Error => &mut self.limit_error, + LimitType::Global => &mut self.limit_global, + LimitType::Guild => &mut self.limit_guild, + LimitType::Ip => &mut self.limit_ip, + LimitType::Webhook => &mut self.limit_webhook, } } diff --git a/src/api/users/users.rs b/src/api/users/users.rs index 166bdd8..8423e01 100644 --- a/src/api/users/users.rs +++ b/src/api/users/users.rs @@ -54,7 +54,7 @@ impl UserMeta { let request = Client::new() .patch(format!( "{}/users/@me/", - self.belongs_to.borrow_mut().urls.get_api() + self.belongs_to.borrow().urls.get_api() )) .body(to_string(&modify_schema).unwrap()) .bearer_auth(self.token()); @@ -103,12 +103,11 @@ impl User { limits_instance: &mut Limits, id: Option<&String>, ) -> Result { - let url: String; - if id.is_none() { - url = format!("{}/users/@me/", url_api); + let url = if id.is_none() { + format!("{}/users/@me/", url_api) } else { - url = format!("{}/users/{}", url_api, id.unwrap()); - } + format!("{}/users/{}", url_api, id.unwrap()) + }; let request = reqwest::Client::new().get(url).bearer_auth(token); let mut cloned_limits = limits_instance.clone(); match LimitedRequester::send_request( @@ -166,12 +165,6 @@ impl Instance { token: String, id: Option<&String>, ) -> Result { - User::_get( - &token, - &self.urls.get_api().to_string(), - &mut self.limits, - id, - ) - .await + User::_get(&token, self.urls.get_api(), &mut self.limits, id).await } } diff --git a/src/gateway.rs b/src/gateway.rs index a765702..28ed702 100644 --- a/src/gateway.rs +++ b/src/gateway.rs @@ -94,60 +94,36 @@ impl GatewayMessage { let content = self.message.to_string(); // Some error strings have dots on the end, which we don't care about - let processed_content = content.clone().to_lowercase().replace(".", ""); + let processed_content = content.to_lowercase().replace('.', ""); match processed_content.as_str() { - "unknown error" | "4000" => { - return Some(GatewayError::UnknownError); - } - "unknown opcode" | "4001" => { - return Some(GatewayError::UnknownOpcodeError); - } + "unknown error" | "4000" => Some(GatewayError::UnknownError), + "unknown opcode" | "4001" => Some(GatewayError::UnknownOpcodeError), "decode error" | "error while decoding payload" | "4002" => { - return Some(GatewayError::DecodeError); - } - "not authenticated" | "4003" => { - return Some(GatewayError::NotAuthenticatedError); - } - "authentication failed" | "4004" => { - return Some(GatewayError::AuthenticationFailedError); - } - "already authenticated" | "4005" => { - return Some(GatewayError::AlreadyAuthenticatedError); - } - "invalid seq" | "4007" => { - return Some(GatewayError::InvalidSequenceNumberError); - } - "rate limited" | "4008" => { - return Some(GatewayError::RateLimitedError); - } - "session timed out" | "4009" => { - return Some(GatewayError::SessionTimedOutError); - } - "invalid shard" | "4010" => { - return Some(GatewayError::InvalidShardError); - } - "sharding required" | "4011" => { - return Some(GatewayError::ShardingRequiredError); - } - "invalid api version" | "4012" => { - return Some(GatewayError::InvalidAPIVersionError); + Some(GatewayError::DecodeError) } + "not authenticated" | "4003" => Some(GatewayError::NotAuthenticatedError), + "authentication failed" | "4004" => Some(GatewayError::AuthenticationFailedError), + "already authenticated" | "4005" => Some(GatewayError::AlreadyAuthenticatedError), + "invalid seq" | "4007" => Some(GatewayError::InvalidSequenceNumberError), + "rate limited" | "4008" => Some(GatewayError::RateLimitedError), + "session timed out" | "4009" => Some(GatewayError::SessionTimedOutError), + "invalid shard" | "4010" => Some(GatewayError::InvalidShardError), + "sharding required" | "4011" => Some(GatewayError::ShardingRequiredError), + "invalid api version" | "4012" => Some(GatewayError::InvalidAPIVersionError), "invalid intent(s)" | "invalid intent" | "4013" => { - return Some(GatewayError::InvalidIntentsError); + Some(GatewayError::InvalidIntentsError) } "disallowed intent(s)" | "disallowed intents" | "4014" => { - return Some(GatewayError::DisallowedIntentsError); - } - _ => { - return None; + Some(GatewayError::DisallowedIntentsError) } + _ => None, } } /// Returns whether or not the message is an error pub fn is_error(&self) -> bool { - return self.error().is_some(); + self.error().is_some() } /// Parses the message as a payload; @@ -168,7 +144,7 @@ impl GatewayMessage { /// Returns whether or not the message is empty pub fn is_empty(&self) -> bool { - return self.message.is_empty(); + self.message.is_empty() } } @@ -308,6 +284,7 @@ pub struct Gateway { } impl Gateway { + #[allow(clippy::new_ret_no_self)] pub async fn new(websocket_url: String) -> Result { let (websocket_stream, _) = match connect_async_tls_with_config( &websocket_url, @@ -371,13 +348,13 @@ impl Gateway { gateway.gateway_listen_task().await; }); - return Ok(GatewayHandle { + Ok(GatewayHandle { url: websocket_url.clone(), events: shared_events, websocket_send: shared_websocket_send.clone(), handle, kill_send: kill_send.clone(), - }); + }) } /// The main gateway listener task; @@ -388,14 +365,10 @@ impl Gateway { let msg = self.websocket_receive.next().await; // This if chain can be much better but if let is unstable on stable rust - if msg.as_ref().is_some() { - if msg.as_ref().unwrap().is_ok() { - let msg_unwrapped = msg.unwrap().unwrap(); - self.handle_message(GatewayMessage::from_tungstenite_message(msg_unwrapped)) - .await; - - continue; - } + if let Some(Ok(message)) = msg { + self.handle_message(GatewayMessage::from_tungstenite_message(message)) + .await; + continue; } // We couldn't receive the next message or it was an error, something is wrong with the websocket, close @@ -423,7 +396,7 @@ impl Gateway { } event.update_data(data_deserialize_result.unwrap()).await; - return Ok(()); + Ok(()) } /// This handles a message as a websocket event and updates its events along with the events' observers @@ -1773,7 +1746,7 @@ impl GatewayEvent { // The usage of the debug format to compare the generic T of observers is quite stupid, but the only thing to compare between them is T and if T == T they are the same // anddd there is no way to do that without using format self.observers - .retain(|obs| !(format!("{:?}", obs) == format!("{:?}", &observable))); + .retain(|obs| format!("{:?}", obs) != format!("{:?}", &observable)); self.is_observed = !self.observers.is_empty(); } @@ -1998,12 +1971,12 @@ mod example { let arc_mut_second_consumer = Arc::new(Mutex::new(second_consumer)); match event.subscribe(arc_mut_second_consumer.clone()).err() { - None => assert!(false), + None => panic!(), Some(err) => println!("You cannot subscribe twice: {}", err), } event.unsubscribe(arc_mut_consumer.clone()); - event.subscribe(arc_mut_second_consumer.clone()).unwrap(); + event.subscribe(arc_mut_second_consumer).unwrap(); } } diff --git a/src/instance.rs b/src/instance.rs index 42b7298..cc29c99 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -29,17 +29,8 @@ impl Instance { pub async fn new(urls: URLBundle) -> Result { let mut instance = Instance { urls: urls.clone(), - instance_info: GeneralConfiguration::new( - // This is okay, because the instance_info will be overwritten by the instance_policies_schema() function. - "".to_string(), - None, - None, - None, - None, - None, - None, - None, - ), + // Will be overwritten in the next step + instance_info: GeneralConfiguration::default(), limits: Limits::check_limits(urls.api).await, }; instance.instance_info = match instance.general_configuration_schema().await { diff --git a/src/lib.rs b/src/lib.rs index 2e25d3d..06cbb81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::module_inception)] + use url::{ParseError, Url}; #[cfg(feature = "client")] diff --git a/src/limit.rs b/src/limit.rs index 8fa5767..2857449 100644 --- a/src/limit.rs +++ b/src/limit.rs @@ -82,13 +82,11 @@ impl LimitedRequester { ); if !response.status().is_success() { match response.status().as_u16() { - 401 => return Err(ChorusLibError::TokenExpired), - 403 => return Err(ChorusLibError::TokenExpired), - _ => { - return Err(ChorusLibError::ReceivedErrorCodeError { - error_code: response.status().as_str().to_string(), - }); - } + 401 => Err(ChorusLibError::TokenExpired), + 403 => Err(ChorusLibError::TokenExpired), + _ => Err(ChorusLibError::ReceivedErrorCodeError { + error_code: response.status().as_str().to_string(), + }), } } else { Ok(response) @@ -286,14 +284,7 @@ mod rate_limit { .await, ); } - if request.is_some() { - match request.unwrap() { - Ok(_) => assert!(false), - Err(_) => assert!(true), - } - } else { - assert!(false) - } + assert!(matches!(request, Some(Err(_)))); } #[tokio::test] diff --git a/src/types/config/types/general_configuration.rs b/src/types/config/types/general_configuration.rs index a3c8f65..07444b0 100644 --- a/src/types/config/types/general_configuration.rs +++ b/src/types/config/types/general_configuration.rs @@ -31,27 +31,3 @@ impl Default for GeneralConfiguration { } } } - -impl GeneralConfiguration { - pub fn new( - instance_name: String, - instance_description: Option, - front_page: Option, - tos_page: Option, - correspondence_email: Option, - correspondence_user_id: Option, - image: Option, - instance_id: Option, - ) -> Self { - Self { - instance_name, - instance_description, - front_page, - tos_page, - correspondence_email, - correspondence_user_id, - image, - instance_id, - } - } -} diff --git a/src/types/config/types/guild_configuration.rs b/src/types/config/types/guild_configuration.rs index 4fedf51..a854460 100644 --- a/src/types/config/types/guild_configuration.rs +++ b/src/types/config/types/guild_configuration.rs @@ -1,4 +1,5 @@ use std::fmt::{Display, Formatter}; +#[cfg(feature = "sqlx")] use std::io::Write; use std::ops::{Deref, DerefMut}; use std::str::FromStr; diff --git a/src/types/entities/application.rs b/src/types/entities/application.rs index e5c4a01..6cac20b 100644 --- a/src/types/entities/application.rs +++ b/src/types/entities/application.rs @@ -1,4 +1,4 @@ -use bitflags::{bitflags, Flags}; +use bitflags::bitflags; use serde::{Deserialize, Serialize}; use serde_json::Value; use serde_repr::{Deserialize_repr, Serialize_repr}; diff --git a/src/types/entities/role.rs b/src/types/entities/role.rs index 7f527be..1719d28 100644 --- a/src/types/entities/role.rs +++ b/src/types/entities/role.rs @@ -108,6 +108,7 @@ impl PermissionFlags { self.contains(permission) || self.contains(PermissionFlags::ADMINISTRATOR) } + #[allow(clippy::inherent_to_string)] pub fn to_string(&self) -> String { self.bits().to_string() } @@ -129,7 +130,7 @@ impl PermissionFlags { pub fn from_vec(flags: Vec) -> String { let mut permissions: PermissionFlags = Default::default(); for flag in flags.iter() { - permissions = permissions | flag.clone(); + permissions |= flag.clone(); } permissions.to_string() } diff --git a/src/types/events/identify.rs b/src/types/events/identify.rs index dcd3a8a..35e1f78 100644 --- a/src/types/events/identify.rs +++ b/src/types/events/identify.rs @@ -51,16 +51,18 @@ impl GatewayIdentifyPayload { impl GatewayIdentifyPayload { /// Creates an identify payload with the same default capabilities as the official client pub fn default_w_client_capabilities() -> Self { - let mut def = Self::default(); - def.capabilities = Some(8189); // Default capabilities for a client - def + Self { + capabilities: Some(8189), // Default capabilities for a client + ..Self::default() + } } /// Creates an identify payload with all possible capabilities pub fn default_w_all_capabilities() -> Self { - let mut def = Self::default(); - def.capabilities = Some(i32::MAX); // Since discord uses bitwise for capabilities, this has almost every bit as 1, so all capabilities - def + Self { + capabilities: Some(i32::MAX), // Since discord uses bitwise for capabilities, this has almost every bit as 1, so all capabilities + ..Self::default() + } } } @@ -148,22 +150,18 @@ impl GatewayIdentifyConnectionProps { /// Returns the most common connection props so we can't be tracked pub fn common() -> Self { - let mut default = Self::minimal(); - - // See https://www.useragents.me/#most-common-desktop-useragents - // 25% of the web - //default.browser_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36".to_string(); - default.browser = String::from("Chrome"); - default.browser_version = String::from("113.0.0.0"); - - default.system_locale = String::from("en-US"); - - default.os = String::from("Windows"); - default.os_version = Some(String::from("10")); - - default.client_build_number = 199933; - default.release_channel = String::from("stable"); - - return default; + Self { + // See https://www.useragents.me/#most-common-desktop-useragents + // 25% of the web + //default.browser_user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36".to_string(); + browser: String::from("Chrome"), + browser_version: String::from("113.0.0.0"), + system_locale: String::from("en-US"), + os: String::from("Windows"), + os_version: Some(String::from("10")), + client_build_number: 199933, + release_channel: String::from("stable"), + ..Self::minimal() + } } } diff --git a/src/types/events/presence.rs b/src/types/events/presence.rs index 93afbf5..ad06954 100644 --- a/src/types/events/presence.rs +++ b/src/types/events/presence.rs @@ -1,5 +1,5 @@ use crate::types::{events::WebSocketEvent, UserStatus}; -use crate::types::{Activity, PublicUser, Snowflake}; +use crate::types::{Activity, ClientStatusObject, PublicUser, Snowflake}; use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize, Serialize, Default, Clone)] @@ -26,12 +26,4 @@ pub struct PresenceUpdate { pub client_status: ClientStatusObject, } -#[derive(Debug, Deserialize, Serialize, Default, Clone)] -/// See https://discord.com/developers/docs/topics/gateway-events#client-status-object -pub struct ClientStatusObject { - pub desktop: Option, - pub mobile: Option, - pub web: Option, -} - impl WebSocketEvent for PresenceUpdate {} diff --git a/src/types/schema/auth.rs b/src/types/schema/auth.rs index fc7a1ad..8b8a601 100644 --- a/src/types/schema/auth.rs +++ b/src/types/schema/auth.rs @@ -116,9 +116,39 @@ pub struct RegisterSchema { promotional_email_opt_in: Option, } +pub struct RegisterSchemaOptions { + pub username: String, + pub password: Option, + pub consent: bool, + pub email: Option, + pub fingerprint: Option, + pub invite: Option, + pub date_of_birth: Option, + pub gift_code_sku_id: Option, + pub captcha_key: Option, + pub promotional_email_opt_in: Option, +} + impl RegisterSchema { + pub fn builder(username: impl Into, consent: bool) -> RegisterSchemaOptions { + RegisterSchemaOptions { + username: username.into(), + password: None, + consent, + email: None, + fingerprint: None, + invite: None, + date_of_birth: None, + gift_code_sku_id: None, + captcha_key: None, + promotional_email_opt_in: None, + } + } +} + +impl RegisterSchemaOptions { /** - Returns a new [`Result`]. + Create a new [`RegisterSchema`]. ## Arguments All but "String::username" and "bool::consent" are optional. @@ -129,47 +159,36 @@ impl RegisterSchema { These constraints have been defined [in the Spacebar-API](https://docs.spacebar.chat/routes/) */ - pub fn new( - username: String, - password: Option, - consent: bool, - email: Option, - fingerprint: Option, - invite: Option, - date_of_birth: Option, - gift_code_sku_id: Option, - captcha_key: Option, - promotional_email_opt_in: Option, - ) -> Result { - let username = AuthUsername::new(username)?.username; + pub fn build(self) -> Result { + let username = AuthUsername::new(self.username)?.username; - let email = if let Some(email) = email { + let email = if let Some(email) = self.email { Some(AuthEmail::new(email)?.email) } else { None }; - let password = if let Some(password) = password { + let password = if let Some(password) = self.password { Some(AuthPassword::new(password)?.password) } else { None }; - if !consent { + if !self.consent { return Err(FieldFormatError::ConsentError); } Ok(RegisterSchema { username, password, - consent, + consent: self.consent, email, - fingerprint, - invite, - date_of_birth, - gift_code_sku_id, - captcha_key, - promotional_email_opt_in, + fingerprint: self.fingerprint, + invite: self.invite, + date_of_birth: self.date_of_birth, + gift_code_sku_id: self.gift_code_sku_id, + captcha_key: self.captcha_key, + promotional_email_opt_in: self.promotional_email_opt_in, }) } } diff --git a/src/types/schema/message.rs b/src/types/schema/message.rs index 7ff27f1..e1abdf7 100644 --- a/src/types/schema/message.rs +++ b/src/types/schema/message.rs @@ -4,47 +4,18 @@ use crate::types::entities::{ AllowedMention, Component, Embed, MessageReference, PartialDiscordFileAttachment, }; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Default, Deserialize, Serialize)] #[serde(rename_all = "snake_case")] pub struct MessageSendSchema { #[serde(rename = "type")] - message_type: Option, - content: Option, - nonce: Option, - tts: Option, - embeds: Option>, - allowed_mentions: Option, - message_reference: Option, - components: Option>, - sticker_ids: Option>, + pub message_type: Option, + pub content: Option, + pub nonce: Option, + pub tts: Option, + pub embeds: Option>, + pub allowed_mentions: Option, + pub message_reference: Option, + pub components: Option>, + pub sticker_ids: Option>, pub attachments: Option>, } - -// make a new() method for MessageSendSchema -impl MessageSendSchema { - pub fn new( - message_type: Option, - content: Option, - nonce: Option, - tts: Option, - embeds: Option>, - allowed_mentions: Option, - message_reference: Option, - components: Option>, - sticker_ids: Option>, - attachments: Option>, - ) -> MessageSendSchema { - MessageSendSchema { - message_type, - content, - nonce, - tts, - embeds, - allowed_mentions, - message_reference, - components, - sticker_ids, - attachments, - } - } -} diff --git a/src/types/schema/mod.rs b/src/types/schema/mod.rs index b82aea2..1069428 100644 --- a/src/types/schema/mod.rs +++ b/src/types/schema/mod.rs @@ -65,18 +65,7 @@ mod schemas_tests { #[test] fn consent_false() { assert_eq!( - RegisterSchema::new( - "Test".to_string(), - None, - false, - None, - None, - None, - None, - None, - None, - None, - ), + RegisterSchema::builder("Test", false).build(), Err(FieldFormatError::ConsentError) ); } @@ -91,18 +80,11 @@ mod schemas_tests { #[test] fn valid_email() { - let reg = RegisterSchema::new( - "Testy".to_string(), - None, - true, - Some("me@mail.de".to_string()), - None, - None, - None, - None, - None, - None, - ); + let reg = RegisterSchemaOptions { + email: Some("me@mail.de".to_string()), + ..RegisterSchema::builder("Testy", true) + } + .build(); assert_ne!(reg, Err(FieldFormatError::EmailError)); } } diff --git a/tests/auth.rs b/tests/auth.rs index 24abefc..6972ace 100644 --- a/tests/auth.rs +++ b/tests/auth.rs @@ -1,22 +1,15 @@ -use chorus::types; +use chorus::types::{RegisterSchema, RegisterSchemaOptions}; mod common; #[tokio::test] async fn test_registration() { let mut bundle = common::setup().await; - let reg = types::RegisterSchema::new( - "Hiiii".to_string(), - None, - true, - None, - None, - None, - Some("2000-01-01".to_string()), - None, - None, - None, - ) + let reg = RegisterSchemaOptions { + date_of_birth: Some("2000-01-01".to_string()), + ..RegisterSchema::builder("Hiiii", true) + } + .build() .unwrap(); bundle.instance.register_account(®).await.unwrap(); common::teardown(bundle).await; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index c58c79a..5a29a0b 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -2,7 +2,7 @@ use chorus::{ instance::{Instance, UserMeta}, types::{ Channel, ChannelCreateSchema, Guild, GuildCreateSchema, RegisterSchema, - RoleCreateModifySchema, RoleObject, + RegisterSchemaOptions, RoleCreateModifySchema, RoleObject, }, URLBundle, }; @@ -26,18 +26,11 @@ pub async fn setup() -> TestBundle { ); let mut instance = Instance::new(urls.clone()).await.unwrap(); // Requires the existance of the below user. - let reg = RegisterSchema::new( - "integrationtestuser".to_string(), - None, - true, - None, - None, - None, - Some("2000-01-01".to_string()), - None, - None, - None, - ) + let reg = RegisterSchemaOptions { + date_of_birth: Some("2000-01-01".to_string()), + ..RegisterSchema::builder("integrationtestuser", true) + } + .build() .unwrap(); let guild_create_schema = GuildCreateSchema { name: Some("Test-Guild!".to_string()), diff --git a/tests/guild.rs b/tests/guild.rs index 3f7037c..903b1eb 100644 --- a/tests/guild.rs +++ b/tests/guild.rs @@ -20,10 +20,9 @@ async fn guild_creation_deletion() { .await .unwrap(); - match Guild::delete(&mut bundle.user, &guild.id.to_string()).await { - None => assert!(true), - Some(_) => assert!(false), - } + assert!(Guild::delete(&mut bundle.user, &guild.id.to_string()) + .await + .is_none()); common::teardown(bundle).await } diff --git a/tests/member.rs b/tests/member.rs index c6fc6e3..4ed676e 100644 --- a/tests/member.rs +++ b/tests/member.rs @@ -18,7 +18,7 @@ async fn add_remove_role() { } } if !role_found { - assert!(false) + panic!() } chorus::types::GuildMember::remove_role(&mut bundle.user, guild_id, user_id, role_id).await; let member = chorus::types::GuildMember::get(&mut bundle.user, guild_id, user_id) @@ -28,11 +28,11 @@ async fn add_remove_role() { if role != role_id { role_found = false; } else { - assert!(false); + panic!(); } } if role_found { - assert!(false) + panic!() } common::teardown(bundle).await } diff --git a/tests/message.rs b/tests/message.rs index d614538..e92c35c 100644 --- a/tests/message.rs +++ b/tests/message.rs @@ -8,18 +8,10 @@ mod common; #[tokio::test] async fn send_message() { let mut bundle = common::setup().await; - let mut message = types::MessageSendSchema::new( - None, - Some("A Message!".to_string()), - None, - None, - None, - None, - None, - None, - None, - None, - ); + let mut message = types::MessageSendSchema { + content: Some("A Message!".to_string()), + ..Default::default() + }; let _ = bundle .user .send_message(&mut message, bundle.channel.id.to_string(), None) @@ -53,18 +45,11 @@ async fn send_message_attachment() { content: buffer, }; - let mut message = types::MessageSendSchema::new( - None, - Some("trans rights now".to_string()), - None, - None, - None, - None, - None, - None, - None, - Some(vec![attachment.clone()]), - ); + let mut message = types::MessageSendSchema { + content: Some("trans rights now".to_string()), + attachments: Some(vec![attachment.clone()]), + ..Default::default() + }; let vec_attach = vec![attachment.clone()]; let _arg = Some(&vec_attach); diff --git a/tests/relationships.rs b/tests/relationships.rs index b575046..187f07e 100644 --- a/tests/relationships.rs +++ b/tests/relationships.rs @@ -1,21 +1,14 @@ -use chorus::types; +use chorus::types::{self, RegisterSchema, RegisterSchemaOptions}; mod common; #[tokio::test] async fn test_get_mutual_relationships() { - let register_schema = types::RegisterSchema::new( - "integrationtestuser2".to_string(), - None, - true, - None, - None, - None, - Some("2000-01-01".to_string()), - None, - None, - None, - ) + let register_schema = RegisterSchemaOptions { + date_of_birth: Some("2000-01-01".to_string()), + ..RegisterSchema::builder("integrationtestuser2", true) + } + .build() .unwrap(); let mut bundle = common::setup().await; @@ -37,18 +30,11 @@ async fn test_get_mutual_relationships() { #[tokio::test] async fn test_get_relationships() { - let register_schema = types::RegisterSchema::new( - "integrationtestuser2".to_string(), - None, - true, - None, - None, - None, - Some("2000-01-01".to_string()), - None, - None, - None, - ) + let register_schema = RegisterSchemaOptions { + date_of_birth: Some("2000-01-01".to_string()), + ..RegisterSchema::builder("integrationtestuser2", true) + } + .build() .unwrap(); let mut bundle = common::setup().await; diff --git a/tests/roles.rs b/tests/roles.rs index fd80de3..6cce1d3 100644 --- a/tests/roles.rs +++ b/tests/roles.rs @@ -25,10 +25,7 @@ async fn create_and_get_roles() { let expected = types::RoleObject::get_all(&mut bundle.user, &guild_id) .await .unwrap() - .unwrap() - .iter() - .nth(2) - .unwrap() + .unwrap()[2] .clone(); assert_eq!(role, expected);