Error handling
This commit is contained in:
		@@ -16,7 +16,7 @@ use rand::{rngs::OsRng, RngCore};
 | 
				
			|||||||
use serde::{Deserialize, Serialize};
 | 
					use serde::{Deserialize, Serialize};
 | 
				
			||||||
use subtle::ConstantTimeEq;
 | 
					use subtle::ConstantTimeEq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{db, errors::handle_error, Pool};
 | 
					use crate::{db, Pool};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const HASH_LENGTH: usize = 64;
 | 
					pub const HASH_LENGTH: usize = 64;
 | 
				
			||||||
pub const SALT_LENGTH: usize = 64;
 | 
					pub const SALT_LENGTH: usize = 64;
 | 
				
			||||||
@@ -186,7 +186,7 @@ where
 | 
				
			|||||||
            Ok(true) => Ok(claims),
 | 
					            Ok(true) => Ok(claims),
 | 
				
			||||||
            Ok(false) => Err(Error::WrongCredentials),
 | 
					            Ok(false) => Err(Error::WrongCredentials),
 | 
				
			||||||
            Err(err) => {
 | 
					            Err(err) => {
 | 
				
			||||||
                handle_error(err);
 | 
					                tracing::error!(%err);
 | 
				
			||||||
                Err(Error::Validation)
 | 
					                Err(Error::Validation)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,41 +32,39 @@ impl From<Option<PermissionRaw>> for PermissionType {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl From<PermissionType> for PermissionRaw {
 | 
					 | 
				
			||||||
    fn from(value: PermissionType) -> Self {
 | 
					 | 
				
			||||||
        match value {
 | 
					 | 
				
			||||||
            PermissionType::Manage => Self::Manage,
 | 
					 | 
				
			||||||
            PermissionType::Write => Self::Write,
 | 
					 | 
				
			||||||
            PermissionType::Read => Self::Read,
 | 
					 | 
				
			||||||
            PermissionType::NoPermission => unreachable!(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl PermissionType {
 | 
					impl PermissionType {
 | 
				
			||||||
    pub fn can_read(self) -> bool {
 | 
					    pub fn can_read(self) -> bool {
 | 
				
			||||||
        self >= PermissionType::Read
 | 
					        self >= PermissionType::Read
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn can_read_guard(self) -> Result<(), StatusCode> {
 | 
					    pub fn can_read_guard(self) -> GeneralResult<()> {
 | 
				
			||||||
        if !self.can_read() {
 | 
					        if !self.can_read() {
 | 
				
			||||||
            return Err(StatusCode::NOT_FOUND);
 | 
					            return Err(GeneralError::message(
 | 
				
			||||||
 | 
					                StatusCode::NOT_FOUND,
 | 
				
			||||||
 | 
					                "Item not found",
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn can_write_guard(self) -> Result<(), StatusCode> {
 | 
					    pub fn can_write_guard(self) -> GeneralResult<()> {
 | 
				
			||||||
        self.can_read_guard()?;
 | 
					        self.can_read_guard()?;
 | 
				
			||||||
        if self < PermissionType::Write {
 | 
					        if self < PermissionType::Write {
 | 
				
			||||||
            return Err(StatusCode::FORBIDDEN);
 | 
					            return Err(GeneralError::message(
 | 
				
			||||||
 | 
					                StatusCode::FORBIDDEN,
 | 
				
			||||||
 | 
					                "Cannot write to the folder",
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn can_manage_guard(self) -> Result<(), StatusCode> {
 | 
					    pub fn can_manage_guard(self) -> GeneralResult<()> {
 | 
				
			||||||
        self.can_read_guard()?;
 | 
					        self.can_read_guard()?;
 | 
				
			||||||
        if self < PermissionType::Manage {
 | 
					        if self < PermissionType::Manage {
 | 
				
			||||||
            return Err(StatusCode::FORBIDDEN);
 | 
					            return Err(GeneralError::message(
 | 
				
			||||||
 | 
					                StatusCode::FORBIDDEN,
 | 
				
			||||||
 | 
					                "Cannot manage the folder",
 | 
				
			||||||
 | 
					            ));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
pub use crate::prelude::*;
 | 
					use crate::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Deserialize, Debug)]
 | 
					#[derive(Deserialize, Debug)]
 | 
				
			||||||
pub struct Params {
 | 
					pub struct Params {
 | 
				
			||||||
@@ -9,24 +9,27 @@ pub async fn delete(
 | 
				
			|||||||
    Query(params): Query<Params>,
 | 
					    Query(params): Query<Params>,
 | 
				
			||||||
    State(state): State<AppState>,
 | 
					    State(state): State<AppState>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
) -> Result<StatusCode, StatusCode> {
 | 
					) -> GeneralResult<StatusCode> {
 | 
				
			||||||
    db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
 | 
					    db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .can_write_guard()?;
 | 
					        .can_write_guard()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let deleted = db::file::delete(params.file_id, &state.pool)
 | 
					    let deleted = db::file::delete(params.file_id, &state.pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error deleting the file")?;
 | 
				
			||||||
    if !deleted {
 | 
					    if !deleted {
 | 
				
			||||||
        return Err(StatusCode::NOT_FOUND); // Will not happen most of the time due to can write guard
 | 
					        return Err(GeneralError::message(
 | 
				
			||||||
 | 
					            StatusCode::NOT_FOUND,
 | 
				
			||||||
 | 
					            "Item not found",
 | 
				
			||||||
 | 
					        )); // Will not happen most of the time due to can write guard
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state
 | 
					    state
 | 
				
			||||||
        .storage
 | 
					        .storage
 | 
				
			||||||
        .delete(params.file_id)
 | 
					        .delete(params.file_id)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error deleting the file")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(StatusCode::NO_CONTENT)
 | 
					    Ok(StatusCode::NO_CONTENT)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,16 +12,16 @@ pub async fn download(
 | 
				
			|||||||
    Query(params): Query<Params>,
 | 
					    Query(params): Query<Params>,
 | 
				
			||||||
    State(state): State<AppState>,
 | 
					    State(state): State<AppState>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
) -> Result<impl IntoResponse, StatusCode> {
 | 
					) -> GeneralResult<impl IntoResponse> {
 | 
				
			||||||
    db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
 | 
					    db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .can_read_guard()?;
 | 
					        .can_read_guard()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut name = db::file::get_name(params.file_id, &state.pool)
 | 
					    let mut name = db::file::get_name(params.file_id, &state.pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .handle_internal("Error getting file info")?
 | 
				
			||||||
        .ok_or(StatusCode::NOT_FOUND)?;
 | 
					        .ok_or_else(GeneralError::item_not_found)?;
 | 
				
			||||||
    name = name
 | 
					    name = name
 | 
				
			||||||
        .chars()
 | 
					        .chars()
 | 
				
			||||||
        .fold(String::with_capacity(name.len()), |mut result, char| {
 | 
					        .fold(String::with_capacity(name.len()), |mut result, char| {
 | 
				
			||||||
@@ -32,7 +32,11 @@ pub async fn download(
 | 
				
			|||||||
            result
 | 
					            result
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let file = state.storage.read(params.file_id).await.handle_internal()?;
 | 
					    let file = state
 | 
				
			||||||
 | 
					        .storage
 | 
				
			||||||
 | 
					        .read(params.file_id)
 | 
				
			||||||
 | 
					        .await
 | 
				
			||||||
 | 
					        .handle_internal("Error reading the file")?;
 | 
				
			||||||
    let body = Body::from_stream(ReaderStream::new(file));
 | 
					    let body = Body::from_stream(ReaderStream::new(file));
 | 
				
			||||||
    let disposition = format!("attachment; filename=\"{name}\"");
 | 
					    let disposition = format!("attachment; filename=\"{name}\"");
 | 
				
			||||||
    let headers = [(header::CONTENT_DISPOSITION, disposition)];
 | 
					    let headers = [(header::CONTENT_DISPOSITION, disposition)];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,10 +12,10 @@ pub async fn modify(
 | 
				
			|||||||
    State(state): State<AppState>,
 | 
					    State(state): State<AppState>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
    mut multipart: Multipart,
 | 
					    mut multipart: Multipart,
 | 
				
			||||||
) -> Result<StatusCode, StatusCode> {
 | 
					) -> GeneralResult<StatusCode> {
 | 
				
			||||||
    db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
 | 
					    db::file::get_permissions(params.file_id, claims.user_id, &state.pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .can_write_guard()?;
 | 
					        .can_write_guard()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Very weird work around to get the first file in multipart
 | 
					    // Very weird work around to get the first file in multipart
 | 
				
			||||||
@@ -23,7 +23,12 @@ pub async fn modify(
 | 
				
			|||||||
        match multipart.next_field().await {
 | 
					        match multipart.next_field().await {
 | 
				
			||||||
            Ok(Some(field)) if field.file_name().is_some() => break field,
 | 
					            Ok(Some(field)) if field.file_name().is_some() => break field,
 | 
				
			||||||
            Ok(Some(_)) => continue,
 | 
					            Ok(Some(_)) => continue,
 | 
				
			||||||
            _ => return Err(StatusCode::BAD_REQUEST),
 | 
					            _ => {
 | 
				
			||||||
 | 
					                return Err(GeneralError::message(
 | 
				
			||||||
 | 
					                    StatusCode::BAD_REQUEST,
 | 
				
			||||||
 | 
					                    "No file in the multipart",
 | 
				
			||||||
 | 
					                ))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,19 +36,22 @@ pub async fn modify(
 | 
				
			|||||||
        .storage
 | 
					        .storage
 | 
				
			||||||
        .write(params.file_id)
 | 
					        .write(params.file_id)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .handle_internal("Error writing to the file")?
 | 
				
			||||||
        .ok_or(StatusCode::NOT_FOUND)?;
 | 
					        .ok_or_else(GeneralError::item_not_found)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let (hash, size) = crate::FileStorage::write_to_file(&mut file, &mut field)
 | 
					    let (hash, size) = crate::FileStorage::write_to_file(&mut file, &mut field)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .map_err(|err| {
 | 
					        .map_err(|err| {
 | 
				
			||||||
            tracing::warn!(%err);
 | 
					            tracing::warn!(%err);
 | 
				
			||||||
            StatusCode::INTERNAL_SERVER_ERROR
 | 
					            GeneralError::message(
 | 
				
			||||||
 | 
					                StatusCode::INTERNAL_SERVER_ERROR,
 | 
				
			||||||
 | 
					                "Error writing to the file",
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        })?;
 | 
					        })?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    db::file::update(params.file_id, size, hash, &state.pool)
 | 
					    db::file::update(params.file_id, size, hash, &state.pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error updating the file")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(StatusCode::NO_CONTENT)
 | 
					    Ok(StatusCode::NO_CONTENT)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -36,16 +36,16 @@ pub async fn upload(
 | 
				
			|||||||
    State(state): State<AppState>,
 | 
					    State(state): State<AppState>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
    mut multi: Multipart,
 | 
					    mut multi: Multipart,
 | 
				
			||||||
) -> Result<Json<HashMap<String, Uuid>>, StatusCode> {
 | 
					) -> GeneralResult<Json<HashMap<String, Uuid>>> {
 | 
				
			||||||
    db::folder::get_permissions(params.parent_folder, claims.user_id, &state.pool)
 | 
					    db::folder::get_permissions(params.parent_folder, claims.user_id, &state.pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .can_write_guard()?;
 | 
					        .can_write_guard()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let existing_names: HashSet<String> = db::folder::get_names(params.parent_folder, &state.pool)
 | 
					    let existing_names: HashSet<String> = db::folder::get_names(params.parent_folder, &state.pool)
 | 
				
			||||||
        .try_collect()
 | 
					        .try_collect()
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error getting existing names")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut result = HashMap::new();
 | 
					    let mut result = HashMap::new();
 | 
				
			||||||
    while let Ok(Some(mut field)) = multi.next_field().await {
 | 
					    while let Ok(Some(mut field)) = multi.next_field().await {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,22 +10,24 @@ pub async fn create(
 | 
				
			|||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
    Json(params): Json<Params>,
 | 
					    Json(params): Json<Params>,
 | 
				
			||||||
) -> Result<Json<Uuid>, StatusCode> {
 | 
					) -> GeneralResult<Json<Uuid>> {
 | 
				
			||||||
    db::folder::get_permissions(params.parent_folder_id, claims.user_id, &pool)
 | 
					    db::folder::get_permissions(params.parent_folder_id, claims.user_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .can_write_guard()?;
 | 
					        .can_write_guard()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let exists = db::folder::name_exists(params.parent_folder_id, ¶ms.folder_name, &pool)
 | 
					    let exists = db::folder::name_exists(params.parent_folder_id, ¶ms.folder_name, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error getting existing names")?;
 | 
				
			||||||
    if exists {
 | 
					    if exists {
 | 
				
			||||||
        return Err(StatusCode::CONFLICT);
 | 
					        return Err(GeneralError::message(
 | 
				
			||||||
 | 
					            StatusCode::CONFLICT,
 | 
				
			||||||
 | 
					            "Name already taken",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let id = db::folder::insert(params.parent_folder_id, ¶ms.folder_name, &pool)
 | 
					    db::folder::insert(params.parent_folder_id, ¶ms.folder_name, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error creating the folder")
 | 
				
			||||||
 | 
					        .map(Json)
 | 
				
			||||||
    Ok(Json(id))
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,17 +9,20 @@ pub async fn delete(
 | 
				
			|||||||
    State(state): State<AppState>,
 | 
					    State(state): State<AppState>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
    Json(params): Json<Params>,
 | 
					    Json(params): Json<Params>,
 | 
				
			||||||
) -> Result<(), StatusCode> {
 | 
					) -> GeneralResult<()> {
 | 
				
			||||||
    let root = db::folder::get_root(claims.user_id, &state.pool)
 | 
					    let root = db::folder::get_root(claims.user_id, &state.pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error getting the root folder")?;
 | 
				
			||||||
    if params.folder_id == root {
 | 
					    if params.folder_id == root {
 | 
				
			||||||
        return Err(StatusCode::BAD_REQUEST);
 | 
					        return Err(GeneralError::message(
 | 
				
			||||||
 | 
					            StatusCode::BAD_REQUEST,
 | 
				
			||||||
 | 
					            "Cannot delete the root folder",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    db::folder::get_permissions(params.folder_id, claims.user_id, &state.pool)
 | 
					    db::folder::get_permissions(params.folder_id, claims.user_id, &state.pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .can_write_guard()?;
 | 
					        .can_write_guard()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let storage = &state.storage;
 | 
					    let storage = &state.storage;
 | 
				
			||||||
@@ -29,5 +32,5 @@ pub async fn delete(
 | 
				
			|||||||
            Ok(())
 | 
					            Ok(())
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()
 | 
					        .handle_internal("Error deleting the fodler")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,16 +25,16 @@ pub async fn structure(
 | 
				
			|||||||
    Query(params): Query<Params>,
 | 
					    Query(params): Query<Params>,
 | 
				
			||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
) -> Result<Json<FolderStructure>, StatusCode> {
 | 
					) -> GeneralResult<Json<FolderStructure>> {
 | 
				
			||||||
    let folder_id = db::folder::process_id(params.folder_id, claims.user_id, &pool)
 | 
					    let folder_id = db::folder::process_id(params.folder_id, claims.user_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .ok_or(StatusCode::NOT_FOUND)?;
 | 
					        .ok_or_else(GeneralError::item_not_found)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let folder = db::folder::get_by_id(folder_id, &pool)
 | 
					    let folder = db::folder::get_by_id(folder_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .handle_internal("Error getting folder info")?
 | 
				
			||||||
        .ok_or(StatusCode::NOT_FOUND)?;
 | 
					        .ok_or_else(GeneralError::item_not_found)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let mut response: FolderStructure = folder.into();
 | 
					    let mut response: FolderStructure = folder.into();
 | 
				
			||||||
    let mut stack = vec![&mut response];
 | 
					    let mut stack = vec![&mut response];
 | 
				
			||||||
@@ -45,7 +45,7 @@ pub async fn structure(
 | 
				
			|||||||
                .map_ok(Into::into)
 | 
					                .map_ok(Into::into)
 | 
				
			||||||
                .try_collect()
 | 
					                .try_collect()
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error getting folder contents")?;
 | 
				
			||||||
        folder.folders = folders;
 | 
					        folder.folders = folders;
 | 
				
			||||||
        folder.files = files;
 | 
					        folder.files = files;
 | 
				
			||||||
        stack.extend(folder.folders.iter_mut());
 | 
					        stack.extend(folder.folders.iter_mut());
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,17 +18,17 @@ pub async fn list(
 | 
				
			|||||||
    Query(params): Query<Params>,
 | 
					    Query(params): Query<Params>,
 | 
				
			||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
) -> Result<Json<Response>, StatusCode> {
 | 
					) -> GeneralResult<Json<Response>> {
 | 
				
			||||||
    let folder_id = db::folder::process_id(params.folder_id, claims.user_id, &pool)
 | 
					    let folder_id = db::folder::process_id(params.folder_id, claims.user_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .ok_or(StatusCode::NOT_FOUND)?;
 | 
					        .handle(StatusCode::NOT_FOUND, "Item not found")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let (files, folders) = try_join!(
 | 
					    let (files, folders) = try_join!(
 | 
				
			||||||
        db::file::get_files(folder_id, &pool).try_collect(),
 | 
					        db::file::get_files(folder_id, &pool).try_collect(),
 | 
				
			||||||
        db::folder::get_folders(folder_id, claims.user_id, &pool).try_collect()
 | 
					        db::folder::get_folders(folder_id, claims.user_id, &pool).try_collect()
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .handle_internal()?;
 | 
					    .handle_internal("Error getting folder contents")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(Json(Response {
 | 
					    Ok(Json(Response {
 | 
				
			||||||
        folder_id,
 | 
					        folder_id,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,17 +10,17 @@ pub async fn delete(
 | 
				
			|||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
    Json(params): Json<Params>,
 | 
					    Json(params): Json<Params>,
 | 
				
			||||||
) -> Result<StatusCode, StatusCode> {
 | 
					) -> GeneralResult<StatusCode> {
 | 
				
			||||||
    if params.user_id != claims.user_id {
 | 
					    if params.user_id != claims.user_id {
 | 
				
			||||||
        db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
 | 
					        db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
 | 
				
			||||||
            .await
 | 
					            .await
 | 
				
			||||||
            .handle_internal()?
 | 
					            .map_err(GeneralError::permissions)?
 | 
				
			||||||
            .can_manage_guard()?;
 | 
					            .can_manage_guard()?;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    db::permissions::delete_for_folder(params.folder_id, params.user_id, &pool)
 | 
					    db::permissions::delete_for_folder(params.folder_id, params.user_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error deleting the permissions")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(StatusCode::NO_CONTENT)
 | 
					    Ok(StatusCode::NO_CONTENT)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,14 +13,14 @@ pub async fn get(
 | 
				
			|||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    Query(params): Query<Params>,
 | 
					    Query(params): Query<Params>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
) -> Result<Json<HashMap<String, PermissionRaw>>, StatusCode> {
 | 
					) -> GeneralResult<Json<HashMap<String, PermissionRaw>>> {
 | 
				
			||||||
    db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
 | 
					    db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .can_manage_guard()?;
 | 
					        .can_manage_guard()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let permissions = db::permissions::get_all_for_folder(params.folder_id, &pool)
 | 
					    let permissions = db::permissions::get_all_for_folder(params.folder_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error getting permissions")?;
 | 
				
			||||||
    Ok(Json(permissions))
 | 
					    Ok(Json(permissions))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,9 +3,9 @@ use crate::prelude::*;
 | 
				
			|||||||
pub async fn get_top_level(
 | 
					pub async fn get_top_level(
 | 
				
			||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
) -> Result<Json<Vec<Uuid>>, StatusCode> {
 | 
					) -> GeneralResult<Json<Vec<Uuid>>> {
 | 
				
			||||||
    let folders = db::permissions::get_top_level_permitted_folders(claims.user_id, &pool)
 | 
					    let folders = db::permissions::get_top_level_permitted_folders(claims.user_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error reading from the database")?;
 | 
				
			||||||
    Ok(Json(folders))
 | 
					    Ok(Json(folders))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,4 @@
 | 
				
			|||||||
use db::permissions::PermissionRaw;
 | 
					use crate::{db::permissions::PermissionRaw, prelude::*};
 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::prelude::*;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Deserialize, Debug)]
 | 
					#[derive(Deserialize, Debug)]
 | 
				
			||||||
pub struct Params {
 | 
					pub struct Params {
 | 
				
			||||||
@@ -13,25 +11,31 @@ pub async fn set(
 | 
				
			|||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    Json(params): Json<Params>,
 | 
					    Json(params): Json<Params>,
 | 
				
			||||||
) -> Result<StatusCode, StatusCode> {
 | 
					) -> GeneralResult<StatusCode> {
 | 
				
			||||||
    let root = db::folder::get_root(claims.user_id, &pool)
 | 
					    let root = db::folder::get_root(claims.user_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?;
 | 
					        .handle_internal("Error getting the root folder")?;
 | 
				
			||||||
    if params.folder_id == root {
 | 
					    if params.folder_id == root {
 | 
				
			||||||
        return Err(StatusCode::BAD_REQUEST);
 | 
					        return Err(GeneralError::message(
 | 
				
			||||||
 | 
					            StatusCode::BAD_REQUEST,
 | 
				
			||||||
 | 
					            "Cannot delete the root folder",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
 | 
					    db::folder::get_permissions(params.folder_id, claims.user_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .map_err(GeneralError::permissions)?
 | 
				
			||||||
        .can_manage_guard()?;
 | 
					        .can_manage_guard()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let folder_info = db::folder::get_by_id(params.folder_id, &pool)
 | 
					    let folder_info = db::folder::get_by_id(params.folder_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .handle_internal("Error getting folder info")?
 | 
				
			||||||
        .ok_or(StatusCode::NOT_FOUND)?;
 | 
					        .ok_or_else(GeneralError::item_not_found)?;
 | 
				
			||||||
    if folder_info.owner_id == params.user_id {
 | 
					    if folder_info.owner_id == params.user_id {
 | 
				
			||||||
        return Err(StatusCode::BAD_REQUEST);
 | 
					        return Err(GeneralError::message(
 | 
				
			||||||
 | 
					            StatusCode::BAD_REQUEST,
 | 
				
			||||||
 | 
					            "Cannot set permissions of the folder owner",
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    db::permissions::insert(
 | 
					    db::permissions::insert(
 | 
				
			||||||
@@ -41,7 +45,7 @@ pub async fn set(
 | 
				
			|||||||
        &pool,
 | 
					        &pool,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    .await
 | 
					    .await
 | 
				
			||||||
    .handle_internal()?;
 | 
					    .handle_internal("Error writing to the database")?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(StatusCode::NO_CONTENT)
 | 
					    Ok(StatusCode::NO_CONTENT)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,12 +3,12 @@ use crate::prelude::*;
 | 
				
			|||||||
pub async fn delete(
 | 
					pub async fn delete(
 | 
				
			||||||
    State(AppState { pool, ref storage }): State<AppState>,
 | 
					    State(AppState { pool, ref storage }): State<AppState>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
) -> Result<(), StatusCode> {
 | 
					) -> GeneralResult<()> {
 | 
				
			||||||
    db::users::delete_user(claims.user_id, &pool)
 | 
					    db::users::delete_user(claims.user_id, &pool)
 | 
				
			||||||
        .try_for_each_concurrent(5, |file_id| async move {
 | 
					        .try_for_each_concurrent(5, |file_id| async move {
 | 
				
			||||||
            let _ = storage.delete(file_id).await;
 | 
					            let _ = storage.delete(file_id).await;
 | 
				
			||||||
            Ok(())
 | 
					            Ok(())
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()
 | 
					        .handle_internal("Error deleting the user")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,13 +5,13 @@ pub struct Params {
 | 
				
			|||||||
    user_id: i32,
 | 
					    user_id: i32,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Response = Result<Json<db::users::UserInfo>, StatusCode>;
 | 
					type Response = GeneralResult<Json<db::users::UserInfo>>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub async fn get(State(pool): State<Pool>, Query(params): Query<Params>) -> Response {
 | 
					pub async fn get(State(pool): State<Pool>, Query(params): Query<Params>) -> Response {
 | 
				
			||||||
    let info = db::users::get(params.user_id, &pool)
 | 
					    let info = db::users::get(params.user_id, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()?
 | 
					        .handle_internal("Error getting the user")?
 | 
				
			||||||
        .ok_or(StatusCode::NOT_FOUND)?;
 | 
					        .handle(StatusCode::NOT_FOUND, "User not found")?;
 | 
				
			||||||
    Ok(Json(info))
 | 
					    Ok(Json(info))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,13 +14,10 @@ pub async fn put(
 | 
				
			|||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    claims: Claims,
 | 
					    claims: Claims,
 | 
				
			||||||
    Json(params): Json<Params>,
 | 
					    Json(params): Json<Params>,
 | 
				
			||||||
) -> Result<Json<db::users::UserInfo>, (StatusCode, String)> {
 | 
					) -> GeneralResult<Json<db::users::UserInfo>> {
 | 
				
			||||||
    params
 | 
					    params.validate().map_err(GeneralError::validation)?;
 | 
				
			||||||
        .validate()
 | 
					 | 
				
			||||||
        .map_err(|err| (StatusCode::BAD_REQUEST, err.to_string()))?;
 | 
					 | 
				
			||||||
    db::users::update(claims.user_id, ¶ms.username, ¶ms.email, &pool)
 | 
					    db::users::update(claims.user_id, ¶ms.username, ¶ms.email, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()
 | 
					        .handle_internal("Error updating the user")
 | 
				
			||||||
        .map_err(|status| (status, String::new()))
 | 
					 | 
				
			||||||
        .map(Json)
 | 
					        .map(Json)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,22 +48,22 @@ fn validate_password(password: &str) -> Result<(), ValidationError> {
 | 
				
			|||||||
pub async fn register(
 | 
					pub async fn register(
 | 
				
			||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    Form(params): Form<Params>,
 | 
					    Form(params): Form<Params>,
 | 
				
			||||||
) -> Result<Json<Token>, Either<(StatusCode, String), Error>> {
 | 
					) -> Result<Json<Token>, Either<GeneralError, Error>> {
 | 
				
			||||||
    params
 | 
					    params
 | 
				
			||||||
        .validate()
 | 
					        .validate()
 | 
				
			||||||
        .map_err(|err| Either::E1((StatusCode::BAD_REQUEST, err.to_string())))?;
 | 
					        .map_err(GeneralError::validation)
 | 
				
			||||||
 | 
					        .map_err(Either::E1)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let password = HashedBytes::hash_bytes(params.password.as_bytes()).as_bytes();
 | 
					    let password = HashedBytes::hash_bytes(params.password.as_bytes()).as_bytes();
 | 
				
			||||||
    let Some(id) = db::users::create_user(¶ms.username, ¶ms.email, &password, &pool)
 | 
					    let id = db::users::create_user(¶ms.username, ¶ms.email, &password, &pool)
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()
 | 
					        .handle_internal("Error creating the user")
 | 
				
			||||||
        .map_err(|status| Either::E1((status, String::new())))?
 | 
					        .map_err(Either::E1)?
 | 
				
			||||||
    else {
 | 
					        .handle(
 | 
				
			||||||
        return Err(Either::E1((
 | 
					 | 
				
			||||||
            StatusCode::BAD_REQUEST,
 | 
					            StatusCode::BAD_REQUEST,
 | 
				
			||||||
            "Either the user name or the email are taken".to_owned(),
 | 
					            "The username or the email are taken",
 | 
				
			||||||
        )));
 | 
					        )
 | 
				
			||||||
    };
 | 
					        .map_err(Either::E1)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let token = Claims::new(id).encode().map_err(Either::E2)?;
 | 
					    let token = Claims::new(id).encode().map_err(Either::E2)?;
 | 
				
			||||||
    Ok(Json(token))
 | 
					    Ok(Json(token))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,12 +8,12 @@ pub struct Params {
 | 
				
			|||||||
pub async fn search(
 | 
					pub async fn search(
 | 
				
			||||||
    State(pool): State<Pool>,
 | 
					    State(pool): State<Pool>,
 | 
				
			||||||
    Query(params): Query<Params>,
 | 
					    Query(params): Query<Params>,
 | 
				
			||||||
) -> sqlx::Result<Json<Vec<db::users::UserSearch>>, StatusCode> {
 | 
					) -> GeneralResult<Json<Vec<db::users::UserSearch>>> {
 | 
				
			||||||
    db::users::search_for_user(¶ms.search_string, &pool)
 | 
					    db::users::search_for_user(¶ms.search_string, &pool)
 | 
				
			||||||
        .take(20)
 | 
					        .take(20)
 | 
				
			||||||
        .try_filter(|user| future::ready(user.similarity > 0.1))
 | 
					        .try_filter(|user| future::ready(user.similarity > 0.1))
 | 
				
			||||||
        .try_collect()
 | 
					        .try_collect()
 | 
				
			||||||
        .await
 | 
					        .await
 | 
				
			||||||
        .handle_internal()
 | 
					        .handle_internal("Error getting users from the database")
 | 
				
			||||||
        .map(Json)
 | 
					        .map(Json)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,28 +1,96 @@
 | 
				
			|||||||
use axum::http::StatusCode;
 | 
					use std::{borrow::Cow, convert::Infallible};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use axum::{http::StatusCode, response::IntoResponse};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type BoxError = Box<dyn std::error::Error>;
 | 
					type BoxError = Box<dyn std::error::Error>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn handle_error(error: impl Into<BoxError>) {
 | 
					pub struct GeneralError {
 | 
				
			||||||
    let error: BoxError = error.into();
 | 
					    pub status_code: StatusCode,
 | 
				
			||||||
    tracing::error!(error);
 | 
					    pub message: Cow<'static, str>,
 | 
				
			||||||
 | 
					    pub error: Option<BoxError>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub type GeneralResult<T> = Result<T, GeneralError>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl GeneralError {
 | 
				
			||||||
 | 
					    pub fn message(status_code: StatusCode, message: impl Into<Cow<'static, str>>) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            status_code,
 | 
				
			||||||
 | 
					            message: message.into(),
 | 
				
			||||||
 | 
					            error: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[allow(clippy::needless_pass_by_value)]
 | 
				
			||||||
 | 
					    pub fn validation(error: validator::ValidationErrors) -> Self {
 | 
				
			||||||
 | 
					        Self::message(StatusCode::BAD_REQUEST, error.to_string())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn permissions(error: sqlx::Error) -> Self {
 | 
				
			||||||
 | 
					        GeneralError {
 | 
				
			||||||
 | 
					            status_code: StatusCode::INTERNAL_SERVER_ERROR,
 | 
				
			||||||
 | 
					            message: Cow::Borrowed("Error getting permissions"),
 | 
				
			||||||
 | 
					            error: Some(error.into()),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub const fn item_not_found() -> Self {
 | 
				
			||||||
 | 
					        GeneralError {
 | 
				
			||||||
 | 
					            status_code: StatusCode::NOT_FOUND,
 | 
				
			||||||
 | 
					            message: Cow::Borrowed("Item not found"),
 | 
				
			||||||
 | 
					            error: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl IntoResponse for GeneralError {
 | 
				
			||||||
 | 
					    fn into_response(self) -> axum::response::Response {
 | 
				
			||||||
 | 
					        if let Some(err) = self.error {
 | 
				
			||||||
 | 
					            tracing::error!(err, message = %self.message, status_code = ?self.status_code);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        (self.status_code, self.message).into_response()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait ErrorHandlingExt<T, E>
 | 
					pub trait ErrorHandlingExt<T, E>
 | 
				
			||||||
where
 | 
					where
 | 
				
			||||||
    Self: Sized,
 | 
					    Self: Sized,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    fn handle(self, code: StatusCode) -> Result<T, StatusCode>;
 | 
					    fn handle(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        status_code: StatusCode,
 | 
				
			||||||
 | 
					        message: impl Into<Cow<'static, str>>,
 | 
				
			||||||
 | 
					    ) -> GeneralResult<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn handle_internal(self) -> Result<T, StatusCode> {
 | 
					    fn handle_internal(self, message: impl Into<Cow<'static, str>>) -> GeneralResult<T> {
 | 
				
			||||||
        self.handle(StatusCode::INTERNAL_SERVER_ERROR)
 | 
					        self.handle(StatusCode::INTERNAL_SERVER_ERROR, message)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T, E: Into<BoxError>> ErrorHandlingExt<T, E> for Result<T, E> {
 | 
					impl<T, E: Into<BoxError>> ErrorHandlingExt<T, E> for Result<T, E> {
 | 
				
			||||||
    fn handle(self, code: StatusCode) -> Result<T, StatusCode> {
 | 
					    fn handle(
 | 
				
			||||||
        self.map_err(|err| {
 | 
					        self,
 | 
				
			||||||
            handle_error(err);
 | 
					        status_code: StatusCode,
 | 
				
			||||||
            code
 | 
					        message: impl Into<Cow<'static, str>>,
 | 
				
			||||||
 | 
					    ) -> GeneralResult<T> {
 | 
				
			||||||
 | 
					        self.map_err(|err| GeneralError {
 | 
				
			||||||
 | 
					            status_code,
 | 
				
			||||||
 | 
					            message: message.into(),
 | 
				
			||||||
 | 
					            error: Some(err.into()),
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T> ErrorHandlingExt<T, Infallible> for Option<T> {
 | 
				
			||||||
 | 
					    fn handle(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        status_code: StatusCode,
 | 
				
			||||||
 | 
					        message: impl Into<Cow<'static, str>>,
 | 
				
			||||||
 | 
					    ) -> GeneralResult<T> {
 | 
				
			||||||
 | 
					        self.ok_or_else(|| GeneralError {
 | 
				
			||||||
 | 
					            status_code,
 | 
				
			||||||
 | 
					            message: message.into(),
 | 
				
			||||||
 | 
					            error: None,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,9 @@
 | 
				
			|||||||
pub(crate) use crate::{auth::Claims, db, errors::ErrorHandlingExt as _, AppState, Pool};
 | 
					pub(crate) use crate::{
 | 
				
			||||||
 | 
					    auth::Claims,
 | 
				
			||||||
 | 
					    db,
 | 
				
			||||||
 | 
					    errors::{ErrorHandlingExt as _, GeneralError, GeneralResult},
 | 
				
			||||||
 | 
					    AppState, Pool,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
pub use axum::{
 | 
					pub use axum::{
 | 
				
			||||||
    extract::{Json, Query, State},
 | 
					    extract::{Json, Query, State},
 | 
				
			||||||
    http::StatusCode,
 | 
					    http::StatusCode,
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user