Merge pull request #58 from polyphony-chat/main
Bring full-gateway-coverage up to date from main
This commit is contained in:
commit
32d160db64
|
@ -5,7 +5,6 @@ pub mod messages {
|
||||||
use serde_json::to_string;
|
use serde_json::to_string;
|
||||||
|
|
||||||
use crate::api::types::{Message, PartialDiscordFileAttachment, User};
|
use crate::api::types::{Message, PartialDiscordFileAttachment, User};
|
||||||
use crate::errors::InstanceServerError;
|
|
||||||
use crate::limit::LimitedRequester;
|
use crate::limit::LimitedRequester;
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
use serde_json::from_str;
|
||||||
|
use serde_json::to_string;
|
||||||
|
|
||||||
|
use crate::api::schemas;
|
||||||
|
use crate::api::types;
|
||||||
|
use crate::errors::InstanceServerError;
|
||||||
|
|
||||||
|
impl<'a> types::Guild {
|
||||||
|
/// Creates a new guild with the given parameters.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `user` - A mutable reference to the user creating the guild.
|
||||||
|
/// * `instance` - A mutable reference to the instance where the guild will be created.
|
||||||
|
/// * `guild_create_schema` - A reference to the schema containing the guild creation parameters.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// A `Result<String>` containing the ID of the newly created guild, or an error if the request fails.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an `InstanceServerError` if the request fails.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rs
|
||||||
|
/// let guild_create_schema = chorus::api::schemas::GuildCreateSchema::new(insert args here);
|
||||||
|
///
|
||||||
|
/// let result = Guild::create(&mut user, &mut instance, &guild_create_schema).await;
|
||||||
|
///
|
||||||
|
/// match result {
|
||||||
|
/// Ok(guild_id) => println!("Created guild with ID {}", guild_id),
|
||||||
|
/// Err(e) => println!("Failed to create guild: {}", e),
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn create(
|
||||||
|
user: &mut types::User<'a>,
|
||||||
|
url_api: &str,
|
||||||
|
guild_create_schema: schemas::GuildCreateSchema,
|
||||||
|
) -> Result<String, crate::errors::InstanceServerError> {
|
||||||
|
let url = format!("{}/guilds/", url_api);
|
||||||
|
let limits_user = user.limits.get_as_mut();
|
||||||
|
let limits_instance = &mut user.belongs_to.limits;
|
||||||
|
let request = reqwest::Client::new()
|
||||||
|
.post(url.clone())
|
||||||
|
.bearer_auth(user.token.clone())
|
||||||
|
.body(to_string(&guild_create_schema).unwrap());
|
||||||
|
let mut requester = crate::limit::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 id: types::GuildCreateResponse = from_str(&result.text().await.unwrap()).unwrap();
|
||||||
|
Ok(id.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes a guild.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `user` - A mutable reference to a `User` instance.
|
||||||
|
/// * `instance` - A mutable reference to an `Instance` instance.
|
||||||
|
/// * `guild_id` - A `String` representing the ID of the guild to delete.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// An `Option` containing an `InstanceServerError` if an error occurred during the request, otherwise `None`.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rs
|
||||||
|
/// let mut user = User::new();
|
||||||
|
/// let mut instance = Instance::new();
|
||||||
|
/// let guild_id = String::from("1234567890");
|
||||||
|
///
|
||||||
|
/// match Guild::delete(&mut user, &mut instance, guild_id) {
|
||||||
|
/// Some(e) => println!("Error deleting guild: {:?}", e),
|
||||||
|
/// None => println!("Guild deleted successfully"),
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub async fn delete(
|
||||||
|
user: &mut types::User<'a>,
|
||||||
|
url_api: &str,
|
||||||
|
guild_id: String,
|
||||||
|
) -> Option<InstanceServerError> {
|
||||||
|
let url = format!("{}/guilds/{}/delete/", url_api, guild_id);
|
||||||
|
let limits_user = user.limits.get_as_mut();
|
||||||
|
let limits_instance = &mut user.belongs_to.limits;
|
||||||
|
let request = reqwest::Client::new()
|
||||||
|
.post(url.clone())
|
||||||
|
.bearer_auth(user.token.clone());
|
||||||
|
let mut requester = crate::limit::LimitedRequester::new().await;
|
||||||
|
let result = requester
|
||||||
|
.send_request(
|
||||||
|
request,
|
||||||
|
crate::api::limits::LimitType::Guild,
|
||||||
|
limits_instance,
|
||||||
|
limits_user,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
if result.is_err() {
|
||||||
|
Some(result.err().unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::api::schemas;
|
||||||
|
use crate::api::types;
|
||||||
|
use crate::instance::Instance;
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn guild_creation_deletion() {
|
||||||
|
let mut instance = Instance::new(
|
||||||
|
crate::URLBundle {
|
||||||
|
api: "http://localhost:3001/api".to_string(),
|
||||||
|
wss: "ws://localhost:3001/".to_string(),
|
||||||
|
cdn: "http://localhost:3001".to_string(),
|
||||||
|
},
|
||||||
|
crate::limit::LimitedRequester::new().await,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let login_schema: schemas::LoginSchema = schemas::LoginSchema::new(
|
||||||
|
schemas::AuthUsername::new("user@test.xyz".to_string()).unwrap(),
|
||||||
|
"transrights".to_string(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let mut user = instance.login_account(&login_schema).await.unwrap();
|
||||||
|
|
||||||
|
let guild_create_schema = schemas::GuildCreateSchema {
|
||||||
|
name: Some("test".to_string()),
|
||||||
|
region: None,
|
||||||
|
icon: None,
|
||||||
|
channels: None,
|
||||||
|
guild_template_code: None,
|
||||||
|
system_channel_id: None,
|
||||||
|
rules_channel_id: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let guild =
|
||||||
|
types::Guild::create(&mut user, "http://localhost:3001/api", guild_create_schema)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("{}", guild);
|
||||||
|
|
||||||
|
match types::Guild::delete(&mut user, "http://localhost:3001/api", guild).await {
|
||||||
|
None => assert!(true),
|
||||||
|
Some(_) => assert!(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod guilds;
|
||||||
|
|
||||||
|
use guilds::*;
|
|
@ -1,11 +1,13 @@
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod channels;
|
pub mod channels;
|
||||||
|
pub mod guilds;
|
||||||
pub mod policies;
|
pub mod policies;
|
||||||
pub mod schemas;
|
pub mod schemas;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod users;
|
pub mod users;
|
||||||
|
|
||||||
pub use channels::messages::*;
|
pub use channels::messages::*;
|
||||||
|
pub use guilds::*;
|
||||||
pub use policies::instance::instance::*;
|
pub use policies::instance::instance::*;
|
||||||
pub use policies::instance::limits::*;
|
pub use policies::instance::limits::*;
|
||||||
pub use schemas::*;
|
pub use schemas::*;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pub mod limits {
|
pub mod limits {
|
||||||
use std::{collections::HashMap};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -20,6 +20,23 @@ pub mod limits {
|
||||||
Webhook,
|
Webhook,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToString for LimitType {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
LimitType::AuthRegister => "AuthRegister".to_string(),
|
||||||
|
LimitType::AuthLogin => "AuthLogin".to_string(),
|
||||||
|
LimitType::AbsoluteMessage => "AbsoluteMessage".to_string(),
|
||||||
|
LimitType::AbsoluteRegister => "AbsoluteRegister".to_string(),
|
||||||
|
LimitType::Global => "Global".to_string(),
|
||||||
|
LimitType::Ip => "Ip".to_string(),
|
||||||
|
LimitType::Channel => "Channel".to_string(),
|
||||||
|
LimitType::Error => "Error".to_string(),
|
||||||
|
LimitType::Guild => "Guild".to_string(),
|
||||||
|
LimitType::Webhook => "Webhook".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
|
|
|
@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::errors::FieldFormatError;
|
use crate::errors::FieldFormatError;
|
||||||
|
|
||||||
use super::Embed;
|
use super::{Channel, Embed};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A struct that represents a well-formed email address.
|
A struct that represents a well-formed email address.
|
||||||
|
@ -287,6 +287,18 @@ impl MessageSendSchema {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct GuildCreateSchema {
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub region: Option<String>,
|
||||||
|
pub icon: Option<String>,
|
||||||
|
pub channels: Option<Vec<Channel>>,
|
||||||
|
pub guild_template_code: Option<String>,
|
||||||
|
pub system_channel_id: Option<String>,
|
||||||
|
pub rules_channel_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
// I know that some of these tests are... really really basic and unneccessary, but sometimes, I
|
// 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
|
// just feel like writing tests, so there you go :) -@bitfl0wer
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1841,3 +1841,8 @@ pub struct Webhook {
|
||||||
pub source_guild: Option<Guild>,
|
pub source_guild: Option<Guild>,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
|
||||||
|
pub struct GuildCreateResponse {
|
||||||
|
pub id: String,
|
||||||
|
}
|
||||||
|
|
|
@ -17,8 +17,11 @@ custom_error! {
|
||||||
ReceivedErrorCodeError{error_code:String} = "Received the following error code while requesting from the route: {error_code}",
|
ReceivedErrorCodeError{error_code:String} = "Received the following error code while requesting from the route: {error_code}",
|
||||||
CantGetInfoError{error:String} = "Something seems to be wrong with the instance. Cannot get information about the instance: {error}",
|
CantGetInfoError{error:String} = "Something seems to be wrong with the instance. Cannot get information about the instance: {error}",
|
||||||
InvalidFormBodyError{error_type: String, error:String} = "The server responded with: {error_type}: {error}",
|
InvalidFormBodyError{error_type: String, error:String} = "The server responded with: {error_type}: {error}",
|
||||||
RateLimited = "Ratelimited.",
|
RateLimited{bucket:String} = "Ratelimited on Bucket {bucket}",
|
||||||
MultipartCreationError{error: String} = "Got an error whilst creating the form: {}",
|
MultipartCreationError{error: String} = "Got an error whilst creating the form: {}",
|
||||||
|
TokenExpired = "Token expired, invalid or not found.",
|
||||||
|
NoPermission = "You do not have the permissions needed to perform this action.",
|
||||||
|
NotFound{error: String} = "The provided resource hasn't been found: {}",
|
||||||
}
|
}
|
||||||
|
|
||||||
custom_error! {
|
custom_error! {
|
||||||
|
|
37
src/limit.rs
37
src/limit.rs
|
@ -57,7 +57,8 @@ impl LimitedRequester {
|
||||||
|
|
||||||
## Errors
|
## Errors
|
||||||
|
|
||||||
This method will panic, if:
|
This method will error, if:
|
||||||
|
- The request does not return a success status code (200-299)
|
||||||
- The supplied [`RequestBuilder`](reqwest::RequestBuilder) contains invalid or incomplete
|
- The supplied [`RequestBuilder`](reqwest::RequestBuilder) contains invalid or incomplete
|
||||||
information
|
information
|
||||||
- There has been an error with processing (unwrapping) the [`Response`](`reqwest::Response`)
|
- There has been an error with processing (unwrapping) the [`Response`](`reqwest::Response`)
|
||||||
|
@ -72,13 +73,23 @@ impl LimitedRequester {
|
||||||
user_rate_limits: &mut Limits,
|
user_rate_limits: &mut Limits,
|
||||||
) -> Result<Response, InstanceServerError> {
|
) -> Result<Response, InstanceServerError> {
|
||||||
if self.can_send_request(limit_type, instance_rate_limits, user_rate_limits) {
|
if self.can_send_request(limit_type, instance_rate_limits, user_rate_limits) {
|
||||||
let built_request = request
|
let built_request = match request.build() {
|
||||||
.build()
|
Ok(request) => request,
|
||||||
.unwrap_or_else(|e| panic!("Error while building the Request for sending: {}", e));
|
Err(e) => {
|
||||||
|
return Err(InstanceServerError::RequestErrorError {
|
||||||
|
url: "".to_string(),
|
||||||
|
error: e.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
let result = self.http.execute(built_request).await;
|
let result = self.http.execute(built_request).await;
|
||||||
let response = match result {
|
let response = match result {
|
||||||
Ok(is_response) => is_response,
|
Ok(is_response) => is_response,
|
||||||
Err(e) => panic!("An error occured while processing the response: {}", e),
|
Err(e) => {
|
||||||
|
return Err(InstanceServerError::ReceivedErrorCodeError {
|
||||||
|
error_code: e.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.update_limits(
|
self.update_limits(
|
||||||
&response,
|
&response,
|
||||||
|
@ -86,13 +97,27 @@ impl LimitedRequester {
|
||||||
instance_rate_limits,
|
instance_rate_limits,
|
||||||
user_rate_limits,
|
user_rate_limits,
|
||||||
);
|
);
|
||||||
|
if !response.status().is_success() {
|
||||||
|
match response.status().as_u16() {
|
||||||
|
401 => return Err(InstanceServerError::TokenExpired),
|
||||||
|
403 => return Err(InstanceServerError::TokenExpired),
|
||||||
|
_ => {
|
||||||
|
return Err(InstanceServerError::ReceivedErrorCodeError {
|
||||||
|
error_code: response.status().as_str().to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
Ok(response)
|
Ok(response)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.requests.push_back(TypedRequest {
|
self.requests.push_back(TypedRequest {
|
||||||
request,
|
request,
|
||||||
limit_type,
|
limit_type,
|
||||||
});
|
});
|
||||||
Err(InstanceServerError::RateLimited)
|
Err(InstanceServerError::RateLimited {
|
||||||
|
bucket: limit_type.to_string(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue