Shulkers of fixes (#327)

* Shulkers of fixes

* Fix validation message

* Update deps

* Bump docker image version
This commit is contained in:
Geometrically
2022-03-27 19:12:42 -07:00
committed by GitHub
parent 7415b07586
commit d1c0c9739d
42 changed files with 683 additions and 700 deletions

View File

@@ -19,61 +19,51 @@ pub fn config(cfg: &mut ServiceConfig) {
#[derive(Error, Debug)]
pub enum AuthorizationError {
#[error("Environment Error")]
EnvError(#[from] dotenv::Error),
Env(#[from] dotenv::Error),
#[error("An unknown database error occured: {0}")]
SqlxDatabaseError(#[from] sqlx::Error),
SqlxDatabase(#[from] sqlx::Error),
#[error("Database Error: {0}")]
DatabaseError(#[from] crate::database::models::DatabaseError),
Database(#[from] crate::database::models::DatabaseError),
#[error("Error while parsing JSON: {0}")]
SerDeError(#[from] serde_json::Error),
SerDe(#[from] serde_json::Error),
#[error("Error while communicating to GitHub OAuth2")]
GithubError(#[from] reqwest::Error),
Github(#[from] reqwest::Error),
#[error("Invalid Authentication credentials")]
InvalidCredentialsError,
InvalidCredentials,
#[error("Authentication Error: {0}")]
AuthenticationError(#[from] crate::util::auth::AuthenticationError),
Authentication(#[from] crate::util::auth::AuthenticationError),
#[error("Error while decoding Base62")]
DecodingError(#[from] DecodingError),
Decoding(#[from] DecodingError),
}
impl actix_web::ResponseError for AuthorizationError {
fn status_code(&self) -> StatusCode {
match self {
AuthorizationError::EnvError(..) => {
AuthorizationError::Env(..) => StatusCode::INTERNAL_SERVER_ERROR,
AuthorizationError::SqlxDatabase(..) => {
StatusCode::INTERNAL_SERVER_ERROR
}
AuthorizationError::SqlxDatabaseError(..) => {
AuthorizationError::Database(..) => {
StatusCode::INTERNAL_SERVER_ERROR
}
AuthorizationError::DatabaseError(..) => {
StatusCode::INTERNAL_SERVER_ERROR
}
AuthorizationError::SerDeError(..) => StatusCode::BAD_REQUEST,
AuthorizationError::GithubError(..) => {
StatusCode::FAILED_DEPENDENCY
}
AuthorizationError::InvalidCredentialsError => {
StatusCode::UNAUTHORIZED
}
AuthorizationError::DecodingError(..) => StatusCode::BAD_REQUEST,
AuthorizationError::AuthenticationError(..) => {
StatusCode::UNAUTHORIZED
}
AuthorizationError::SerDe(..) => StatusCode::BAD_REQUEST,
AuthorizationError::Github(..) => StatusCode::FAILED_DEPENDENCY,
AuthorizationError::InvalidCredentials => StatusCode::UNAUTHORIZED,
AuthorizationError::Decoding(..) => StatusCode::BAD_REQUEST,
AuthorizationError::Authentication(..) => StatusCode::UNAUTHORIZED,
}
}
fn error_response(&self) -> HttpResponse {
HttpResponse::build(self.status_code()).json(ApiError {
error: match self {
AuthorizationError::EnvError(..) => "environment_error",
AuthorizationError::SqlxDatabaseError(..) => "database_error",
AuthorizationError::DatabaseError(..) => "database_error",
AuthorizationError::SerDeError(..) => "invalid_input",
AuthorizationError::GithubError(..) => "github_error",
AuthorizationError::InvalidCredentialsError => {
"invalid_credentials"
}
AuthorizationError::DecodingError(..) => "decoding_error",
AuthorizationError::AuthenticationError(..) => {
AuthorizationError::Env(..) => "environment_error",
AuthorizationError::SqlxDatabase(..) => "database_error",
AuthorizationError::Database(..) => "database_error",
AuthorizationError::SerDe(..) => "invalid_input",
AuthorizationError::Github(..) => "github_error",
AuthorizationError::InvalidCredentials => "invalid_credentials",
AuthorizationError::Decoding(..) => "decoding_error",
AuthorizationError::Authentication(..) => {
"authentication_error"
}
},
@@ -159,7 +149,7 @@ pub async fn auth_callback(
let duration = result.expires.signed_duration_since(now);
if duration.num_seconds() < 0 {
return Err(AuthorizationError::InvalidCredentialsError);
return Err(AuthorizationError::InvalidCredentials);
}
sqlx::query!(
@@ -256,6 +246,6 @@ pub async fn auth_callback(
.append_header(("Location", &*redirect_url))
.json(AuthorizationInit { url: redirect_url }))
} else {
Err(AuthorizationError::InvalidCredentialsError)
Err(AuthorizationError::InvalidCredentials)
}
}

View File

@@ -114,7 +114,7 @@ pub async fn maven_metadata(
Ok(HttpResponse::Ok()
.content_type("text/xml")
.body(yaserde::ser::to_string(&respdata).map_err(ApiError::XmlError)?))
.body(yaserde::ser::to_string(&respdata).map_err(ApiError::Xml)?))
}
fn find_file<'a>(
@@ -211,9 +211,9 @@ pub async fn version_file(
name: project.inner.title,
description: project.inner.description,
};
return Ok(HttpResponse::Ok().content_type("text/xml").body(
yaserde::ser::to_string(&respdata).map_err(ApiError::XmlError)?,
));
return Ok(HttpResponse::Ok()
.content_type("text/xml")
.body(yaserde::ser::to_string(&respdata).map_err(ApiError::Xml)?));
} else if let Some(selected_file) =
find_file(&project_id, &project, &version, &file)
{

View File

@@ -159,66 +159,66 @@ pub fn reports_config(cfg: &mut web::ServiceConfig) {
#[derive(thiserror::Error, Debug)]
pub enum ApiError {
#[error("Environment Error")]
EnvError(#[from] dotenv::Error),
Env(#[from] dotenv::Error),
#[error("Error while uploading file")]
FileHostingError(#[from] FileHostingError),
FileHosting(#[from] FileHostingError),
#[error("Database Error: {0}")]
DatabaseError(#[from] crate::database::models::DatabaseError),
Database(#[from] crate::database::models::DatabaseError),
#[error("Database Error: {0}")]
SqlxDatabaseError(#[from] sqlx::Error),
SqlxDatabase(#[from] sqlx::Error),
#[error("Internal server error: {0}")]
XmlError(String),
Xml(String),
#[error("Deserialization error: {0}")]
JsonError(#[from] serde_json::Error),
Json(#[from] serde_json::Error),
#[error("Authentication Error: {0}")]
AuthenticationError(#[from] crate::util::auth::AuthenticationError),
Authentication(#[from] crate::util::auth::AuthenticationError),
#[error("Authentication Error: {0}")]
CustomAuthenticationError(String),
CustomAuthentication(String),
#[error("Invalid Input: {0}")]
InvalidInputError(String),
InvalidInput(String),
#[error("Error while validating input: {0}")]
ValidationError(String),
Validation(String),
#[error("Search Error: {0}")]
SearchError(#[from] meilisearch_sdk::errors::Error),
Search(#[from] meilisearch_sdk::errors::Error),
#[error("Indexing Error: {0}")]
IndexingError(#[from] crate::search::indexing::IndexingError),
Indexing(#[from] crate::search::indexing::IndexingError),
}
impl actix_web::ResponseError for ApiError {
fn status_code(&self) -> actix_web::http::StatusCode {
match self {
ApiError::EnvError(..) => {
ApiError::Env(..) => {
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
}
ApiError::DatabaseError(..) => {
ApiError::Database(..) => {
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
}
ApiError::SqlxDatabaseError(..) => {
ApiError::SqlxDatabase(..) => {
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
}
ApiError::AuthenticationError(..) => {
ApiError::Authentication(..) => {
actix_web::http::StatusCode::UNAUTHORIZED
}
ApiError::CustomAuthenticationError(..) => {
ApiError::CustomAuthentication(..) => {
actix_web::http::StatusCode::UNAUTHORIZED
}
ApiError::XmlError(..) => {
ApiError::Xml(..) => {
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
}
ApiError::JsonError(..) => actix_web::http::StatusCode::BAD_REQUEST,
ApiError::SearchError(..) => {
ApiError::Json(..) => actix_web::http::StatusCode::BAD_REQUEST,
ApiError::Search(..) => {
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
}
ApiError::IndexingError(..) => {
ApiError::Indexing(..) => {
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
}
ApiError::FileHostingError(..) => {
ApiError::FileHosting(..) => {
actix_web::http::StatusCode::INTERNAL_SERVER_ERROR
}
ApiError::InvalidInputError(..) => {
ApiError::InvalidInput(..) => {
actix_web::http::StatusCode::BAD_REQUEST
}
ApiError::ValidationError(..) => {
ApiError::Validation(..) => {
actix_web::http::StatusCode::BAD_REQUEST
}
}
@@ -228,18 +228,18 @@ impl actix_web::ResponseError for ApiError {
actix_web::HttpResponse::build(self.status_code()).json(
crate::models::error::ApiError {
error: match self {
ApiError::EnvError(..) => "environment_error",
ApiError::SqlxDatabaseError(..) => "database_error",
ApiError::DatabaseError(..) => "database_error",
ApiError::AuthenticationError(..) => "unauthorized",
ApiError::CustomAuthenticationError(..) => "unauthorized",
ApiError::XmlError(..) => "xml_error",
ApiError::JsonError(..) => "json_error",
ApiError::SearchError(..) => "search_error",
ApiError::IndexingError(..) => "indexing_error",
ApiError::FileHostingError(..) => "file_hosting_error",
ApiError::InvalidInputError(..) => "invalid_input",
ApiError::ValidationError(..) => "invalid_input",
ApiError::Env(..) => "environment_error",
ApiError::SqlxDatabase(..) => "database_error",
ApiError::Database(..) => "database_error",
ApiError::Authentication(..) => "unauthorized",
ApiError::CustomAuthentication(..) => "unauthorized",
ApiError::Xml(..) => "xml_error",
ApiError::Json(..) => "json_error",
ApiError::Search(..) => "search_error",
ApiError::Indexing(..) => "indexing_error",
ApiError::FileHosting(..) => "file_hosting_error",
ApiError::InvalidInput(..) => "invalid_input",
ApiError::Validation(..) => "invalid_input",
},
description: &self.to_string(),
},

View File

@@ -105,7 +105,7 @@ pub async fn notification_delete(
Ok(HttpResponse::NoContent().body(""))
} else {
Err(ApiError::CustomAuthenticationError(
Err(ApiError::CustomAuthentication(
"You are not authorized to delete this notification!"
.to_string(),
))

View File

@@ -295,7 +295,7 @@ Get logged in user
pub async fn project_create_inner(
req: HttpRequest,
mut payload: Multipart,
mut transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
file_host: &dyn FileHost,
uploaded_files: &mut Vec<UploadedFile>,
) -> Result<HttpResponse, CreateError> {
@@ -535,7 +535,7 @@ pub async fn project_create_inner(
all_game_versions.clone(),
version_data.primary_file.is_some(),
version_data.primary_file.as_deref() == Some(name),
&mut transaction,
transaction,
)
.await?;
}

View File

@@ -102,9 +102,10 @@ pub async fn dependency_list(
) -> Result<HttpResponse, ApiError> {
let string = info.into_inner().0;
let result =
database::models::Project::get_full_from_slug_or_project_id(&string, &**pool)
.await?;
let result = database::models::Project::get_full_from_slug_or_project_id(
&string, &**pool,
)
.await?;
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
@@ -152,7 +153,7 @@ pub async fn dependency_list(
database::Project::get_many_full(
dependencies
.iter()
.map(|x| if x.0.is_none() {
.filter_map(|x| if x.0.is_none() {
if let Some(mod_dependency_id) = x.2 {
Some(mod_dependency_id)
} else {
@@ -161,12 +162,11 @@ pub async fn dependency_list(
} else {
x.1
})
.flatten()
.collect(),
&**pool,
),
database::Version::get_many_full(
dependencies.iter().map(|x| x.0).flatten().collect(),
dependencies.iter().filter_map(|x| x.0).collect(),
&**pool,
)
);
@@ -282,7 +282,7 @@ pub async fn project_edit(
let user = get_user_from_headers(req.headers(), &**pool).await?;
new_project.validate().map_err(|err| {
ApiError::ValidationError(validation_errors_to_string(err, None))
ApiError::Validation(validation_errors_to_string(err, None))
})?;
let string = info.into_inner().0;
@@ -315,7 +315,7 @@ pub async fn project_edit(
if let Some(title) = &new_project.title {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the title of this project!"
.to_string(),
));
@@ -336,7 +336,7 @@ pub async fn project_edit(
if let Some(description) = &new_project.description {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the description of this project!"
.to_string(),
));
@@ -357,7 +357,7 @@ pub async fn project_edit(
if let Some(status) = &new_project.status {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the status of this project!"
.to_string(),
));
@@ -367,7 +367,7 @@ pub async fn project_edit(
|| status == &ProjectStatus::Approved)
&& !user.role.is_mod()
{
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to set this status"
.to_string(),
));
@@ -375,7 +375,7 @@ pub async fn project_edit(
if status == &ProjectStatus::Processing {
if project_item.versions.is_empty() {
return Err(ApiError::InvalidInputError(String::from(
return Err(ApiError::InvalidInput(String::from(
"Project submitted for review with no initial versions",
)));
}
@@ -420,7 +420,7 @@ pub async fn project_edit(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"No database entry for status provided.".to_string(),
)
})?;
@@ -457,7 +457,7 @@ pub async fn project_edit(
if let Some(categories) = &new_project.categories {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the categories of this project!"
.to_string(),
));
@@ -481,7 +481,7 @@ pub async fn project_edit(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(format!(
ApiError::InvalidInput(format!(
"Category {} does not exist.",
category.clone()
))
@@ -502,7 +502,7 @@ pub async fn project_edit(
if let Some(issues_url) = &new_project.issues_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the issues URL of this project!"
.to_string(),
));
@@ -523,7 +523,7 @@ pub async fn project_edit(
if let Some(source_url) = &new_project.source_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the source URL of this project!"
.to_string(),
));
@@ -544,7 +544,7 @@ pub async fn project_edit(
if let Some(wiki_url) = &new_project.wiki_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the wiki URL of this project!"
.to_string(),
));
@@ -565,7 +565,7 @@ pub async fn project_edit(
if let Some(license_url) = &new_project.license_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the license URL of this project!"
.to_string(),
));
@@ -586,7 +586,7 @@ pub async fn project_edit(
if let Some(discord_url) = &new_project.discord_url {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the discord URL of this project!"
.to_string(),
));
@@ -607,7 +607,7 @@ pub async fn project_edit(
if let Some(slug) = &new_project.slug {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the slug of this project!"
.to_string(),
));
@@ -629,7 +629,7 @@ pub async fn project_edit(
.await?;
if results.exists.unwrap_or(true) {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"Slug collides with other project's id!"
.to_string(),
));
@@ -652,7 +652,7 @@ pub async fn project_edit(
if let Some(new_side) = &new_project.client_side {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the side type of this mod!"
.to_string(),
));
@@ -680,7 +680,7 @@ pub async fn project_edit(
if let Some(new_side) = &new_project.server_side {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the side type of this project!"
.to_string(),
));
@@ -708,7 +708,7 @@ pub async fn project_edit(
if let Some(license) = &new_project.license_id {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the license of this project!"
.to_string(),
));
@@ -736,7 +736,7 @@ pub async fn project_edit(
if let Some(donations) = &new_project.donation_urls {
if !perms.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the donation links of this project!"
.to_string(),
));
@@ -760,7 +760,7 @@ pub async fn project_edit(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(format!(
ApiError::InvalidInput(format!(
"Platform {} does not exist.",
donation.id.clone()
))
@@ -784,7 +784,7 @@ pub async fn project_edit(
if !user.role.is_mod()
&& project_item.status != ProjectStatus::Approved
{
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the moderation message of this project!"
.to_string(),
));
@@ -809,7 +809,7 @@ pub async fn project_edit(
if !user.role.is_mod()
&& project_item.status != ProjectStatus::Approved
{
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the moderation message body of this project!"
.to_string(),
));
@@ -830,7 +830,7 @@ pub async fn project_edit(
if let Some(body) = &new_project.body {
if !perms.contains(Permissions::EDIT_BODY) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the body of this project!"
.to_string(),
));
@@ -852,7 +852,7 @@ pub async fn project_edit(
transaction.commit().await?;
Ok(HttpResponse::NoContent().body(""))
} else {
Err(ApiError::CustomAuthenticationError(
Err(ApiError::CustomAuthentication(
"You do not have permission to edit this project!".to_string(),
))
}
@@ -889,7 +889,7 @@ pub async fn project_icon_edit(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
@@ -901,15 +901,15 @@ pub async fn project_icon_edit(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's icon."
.to_string(),
));
@@ -958,7 +958,7 @@ pub async fn project_icon_edit(
Ok(HttpResponse::NoContent().body(""))
} else {
Err(ApiError::InvalidInputError(format!(
Err(ApiError::InvalidInput(format!(
"Invalid format for project icon: {}",
ext.ext
)))
@@ -981,7 +981,7 @@ pub async fn delete_project_icon(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
@@ -993,15 +993,15 @@ pub async fn delete_project_icon(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's icon."
.to_string(),
));
@@ -1057,7 +1057,7 @@ pub async fn add_gallery_item(
crate::util::ext::get_image_content_type(&*ext.ext)
{
item.validate().map_err(|err| {
ApiError::ValidationError(validation_errors_to_string(err, None))
ApiError::Validation(validation_errors_to_string(err, None))
})?;
let cdn_url = dotenv::var("CDN_URL")?;
@@ -1071,7 +1071,7 @@ pub async fn add_gallery_item(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
@@ -1083,15 +1083,15 @@ pub async fn add_gallery_item(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's gallery."
.to_string(),
));
@@ -1143,7 +1143,7 @@ pub async fn add_gallery_item(
Ok(HttpResponse::NoContent().body(""))
} else {
Err(ApiError::InvalidInputError(format!(
Err(ApiError::InvalidInput(format!(
"Invalid format for gallery image: {}",
ext.ext
)))
@@ -1182,7 +1182,7 @@ pub async fn edit_gallery_item(
let string = info.into_inner().0;
item.validate().map_err(|err| {
ApiError::ValidationError(validation_errors_to_string(err, None))
ApiError::Validation(validation_errors_to_string(err, None))
})?;
let project_item = database::models::Project::get_from_slug_or_project_id(
@@ -1191,7 +1191,7 @@ pub async fn edit_gallery_item(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
@@ -1203,15 +1203,15 @@ pub async fn edit_gallery_item(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's gallery."
.to_string(),
));
@@ -1229,7 +1229,7 @@ pub async fn edit_gallery_item(
.fetch_optional(&mut *transaction)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(format!(
ApiError::InvalidInput(format!(
"Gallery item at URL {} is not part of the project's gallery.",
item.url
))
@@ -1319,7 +1319,7 @@ pub async fn delete_gallery_item(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
@@ -1331,15 +1331,15 @@ pub async fn delete_gallery_item(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
if !team_member.permissions.contains(Permissions::EDIT_DETAILS) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this project's gallery."
.to_string(),
));
@@ -1357,7 +1357,7 @@ pub async fn delete_gallery_item(
.fetch_optional(&mut *transaction)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(format!(
ApiError::InvalidInput(format!(
"Gallery item at URL {} is not part of the project's gallery.",
item.url
))
@@ -1403,7 +1403,7 @@ pub async fn project_delete(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
@@ -1416,9 +1416,9 @@ pub async fn project_delete(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
@@ -1427,7 +1427,7 @@ pub async fn project_delete(
.permissions
.contains(Permissions::DELETE_PROJECT)
{
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to delete this project!".to_string(),
));
}
@@ -1463,7 +1463,7 @@ pub async fn project_follow(
database::models::Project::get_from_slug_or_project_id(string, &**pool)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
@@ -1512,7 +1512,7 @@ pub async fn project_follow(
Ok(HttpResponse::NoContent().body(""))
} else {
Err(ApiError::InvalidInputError(
Err(ApiError::InvalidInput(
"You are already following this project!".to_string(),
))
}
@@ -1531,7 +1531,7 @@ pub async fn project_unfollow(
database::models::Project::get_from_slug_or_project_id(string, &**pool)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The specified project does not exist!".to_string(),
)
})?;
@@ -1580,7 +1580,7 @@ pub async fn project_unfollow(
Ok(HttpResponse::NoContent().body(""))
} else {
Err(ApiError::InvalidInputError(
Err(ApiError::InvalidInput(
"You are not following this project!".to_string(),
))
}

View File

@@ -31,7 +31,7 @@ pub async fn report_create(
let mut bytes = web::BytesMut::new();
while let Some(item) = body.next().await {
bytes.extend_from_slice(&item.map_err(|_| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"Error while parsing request payload!".to_string(),
)
})?);
@@ -46,7 +46,7 @@ pub async fn report_create(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(format!(
ApiError::InvalidInput(format!(
"Invalid report type: {}",
new_report.report_type
))
@@ -91,7 +91,7 @@ pub async fn report_create(
)
}
ItemType::Unknown => {
return Err(ApiError::InvalidInputError(format!(
return Err(ApiError::InvalidInput(format!(
"Invalid report item type: {}",
new_report.item_type.as_str()
)))

View File

@@ -74,7 +74,7 @@ pub async fn category_create(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"Specified project type does not exist!".to_string(),
)
})?;

View File

@@ -38,7 +38,7 @@ pub async fn team_members_get_project(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?;
.map_err(ApiError::Database)?;
if team_member.is_some() {
let team_members: Vec<_> = members_data
@@ -80,7 +80,7 @@ pub async fn team_members_get(
let team_member =
TeamMember::get_from_user_id(id.into(), user.id.into(), &**pool)
.await
.map_err(ApiError::DatabaseError)?;
.map_err(ApiError::Database)?;
if team_member.is_some() {
let team_members: Vec<_> = members_data
@@ -119,7 +119,7 @@ pub async fn join_team(
if let Some(member) = member {
if member.accepted {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"You are already a member of this team".to_string(),
));
}
@@ -138,7 +138,7 @@ pub async fn join_team(
transaction.commit().await?;
} else {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"There is no pending request from this team".to_string(),
));
}
@@ -175,26 +175,26 @@ pub async fn add_team_member(
TeamMember::get_from_user_id(team_id, current_user.id.into(), &**pool)
.await?
.ok_or_else(|| {
ApiError::CustomAuthenticationError(
ApiError::CustomAuthentication(
"You don't have permission to edit members of this team"
.to_string(),
)
})?;
if !member.permissions.contains(Permissions::MANAGE_INVITES) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to invite users to this team"
.to_string(),
));
}
if !member.permissions.contains(new_member.permissions) {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"The new member has permissions that you don't have".to_string(),
));
}
if new_member.role == crate::models::teams::OWNER_ROLE {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"The `Owner` role is restricted to one person".to_string(),
));
}
@@ -207,11 +207,11 @@ pub async fn add_team_member(
if let Some(req) = request {
if req.accepted {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"The user is already a member of that team".to_string(),
));
} else {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"There is already a pending member request for this user"
.to_string(),
));
@@ -221,9 +221,7 @@ pub async fn add_team_member(
crate::database::models::User::get(member.user_id, &**pool)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
"An invalid User ID specified".to_string(),
)
ApiError::InvalidInput("An invalid User ID specified".to_string())
})?;
let new_id =
@@ -312,7 +310,7 @@ pub async fn edit_team_member(
TeamMember::get_from_user_id(id, current_user.id.into(), &**pool)
.await?
.ok_or_else(|| {
ApiError::CustomAuthenticationError(
ApiError::CustomAuthentication(
"You don't have permission to edit members of this team"
.to_string(),
)
@@ -321,7 +319,7 @@ pub async fn edit_team_member(
TeamMember::get_from_user_id_pending(id, user_id, &**pool)
.await?
.ok_or_else(|| {
ApiError::CustomAuthenticationError(
ApiError::CustomAuthentication(
"You don't have permission to edit members of this team"
.to_string(),
)
@@ -330,13 +328,13 @@ pub async fn edit_team_member(
let mut transaction = pool.begin().await?;
if &*edit_member_db.role == crate::models::teams::OWNER_ROLE {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"The owner of a team cannot be edited".to_string(),
));
}
if !member.permissions.contains(Permissions::EDIT_MEMBER) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit members of this team"
.to_string(),
));
@@ -344,7 +342,7 @@ pub async fn edit_team_member(
if let Some(new_permissions) = edit_member.permissions {
if !member.permissions.contains(new_permissions) {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"The new permissions have permissions that you don't have"
.to_string(),
));
@@ -352,7 +350,7 @@ pub async fn edit_team_member(
}
if edit_member.role.as_deref() == Some(crate::models::teams::OWNER_ROLE) {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"The `Owner` role is restricted to one person".to_string(),
));
}
@@ -394,7 +392,7 @@ pub async fn transfer_ownership(
)
.await?
.ok_or_else(|| {
ApiError::CustomAuthenticationError(
ApiError::CustomAuthentication(
"You don't have permission to edit members of this team"
.to_string(),
)
@@ -406,20 +404,20 @@ pub async fn transfer_ownership(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"The new owner specified does not exist".to_string(),
)
})?;
if member.role != crate::models::teams::OWNER_ROLE {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit the ownership of this team"
.to_string(),
));
}
if !new_member.accepted {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"You can only transfer ownership to members who are currently in your team".to_string(),
));
}
@@ -466,7 +464,7 @@ pub async fn remove_team_member(
TeamMember::get_from_user_id(id, current_user.id.into(), &**pool)
.await?
.ok_or_else(|| {
ApiError::CustomAuthenticationError(
ApiError::CustomAuthentication(
"You don't have permission to edit members of this team"
.to_string(),
)
@@ -478,7 +476,7 @@ pub async fn remove_team_member(
if let Some(delete_member) = delete_member {
if delete_member.role == crate::models::teams::OWNER_ROLE {
// The owner cannot be removed from a team
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"The owner can't be removed from a team".to_string(),
));
}
@@ -492,7 +490,7 @@ pub async fn remove_team_member(
{
TeamMember::delete(id, user_id, &**pool).await?;
} else {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have permission to remove a member from this team".to_string(),
));
}
@@ -505,7 +503,7 @@ pub async fn remove_team_member(
// permission can remove it.
TeamMember::delete(id, user_id, &**pool).await?;
} else {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have permission to cancel a team invite"
.to_string(),
));

View File

@@ -24,12 +24,12 @@ pub async fn forge_updates(
&id, &**pool,
)
.await?
.ok_or_else(|| ApiError::InvalidInputError(ERROR.to_string()))?;
.ok_or_else(|| ApiError::InvalidInput(ERROR.to_string()))?;
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
if !is_authorized(&project, &user_option, &pool).await? {
return Err(ApiError::InvalidInputError(ERROR.to_string()));
return Err(ApiError::InvalidInput(ERROR.to_string()));
}
let version_ids = database::models::Version::get_project_versions(

View File

@@ -166,7 +166,7 @@ pub async fn user_edit(
let user = get_user_from_headers(req.headers(), &**pool).await?;
new_user.validate().map_err(|err| {
ApiError::ValidationError(validation_errors_to_string(err, None))
ApiError::Validation(validation_errors_to_string(err, None))
})?;
let id_option = crate::database::models::User::get_id_from_username_or_id(
@@ -201,7 +201,7 @@ pub async fn user_edit(
.execute(&mut *transaction)
.await?;
} else {
return Err(ApiError::InvalidInputError(format!(
return Err(ApiError::InvalidInput(format!(
"Username {} is taken!",
username
)));
@@ -252,7 +252,7 @@ pub async fn user_edit(
if let Some(role) = &new_user.role {
if !user.role.is_mod() {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit the role of this user!"
.to_string(),
));
@@ -276,7 +276,7 @@ pub async fn user_edit(
transaction.commit().await?;
Ok(HttpResponse::NoContent().body(""))
} else {
Err(ApiError::CustomAuthenticationError(
Err(ApiError::CustomAuthentication(
"You do not have permission to edit this user!".to_string(),
))
}
@@ -313,7 +313,7 @@ pub async fn user_icon_edit(
if let Some(id) = id_option {
if user.id != id.into() && !user.role.is_mod() {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to edit this user's icon."
.to_string(),
));
@@ -374,7 +374,7 @@ pub async fn user_icon_edit(
Ok(HttpResponse::NotFound().body(""))
}
} else {
Err(ApiError::InvalidInputError(format!(
Err(ApiError::InvalidInput(format!(
"Invalid format for user icon: {}",
ext.ext
)))
@@ -407,24 +407,18 @@ pub async fn user_delete(
if let Some(id) = id_option {
if !user.role.is_mod() && user.id != id.into() {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have permission to delete this user!".to_string(),
));
}
let mut transaction = pool.begin().await?;
let result;
if &*removal_type.removal_type == "full" {
result = crate::database::models::User::remove_full(
id,
&mut transaction,
)
.await?;
let result = if &*removal_type.removal_type == "full" {
crate::database::models::User::remove_full(id, &mut transaction)
.await?
} else {
result =
crate::database::models::User::remove(id, &mut transaction)
.await?;
crate::database::models::User::remove(id, &mut transaction).await?
};
transaction.commit().await?;
@@ -454,7 +448,7 @@ pub async fn user_follows(
if let Some(id) = id_option {
if !user.role.is_mod() && user.id != id.into() {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have permission to see the projects this user follows!".to_string(),
));
}
@@ -504,7 +498,7 @@ pub async fn user_notifications(
if let Some(id) = id_option {
if !user.role.is_mod() && user.id != id.into() {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have permission to see the notifications of this user!".to_string(),
));
}

View File

@@ -64,7 +64,7 @@ pub async fn report_create(
let mut bytes = web::BytesMut::new();
while let Some(item) = body.next().await {
bytes.extend_from_slice(&item.map_err(|_| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"Error while parsing request payload!".to_string(),
)
})?);
@@ -79,7 +79,7 @@ pub async fn report_create(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(format!(
ApiError::InvalidInput(format!(
"Invalid report type: {}",
new_report.report_type
))
@@ -124,7 +124,7 @@ pub async fn report_create(
)
}
ItemType::Unknown => {
return Err(ApiError::InvalidInputError(format!(
return Err(ApiError::InvalidInput(format!(
"Invalid report item type: {}",
new_report.item_type.as_str()
)))

View File

@@ -38,7 +38,7 @@ pub async fn category_create(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"Specified project type does not exist!".to_string(),
)
})?;

View File

@@ -42,7 +42,7 @@ pub async fn team_members_get(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?;
.map_err(ApiError::Database)?;
if team_member.is_some() {
let team_members: Vec<TeamMember> = members_data

View File

@@ -66,7 +66,7 @@ pub async fn user_follows(
if let Some(id) = id_option {
if !user.role.is_mod() && user.id != id.into() {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have permission to see the projects this user follows!".to_string(),
));
}

View File

@@ -269,7 +269,7 @@ pub async fn download_version(
)
.fetch_optional(&**pool)
.await
.map_err(|e| ApiError::DatabaseError(e.into()))?;
.map_err(|e| ApiError::Database(e.into()))?;
if let Some(id) = result {
Ok(HttpResponse::TemporaryRedirect()
@@ -316,9 +316,9 @@ pub async fn delete_file(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::CustomAuthenticationError(
ApiError::CustomAuthentication(
"You don't have permission to delete this file!"
.to_string(),
)
@@ -328,7 +328,7 @@ pub async fn delete_file(
.permissions
.contains(Permissions::DELETE_VERSION)
{
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to delete this file!"
.to_string(),
));

View File

@@ -103,7 +103,7 @@ pub async fn version_create(
async fn version_create_inner(
req: HttpRequest,
mut payload: Multipart,
mut transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
file_host: &dyn FileHost,
uploaded_files: &mut Vec<UploadedFile>,
) -> Result<HttpResponse, CreateError> {
@@ -322,7 +322,7 @@ async fn version_create_inner(
all_game_versions.clone(),
version_data.primary_file.is_some(),
version_data.primary_file.as_deref() == Some(name),
&mut transaction,
transaction,
)
.await?;
}
@@ -486,7 +486,7 @@ async fn upload_file_to_version_inner(
req: HttpRequest,
mut payload: Multipart,
client: Data<PgPool>,
mut transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
file_host: &dyn FileHost,
uploaded_files: &mut Vec<UploadedFile>,
version_id: models::VersionId,
@@ -597,7 +597,7 @@ async fn upload_file_to_version_inner(
all_game_versions.clone(),
true,
false,
&mut transaction,
transaction,
)
.await?;
}

View File

@@ -135,9 +135,9 @@ pub async fn delete_file(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::CustomAuthenticationError(
ApiError::CustomAuthentication(
"You don't have permission to delete this file!"
.to_string(),
)
@@ -147,7 +147,7 @@ pub async fn delete_file(
.permissions
.contains(Permissions::DELETE_VERSION)
{
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You don't have permission to delete this file!"
.to_string(),
));
@@ -169,7 +169,7 @@ pub async fn delete_file(
.await?;
if files.len() < 2 {
return Err(ApiError::InvalidInputError(
return Err(ApiError::InvalidInput(
"Versions must have at least one file uploaded to them"
.to_string(),
));

View File

@@ -28,9 +28,10 @@ pub async fn version_list(
) -> Result<HttpResponse, ApiError> {
let string = info.into_inner().0;
let result =
database::models::Project::get_full_from_slug_or_project_id(&string, &**pool)
.await?;
let result = database::models::Project::get_full_from_slug_or_project_id(
&string, &**pool,
)
.await?;
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
@@ -187,6 +188,7 @@ pub struct EditVersion {
pub loaders: Option<Vec<models::projects::Loader>>,
pub featured: Option<bool>,
pub primary_file: Option<(String, String)>,
pub downloads: Option<u32>,
}
#[patch("{id}")]
@@ -199,7 +201,7 @@ pub async fn version_edit(
let user = get_user_from_headers(req.headers(), &**pool).await?;
new_version.validate().map_err(|err| {
ApiError::ValidationError(validation_errors_to_string(err, None))
ApiError::Validation(validation_errors_to_string(err, None))
})?;
let version_id = info.into_inner().0;
@@ -227,7 +229,7 @@ pub async fn version_edit(
if let Some(perms) = permissions {
if !perms.contains(Permissions::UPLOAD_VERSION) {
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have the permissions to edit this version!"
.to_string(),
));
@@ -321,7 +323,7 @@ pub async fn version_edit(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"No database entry for game version provided."
.to_string(),
)
@@ -358,7 +360,7 @@ pub async fn version_edit(
)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"No database entry for loader provided."
.to_string(),
)
@@ -404,7 +406,7 @@ pub async fn version_edit(
.fetch_optional(&**pool)
.await?
.ok_or_else(|| {
ApiError::InvalidInputError(format!(
ApiError::InvalidInput(format!(
"Specified file with hash {} does not exist.",
primary_file.1.clone()
))
@@ -447,10 +449,38 @@ pub async fn version_edit(
.await?;
}
if let Some(downloads) = &new_version.downloads {
sqlx::query!(
"
UPDATE versions
SET downloads = $1
WHERE (id = $2)
",
*downloads as i32,
id as database::models::ids::VersionId,
)
.execute(&mut *transaction)
.await?;
let diff = *downloads - (version_item.downloads as u32);
sqlx::query!(
"
UPDATE mods
SET downloads = downloads + $1
WHERE (id = $2)
",
diff as i32,
version_item.project_id as database::models::ids::ProjectId,
)
.execute(&mut *transaction)
.await?;
}
transaction.commit().await?;
Ok(HttpResponse::NoContent().body(""))
} else {
Err(ApiError::CustomAuthenticationError(
Err(ApiError::CustomAuthentication(
"You do not have permission to edit this version!".to_string(),
))
}
@@ -503,7 +533,7 @@ pub async fn version_count_patch(
.execute(pool.as_ref()),
)
.await
.map_err(ApiError::SqlxDatabaseError)?;
.map_err(ApiError::SqlxDatabase)?;
Ok(HttpResponse::Ok().body(""))
}
@@ -524,9 +554,9 @@ pub async fn version_delete(
&**pool,
)
.await
.map_err(ApiError::DatabaseError)?
.map_err(ApiError::Database)?
.ok_or_else(|| {
ApiError::InvalidInputError(
ApiError::InvalidInput(
"You do not have permission to delete versions in this team".to_string(),
)
})?;
@@ -535,7 +565,7 @@ pub async fn version_delete(
.permissions
.contains(Permissions::DELETE_VERSION)
{
return Err(ApiError::CustomAuthenticationError(
return Err(ApiError::CustomAuthentication(
"You do not have permission to delete versions in this team"
.to_string(),
));