feat (fs): add file download and delete
This commit is contained in:
parent
03af3e63b2
commit
54e5e09024
|
@ -0,0 +1,56 @@
|
||||||
|
use std::{fs, path::Path};
|
||||||
|
|
||||||
|
use axum::extract::Query;
|
||||||
|
use axum::Extension;
|
||||||
|
use axum_auth::AuthBearer;
|
||||||
|
use homedisk_database::Database;
|
||||||
|
use homedisk_types::{
|
||||||
|
config::types::Config,
|
||||||
|
errors::{FsError, ServerError},
|
||||||
|
fs::delete::Request,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::fs::validate_path;
|
||||||
|
use crate::middleware::{find_user, validate_jwt};
|
||||||
|
|
||||||
|
pub async fn handle(
|
||||||
|
Extension(db): Extension<Database>,
|
||||||
|
Extension(config): Extension<Config>,
|
||||||
|
AuthBearer(token): AuthBearer,
|
||||||
|
query: Query<Request>,
|
||||||
|
) -> Result<(), ServerError> {
|
||||||
|
// validate user token
|
||||||
|
let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?;
|
||||||
|
|
||||||
|
// validate the `path` can be used
|
||||||
|
validate_path(&query.path)?;
|
||||||
|
|
||||||
|
// search for a user by UUID from a token
|
||||||
|
let user = find_user(db, token.claims.sub).await?;
|
||||||
|
|
||||||
|
// path to the file
|
||||||
|
let path = format!(
|
||||||
|
"{user_dir}/{request_path}",
|
||||||
|
user_dir = user.user_dir(&config.storage.path),
|
||||||
|
request_path = query.path
|
||||||
|
);
|
||||||
|
let path = Path::new(&path);
|
||||||
|
|
||||||
|
// if file does not exist return error
|
||||||
|
if !path.exists() {
|
||||||
|
return Err(ServerError::FsError(FsError::FileDoesNotExist));
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete file
|
||||||
|
if path.is_file() {
|
||||||
|
fs::remove_file(&path)
|
||||||
|
.map_err(|err| ServerError::FsError(FsError::DeleteFile(err.to_string())))?;
|
||||||
|
}
|
||||||
|
// delete directory
|
||||||
|
else if path.is_dir() {
|
||||||
|
fs::remove_dir(&path)
|
||||||
|
.map_err(|err| ServerError::FsError(FsError::DeleteDirectory(err.to_string())))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::{fs, io};
|
||||||
|
|
||||||
|
use crate::fs::validate_path;
|
||||||
|
use axum::extract::Query;
|
||||||
|
use axum::{extract::rejection::JsonRejection, Extension, Json};
|
||||||
|
use axum_auth::AuthBearer;
|
||||||
|
use byte_unit::Byte;
|
||||||
|
use homedisk_database::Database;
|
||||||
|
use homedisk_types::fs::list::DirInfo;
|
||||||
|
use homedisk_types::fs::upload::Pagination;
|
||||||
|
use homedisk_types::{
|
||||||
|
config::types::Config,
|
||||||
|
errors::{FsError, ServerError},
|
||||||
|
fs::list::{FileInfo, Request, Response},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::middleware::{find_user, validate_json, validate_jwt};
|
||||||
|
|
||||||
|
pub async fn handle(
|
||||||
|
Extension(db): Extension<Database>,
|
||||||
|
Extension(config): Extension<Config>,
|
||||||
|
AuthBearer(token): AuthBearer,
|
||||||
|
query: Query<Pagination>,
|
||||||
|
) -> Result<Vec<u8>, ServerError> {
|
||||||
|
// validate token
|
||||||
|
let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?;
|
||||||
|
|
||||||
|
// validate the `path` can be used
|
||||||
|
validate_path(&query.path)?;
|
||||||
|
|
||||||
|
// search for a user by UUID from a token
|
||||||
|
let user = find_user(db, token.claims.sub).await?;
|
||||||
|
|
||||||
|
// directory where the file will be placed
|
||||||
|
let path = format!(
|
||||||
|
"{user_dir}/{req_dir}",
|
||||||
|
user_dir = user.user_dir(&config.storage.path),
|
||||||
|
req_dir = query.path
|
||||||
|
);
|
||||||
|
|
||||||
|
// read file content
|
||||||
|
let content = fs::read(path).unwrap();
|
||||||
|
|
||||||
|
Ok(content)
|
||||||
|
}
|
|
@ -59,10 +59,10 @@ pub async fn handle(
|
||||||
let mut dirs = vec![];
|
let mut dirs = vec![];
|
||||||
|
|
||||||
for f in paths {
|
for f in paths {
|
||||||
let f = f.map_err(|err| ServerError::FsError(FsError::UnknowError(err.to_string())))?;
|
let f = f.map_err(|err| ServerError::FsError(FsError::UnknownError(err.to_string())))?;
|
||||||
let metadata = f
|
let metadata = f
|
||||||
.metadata()
|
.metadata()
|
||||||
.map_err(|err| ServerError::FsError(FsError::UnknowError(err.to_string())))?;
|
.map_err(|err| ServerError::FsError(FsError::UnknownError(err.to_string())))?;
|
||||||
|
|
||||||
let name = f.path().display().to_string().replace(&path, "");
|
let name = f.path().display().to_string().replace(&path, "");
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
|
pub mod delete;
|
||||||
|
pub mod download;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod upload;
|
pub mod upload;
|
||||||
|
|
||||||
pub fn app() -> axum::Router {
|
pub fn app() -> axum::Router {
|
||||||
use axum::routing::post;
|
use axum::routing::{delete, get, post};
|
||||||
|
|
||||||
axum::Router::new()
|
axum::Router::new()
|
||||||
.route("/list", post(list::handle))
|
.route("/list", post(list::handle))
|
||||||
.route("/upload", post(upload::handle))
|
.route("/upload", post(upload::handle))
|
||||||
|
.route("/delete", delete(upload::handle))
|
||||||
|
.route("/download", get(download::handle))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_path(path: &str) -> Result<(), homedisk_types::errors::ServerError> {
|
pub fn validate_path(path: &str) -> Result<(), homedisk_types::errors::ServerError> {
|
||||||
|
|
|
@ -5,12 +5,21 @@ pub enum Error {
|
||||||
#[error("file already exists")]
|
#[error("file already exists")]
|
||||||
FileAlreadyExists,
|
FileAlreadyExists,
|
||||||
|
|
||||||
|
#[error("file doesn't exists")]
|
||||||
|
FileDoesNotExist,
|
||||||
|
|
||||||
#[error("unexpected multipart error")]
|
#[error("unexpected multipart error")]
|
||||||
MultipartError,
|
MultipartError,
|
||||||
|
|
||||||
#[error("create file - {0}")]
|
#[error("create file - {0}")]
|
||||||
CreateFile(String),
|
CreateFile(String),
|
||||||
|
|
||||||
|
#[error("delete file - {0}")]
|
||||||
|
DeleteFile(String),
|
||||||
|
|
||||||
|
#[error("delete dir - {0}")]
|
||||||
|
DeleteDirectory(String),
|
||||||
|
|
||||||
#[error("write file - {0}")]
|
#[error("write file - {0}")]
|
||||||
WriteFile(String),
|
WriteFile(String),
|
||||||
|
|
||||||
|
@ -20,6 +29,6 @@ pub enum Error {
|
||||||
#[error("read dir - {0}")]
|
#[error("read dir - {0}")]
|
||||||
ReadDir(String),
|
ReadDir(String),
|
||||||
|
|
||||||
#[error("unknow error")]
|
#[error("unknown error")]
|
||||||
UnknowError(String),
|
UnknownError(String),
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,13 +51,16 @@ impl axum::response::IntoResponse for ServerError {
|
||||||
AuthError::UnknownError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
AuthError::UnknownError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
},
|
},
|
||||||
Self::FsError(ref err) => match err {
|
Self::FsError(ref err) => match err {
|
||||||
FsError::MultipartError => StatusCode::BAD_REQUEST,
|
|
||||||
FsError::FileAlreadyExists => StatusCode::BAD_REQUEST,
|
FsError::FileAlreadyExists => StatusCode::BAD_REQUEST,
|
||||||
|
FsError::FileDoesNotExist => StatusCode::BAD_REQUEST,
|
||||||
|
FsError::MultipartError => StatusCode::BAD_REQUEST,
|
||||||
FsError::CreateFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
FsError::CreateFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
FsError::DeleteFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
FsError::DeleteDirectory(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
FsError::WriteFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
FsError::WriteFile(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
FsError::Base64(_) => StatusCode::BAD_REQUEST,
|
FsError::Base64(_) => StatusCode::BAD_REQUEST,
|
||||||
FsError::ReadDir(_) => StatusCode::BAD_REQUEST,
|
FsError::ReadDir(_) => StatusCode::BAD_REQUEST,
|
||||||
FsError::UnknowError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
FsError::UnknownError(_) => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
},
|
},
|
||||||
Self::TooManyRequests => StatusCode::TOO_MANY_REQUESTS,
|
Self::TooManyRequests => StatusCode::TOO_MANY_REQUESTS,
|
||||||
Self::MissingJsonContentType => StatusCode::BAD_REQUEST,
|
Self::MissingJsonContentType => StatusCode::BAD_REQUEST,
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct Request {
|
||||||
|
pub path: String,
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct Request {
|
||||||
|
pub path: String,
|
||||||
|
}
|
|
@ -1,2 +1,4 @@
|
||||||
|
pub mod delete;
|
||||||
|
pub mod download;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod upload;
|
pub mod upload;
|
||||||
|
|
Loading…
Reference in New Issue