Merge pull request #3 from polyphony-chat/feature/register-login
Bring main up-to-date
This commit is contained in:
commit
389a509bfc
|
@ -13,3 +13,4 @@ serde_json = "1.0.95"
|
||||||
reqwest = "0.11.16"
|
reqwest = "0.11.16"
|
||||||
url = "2.3.1"
|
url = "2.3.1"
|
||||||
chrono = "0.4.24"
|
chrono = "0.4.24"
|
||||||
|
regex = "1.7.3"
|
|
@ -0,0 +1 @@
|
||||||
|
pub mod login {}
|
|
@ -0,0 +1,5 @@
|
||||||
|
pub mod login;
|
||||||
|
pub mod register;
|
||||||
|
|
||||||
|
pub use login::*;
|
||||||
|
pub use register::*;
|
|
@ -0,0 +1,7 @@
|
||||||
|
pub mod register {
|
||||||
|
use crate::instance::Instance;
|
||||||
|
|
||||||
|
impl Instance {
|
||||||
|
pub fn register() {}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,7 @@
|
||||||
|
pub mod auth;
|
||||||
pub mod policies;
|
pub mod policies;
|
||||||
|
pub mod schemas;
|
||||||
|
|
||||||
|
pub use policies::instance::instance::*;
|
||||||
pub use policies::instance::limits::*;
|
pub use policies::instance::limits::*;
|
||||||
|
pub use schemas::*;
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
pub mod instance {
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use reqwest::Client;
|
||||||
|
use serde_json::from_str;
|
||||||
|
|
||||||
|
use crate::{api::schemas::schemas::InstancePoliciesSchema, instance::Instance};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct InstancePoliciesError {
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstancePoliciesError {
|
||||||
|
fn new(message: String) -> Self {
|
||||||
|
InstancePoliciesError { message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InstancePoliciesError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for InstancePoliciesError {}
|
||||||
|
impl Instance {
|
||||||
|
/// Gets the instance policies schema.
|
||||||
|
/// # Errors
|
||||||
|
/// * [`InstancePoliciesError`] - If the request fails.
|
||||||
|
pub async fn instance_policies_schema(
|
||||||
|
&self,
|
||||||
|
) -> Result<InstancePoliciesSchema, InstancePoliciesError> {
|
||||||
|
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(InstancePoliciesError {
|
||||||
|
message: format!(
|
||||||
|
"An error occured while trying to GET from {}: {}",
|
||||||
|
endpoint_url, e
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if request.status().as_str().chars().next().unwrap() != '2' {
|
||||||
|
return Err(InstancePoliciesError {
|
||||||
|
message: format!(
|
||||||
|
"Received the following error code while requesting from the route: {}",
|
||||||
|
request.status().as_str()
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = request.text().await.unwrap();
|
||||||
|
let instance_policies_schema: InstancePoliciesSchema = from_str(&body).unwrap();
|
||||||
|
Ok(instance_policies_schema)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod instance_policies_schema_test {
|
||||||
|
use crate::{instance::Instance, limit::LimitedRequester, URLBundle};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn generate_instance_policies_schema() {
|
||||||
|
let urls = URLBundle::new(
|
||||||
|
"http://localhost:3001/api".to_string(),
|
||||||
|
"http://localhost:3001".to_string(),
|
||||||
|
"http://localhost:3001".to_string(),
|
||||||
|
);
|
||||||
|
let limited_requester = LimitedRequester::new(urls.get_api().to_string()).await;
|
||||||
|
let test_instance = Instance::new(urls.clone(), limited_requester)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let schema = test_instance.instance_policies_schema().await.unwrap();
|
||||||
|
println!("{}", schema);
|
||||||
|
}
|
||||||
|
}
|
|
@ -197,6 +197,10 @@ pub mod limits {
|
||||||
|
|
||||||
/// check_limits uses the API to get the current request limits of the instance.
|
/// check_limits uses the API to get the current request limits of the instance.
|
||||||
/// It returns a `Limits` struct containing all the limits.
|
/// It returns a `Limits` struct containing all the limits.
|
||||||
|
/// If the rate limit is disabled, then the limit is set to `u64::MAX`.
|
||||||
|
/// # Errors
|
||||||
|
/// This function will panic if the request fails or if the response body cannot be parsed.
|
||||||
|
/// TODO: Change this to return a Result and handle the errors properly.
|
||||||
pub async fn check_limits(api_url: String) -> HashMap<LimitType, Limit> {
|
pub async fn check_limits(api_url: String) -> HashMap<LimitType, Limit> {
|
||||||
let client = Client::new();
|
let client = Client::new();
|
||||||
let url_parsed = crate::URLBundle::parse_url(api_url) + "/policies/instance/limits";
|
let url_parsed = crate::URLBundle::parse_url(api_url) + "/policies/instance/limits";
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// src/api/policies/instance/mod.rs
|
pub mod instance;
|
||||||
|
|
||||||
pub mod limits;
|
pub mod limits;
|
||||||
|
|
||||||
|
pub use instance::*;
|
||||||
pub use limits::*;
|
pub use limits::*;
|
||||||
|
|
|
@ -0,0 +1,331 @@
|
||||||
|
pub mod schemas {
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct RegisterSchema {
|
||||||
|
username: String,
|
||||||
|
password: Option<String>,
|
||||||
|
consent: bool,
|
||||||
|
email: Option<String>,
|
||||||
|
fingerprint: Option<String>,
|
||||||
|
invite: Option<String>,
|
||||||
|
date_of_birth: Option<String>,
|
||||||
|
gift_code_sku_id: Option<String>,
|
||||||
|
captcha_key: Option<String>,
|
||||||
|
promotional_email_opt_in: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct RegisterSchemaError {
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RegisterSchemaError {
|
||||||
|
fn new(message: String) -> Self {
|
||||||
|
RegisterSchemaError { message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for RegisterSchemaError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for RegisterSchemaError {}
|
||||||
|
|
||||||
|
impl RegisterSchema {
|
||||||
|
/**
|
||||||
|
Returns a new [`Result<RegisterSchema, RegisterSchemaError>`].
|
||||||
|
## Arguments
|
||||||
|
All but "String::username" and "bool::consent" are optional.
|
||||||
|
|
||||||
|
## Errors
|
||||||
|
You will receive a [`RegisterSchemaError`], if:
|
||||||
|
- The username is less than 2 or more than 32 characters in length
|
||||||
|
- You supply a `password` which is less than 1 or more than 72 characters in length.
|
||||||
|
|
||||||
|
These constraints have been defined [in the Spacebar-API](https://docs.spacebar.chat/routes/)
|
||||||
|
*/
|
||||||
|
pub fn new(
|
||||||
|
username: String,
|
||||||
|
password: Option<String>,
|
||||||
|
consent: bool,
|
||||||
|
email: Option<String>,
|
||||||
|
fingerprint: Option<String>,
|
||||||
|
invite: Option<String>,
|
||||||
|
date_of_birth: Option<String>,
|
||||||
|
gift_code_sku_id: Option<String>,
|
||||||
|
captcha_key: Option<String>,
|
||||||
|
promotional_email_opt_in: Option<bool>,
|
||||||
|
) -> Result<RegisterSchema, RegisterSchemaError> {
|
||||||
|
if username.len() < 2 || username.len() > 32 {
|
||||||
|
return Err(RegisterSchemaError::new(
|
||||||
|
"Username must be between 2 and 32 characters".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if password.is_some()
|
||||||
|
&& (password.as_ref().unwrap().len() < 1 || password.as_ref().unwrap().len() > 72)
|
||||||
|
{
|
||||||
|
return Err(RegisterSchemaError {
|
||||||
|
message: "Password must be between 1 and 72 characters.".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if !consent {
|
||||||
|
return Err(RegisterSchemaError {
|
||||||
|
message: "Consent must be 'true' to register.".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let regex = Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap();
|
||||||
|
if email.clone().is_some() && !regex.is_match(email.clone().unwrap().as_str()) {
|
||||||
|
return Err(RegisterSchemaError {
|
||||||
|
message: "The provided email address is in an invalid format.".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(RegisterSchema {
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
consent,
|
||||||
|
email,
|
||||||
|
fingerprint,
|
||||||
|
invite,
|
||||||
|
date_of_birth,
|
||||||
|
gift_code_sku_id,
|
||||||
|
captcha_key,
|
||||||
|
promotional_email_opt_in,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct LoginSchema {
|
||||||
|
login: String,
|
||||||
|
password: String,
|
||||||
|
undelete: Option<bool>,
|
||||||
|
captcha_key: Option<String>,
|
||||||
|
login_source: Option<String>,
|
||||||
|
gift_code_sku_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct TotpSchema {
|
||||||
|
code: String,
|
||||||
|
ticket: String,
|
||||||
|
gift_code_sku_id: Option<String>,
|
||||||
|
login_source: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct InstancePoliciesSchema {
|
||||||
|
instance_name: String,
|
||||||
|
instance_description: Option<String>,
|
||||||
|
front_page: Option<String>,
|
||||||
|
tos_page: Option<String>,
|
||||||
|
correspondence_email: Option<String>,
|
||||||
|
correspondence_user_id: Option<String>,
|
||||||
|
image: Option<String>,
|
||||||
|
instance_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstancePoliciesSchema {
|
||||||
|
pub fn new(
|
||||||
|
instance_name: String,
|
||||||
|
instance_description: Option<String>,
|
||||||
|
front_page: Option<String>,
|
||||||
|
tos_page: Option<String>,
|
||||||
|
correspondence_email: Option<String>,
|
||||||
|
correspondence_user_id: Option<String>,
|
||||||
|
image: Option<String>,
|
||||||
|
instance_id: Option<String>,
|
||||||
|
) -> Self {
|
||||||
|
InstancePoliciesSchema {
|
||||||
|
instance_name,
|
||||||
|
instance_description,
|
||||||
|
front_page,
|
||||||
|
tos_page,
|
||||||
|
correspondence_email,
|
||||||
|
correspondence_user_id,
|
||||||
|
image,
|
||||||
|
instance_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InstancePoliciesSchema {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"InstancePoliciesSchema {{ instance_name: {}, instance_description: {}, front_page: {}, tos_page: {}, correspondence_email: {}, correspondence_user_id: {}, image: {}, instance_id: {} }}",
|
||||||
|
self.instance_name,
|
||||||
|
self.instance_description.clone().unwrap_or("None".to_string()),
|
||||||
|
self.front_page.clone().unwrap_or("None".to_string()),
|
||||||
|
self.tos_page.clone().unwrap_or("None".to_string()),
|
||||||
|
self.correspondence_email.clone().unwrap_or("None".to_string()),
|
||||||
|
self.correspondence_user_id.clone().unwrap_or("None".to_string()),
|
||||||
|
self.image.clone().unwrap_or("None".to_string()),
|
||||||
|
self.instance_id.clone().unwrap_or("None".to_string()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)]
|
||||||
|
mod schemas_tests {
|
||||||
|
use super::schemas::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn password_too_short() {
|
||||||
|
assert_eq!(
|
||||||
|
RegisterSchema::new(
|
||||||
|
"Test".to_string(),
|
||||||
|
Some("".to_string()),
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Err(RegisterSchemaError {
|
||||||
|
message: "Password must be between 1 and 72 characters.".to_string()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn password_too_long() {
|
||||||
|
let mut long_pw = String::new();
|
||||||
|
for _ in 0..73 {
|
||||||
|
long_pw = long_pw + "a";
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
RegisterSchema::new(
|
||||||
|
"Test".to_string(),
|
||||||
|
Some(long_pw),
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Err(RegisterSchemaError {
|
||||||
|
message: "Password must be between 1 and 72 characters.".to_string()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn username_too_short() {
|
||||||
|
assert_eq!(
|
||||||
|
RegisterSchema::new(
|
||||||
|
"T".to_string(),
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Err(RegisterSchemaError {
|
||||||
|
message: "Username must be between 2 and 32 characters".to_string()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn username_too_long() {
|
||||||
|
let mut long_un = String::new();
|
||||||
|
for _ in 0..33 {
|
||||||
|
long_un = long_un + "a";
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
RegisterSchema::new(long_un, None, true, None, None, None, None, None, None, None,),
|
||||||
|
Err(RegisterSchemaError {
|
||||||
|
message: "Username must be between 2 and 32 characters".to_string()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn consent_false() {
|
||||||
|
assert_eq!(
|
||||||
|
RegisterSchema::new(
|
||||||
|
"Test".to_string(),
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Err(RegisterSchemaError {
|
||||||
|
message: "Consent must be 'true' to register.".to_string()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_email() {
|
||||||
|
assert_eq!(
|
||||||
|
RegisterSchema::new(
|
||||||
|
"Test".to_string(),
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
Some("p@p.p".to_string()),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Err(RegisterSchemaError {
|
||||||
|
message: "The provided email address is in an invalid format.".to_string()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn valid_email() {
|
||||||
|
let reg = RegisterSchema::new(
|
||||||
|
"Test".to_string(),
|
||||||
|
None,
|
||||||
|
true,
|
||||||
|
Some("me@mail.xy".to_string()),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
assert_ne!(
|
||||||
|
reg,
|
||||||
|
Err(RegisterSchemaError {
|
||||||
|
message: "The provided email address is in an invalid format.".to_string()
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
use crate::gateway::Gateway;
|
|
||||||
use crate::limit::LimitedRequester;
|
|
||||||
|
|
||||||
struct ClientBuilder {}
|
|
||||||
|
|
||||||
/* impl ClientBuilder {
|
|
||||||
fn build() -> Client {}
|
|
||||||
} */
|
|
||||||
|
|
||||||
struct Client {}
|
|
|
@ -1 +1,2 @@
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Gateway {}
|
pub struct Gateway {}
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
use regex::internal::Inst;
|
||||||
|
|
||||||
|
use crate::api::instance;
|
||||||
|
use crate::api::schemas::schemas::InstancePoliciesSchema;
|
||||||
|
use crate::gateway::Gateway;
|
||||||
|
use crate::limit::LimitedRequester;
|
||||||
|
use crate::URLBundle;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/**
|
||||||
|
The [`Instance`] what you will be using to perform all sorts of actions on the Spacebar server.
|
||||||
|
*/
|
||||||
|
pub struct Instance {
|
||||||
|
pub urls: URLBundle,
|
||||||
|
pub instance_info: InstancePoliciesSchema,
|
||||||
|
pub requester: LimitedRequester,
|
||||||
|
//pub gateway: Gateway,
|
||||||
|
//pub users: HashMap<Token, Username>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Instance {
|
||||||
|
/// Creates a new [`Instance`].
|
||||||
|
/// # Arguments
|
||||||
|
/// * `urls` - The [`URLBundle`] that contains all the URLs that are needed to connect to the Spacebar server.
|
||||||
|
/// * `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,
|
||||||
|
requester: LimitedRequester,
|
||||||
|
) -> Result<Instance, InstanceError> {
|
||||||
|
let mut instance = Instance {
|
||||||
|
urls,
|
||||||
|
instance_info: InstancePoliciesSchema::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,
|
||||||
|
),
|
||||||
|
requester,
|
||||||
|
//gateway: (),
|
||||||
|
//users: (),
|
||||||
|
};
|
||||||
|
instance.instance_info = match instance.instance_policies_schema().await {
|
||||||
|
Ok(schema) => schema,
|
||||||
|
Err(e) => return Err(InstanceError{message: format!("Something seems to be wrong with the instance. Cannot get information about the instance: {}", e)}),
|
||||||
|
};
|
||||||
|
Ok(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct InstanceError {
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstanceError {
|
||||||
|
fn new(message: String) -> Self {
|
||||||
|
InstanceError { message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for InstanceError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for InstanceError {}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Token {
|
||||||
|
pub token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Username {
|
||||||
|
pub username: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Username {
|
||||||
|
/// Creates a new [`Username`].
|
||||||
|
/// # Arguments
|
||||||
|
/// * `username` - The username that will be used to create the [`Username`].
|
||||||
|
/// # Errors
|
||||||
|
/// * [`UsernameFormatError`] - If the username is not between 2 and 32 characters.
|
||||||
|
pub fn new(username: String) -> Result<Username, UsernameFormatError> {
|
||||||
|
if username.len() < 2 || username.len() > 32 {
|
||||||
|
return Err(UsernameFormatError::new(
|
||||||
|
"Username must be between 2 and 32 characters".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return Ok(Username { username });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct UsernameFormatError {
|
||||||
|
pub message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UsernameFormatError {
|
||||||
|
fn new(message: String) -> Self {
|
||||||
|
UsernameFormatError { message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for UsernameFormatError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for UsernameFormatError {}
|
|
@ -1,11 +1,11 @@
|
||||||
mod api;
|
mod api;
|
||||||
mod client;
|
|
||||||
mod gateway;
|
mod gateway;
|
||||||
|
mod instance;
|
||||||
mod limit;
|
mod limit;
|
||||||
mod voice;
|
mod voice;
|
||||||
|
|
||||||
use url::{ParseError, Url};
|
use url::{ParseError, Url};
|
||||||
#[derive(Clone, Default, Debug)]
|
#[derive(Clone, Default, Debug, PartialEq, Eq)]
|
||||||
|
|
||||||
/// A URLBundle is a struct which bundles together the API-, Gateway- and CDN-URLs of a Spacebar
|
/// A URLBundle is a struct which bundles together the API-, Gateway- and CDN-URLs of a Spacebar
|
||||||
/// instance.
|
/// instance.
|
||||||
|
|
Loading…
Reference in New Issue