Merge pull request #58 from polyphony-chat/main

Bring full-gateway-coverage up to date from main
This commit is contained in:
kozabrada123 2023-05-15 12:42:06 +00:00 committed by GitHub
commit 4a8cff6fd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 246 additions and 11 deletions

View File

@ -5,7 +5,6 @@ pub mod messages {
use serde_json::to_string;
use crate::api::types::{Message, PartialDiscordFileAttachment, User};
use crate::errors::InstanceServerError;
use crate::limit::LimitedRequester;
impl Message {

169
src/api/guilds/guilds.rs Normal file
View File

@ -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),
}
}
}

3
src/api/guilds/mod.rs Normal file
View File

@ -0,0 +1,3 @@
pub mod guilds;
use guilds::*;

View File

@ -1,11 +1,13 @@
pub mod auth;
pub mod channels;
pub mod guilds;
pub mod policies;
pub mod schemas;
pub mod types;
pub mod users;
pub use channels::messages::*;
pub use guilds::*;
pub use policies::instance::instance::*;
pub use policies::instance::limits::*;
pub use schemas::*;

View File

@ -1,5 +1,5 @@
pub mod limits {
use std::{collections::HashMap};
use std::collections::HashMap;
use reqwest::Client;
use serde::{Deserialize, Serialize};
@ -20,6 +20,23 @@ pub mod limits {
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)]
#[allow(non_snake_case)]
pub struct User {

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use crate::errors::FieldFormatError;
use super::Embed;
use super::{Channel, Embed};
/**
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
// just feel like writing tests, so there you go :) -@bitfl0wer
#[cfg(test)]

View File

@ -1841,3 +1841,8 @@ pub struct Webhook {
pub source_guild: Option<Guild>,
pub id: String,
}
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct GuildCreateResponse {
pub id: String,
}

View File

@ -17,8 +17,11 @@ custom_error! {
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}",
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: {}",
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! {

View File

@ -57,7 +57,8 @@ impl LimitedRequester {
## 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
information
- There has been an error with processing (unwrapping) the [`Response`](`reqwest::Response`)
@ -72,13 +73,23 @@ impl LimitedRequester {
user_rate_limits: &mut Limits,
) -> Result<Response, InstanceServerError> {
if self.can_send_request(limit_type, instance_rate_limits, user_rate_limits) {
let built_request = request
.build()
.unwrap_or_else(|e| panic!("Error while building the Request for sending: {}", e));
let built_request = match request.build() {
Ok(request) => request,
Err(e) => {
return Err(InstanceServerError::RequestErrorError {
url: "".to_string(),
error: e.to_string(),
})
}
};
let result = self.http.execute(built_request).await;
let response = match result {
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(
&response,
@ -86,13 +97,27 @@ impl LimitedRequester {
instance_rate_limits,
user_rate_limits,
);
Ok(response)
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)
}
} else {
self.requests.push_back(TypedRequest {
request,
limit_type,
});
Err(InstanceServerError::RateLimited)
Err(InstanceServerError::RateLimited {
bucket: limit_type.to_string(),
})
}
}