chore: add app_file_handlers
This commit is contained in:
parent
fc0a3684af
commit
db96e0284a
10
app_file_handlers/.gitignore
vendored
Normal file
10
app_file_handlers/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/target
|
||||||
|
target
|
||||||
|
Cargo.lock
|
||||||
|
.cache
|
||||||
|
.temp
|
||||||
|
.env
|
||||||
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
logs
|
||||||
|
tmp
|
57
app_file_handlers/Cargo.toml
Normal file
57
app_file_handlers/Cargo.toml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
[package]
|
||||||
|
name = "app_file_handlers"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["JesusPerez <jpl@jesusperez.pro>"]
|
||||||
|
edition = "2018"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.40"
|
||||||
|
base64 = "0.13.0"
|
||||||
|
bytes = "1.0.1"
|
||||||
|
casbin = "2.0.7"
|
||||||
|
chrono = "0.4"
|
||||||
|
dotenv = "0.15.0"
|
||||||
|
envmnt = "0.9.0"
|
||||||
|
error-chain = "0.12.4"
|
||||||
|
glob = "0.3.0"
|
||||||
|
json = "0.12.4"
|
||||||
|
once_cell = "1.7.2"
|
||||||
|
parking_lot = "0.11.1"
|
||||||
|
rand = "0.8.3"
|
||||||
|
regex = "1.4.3"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_derive = "1.0.125"
|
||||||
|
serde_json = "1.0.64"
|
||||||
|
serde_yaml = "0.8.17"
|
||||||
|
slab = "0.4.3"
|
||||||
|
tempfile = "3.2.0"
|
||||||
|
tera = "1.8.0"
|
||||||
|
thiserror = "1.0.24"
|
||||||
|
toml = "0.5.8"
|
||||||
|
yaml-rust = "0.4"
|
||||||
|
tokio = { version = "1.5.0", features = ["full"] }
|
||||||
|
futures = { version = "0.3.14", default-features = false }
|
||||||
|
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||||
|
url = "2.2.1"
|
||||||
|
warp = { version = "0.3", features = ["default","websocket","tls","compression"] }
|
||||||
|
app_tools = { version = "0.1.0", path = "../../utils/app_tools" }
|
||||||
|
app_env = { version = "0.1.0", path = "../../defs/app_env" }
|
||||||
|
app_auth = { version = "0.1.0", path = "../../defs/app_auth" }
|
||||||
|
reqtasks = { version = "0.1.0", path = "../reqtasks" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pretty_env_logger = "0.4"
|
||||||
|
tracing-subscriber = "0.2.15"
|
||||||
|
tracing-log = "0.1"
|
||||||
|
serde_derive = "1.0.125"
|
||||||
|
handlebars = "3.0.0"
|
||||||
|
tokio = { version = "1.5.0", features = ["macros", "rt-multi-thread"] }
|
||||||
|
tokio-stream = { version = "0.1.5", features = ["net"] }
|
||||||
|
listenfd = "0.3"
|
||||||
|
envmnt = "0.9.0"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
envmnt = "0.9.0"
|
5
app_file_handlers/README.md
Normal file
5
app_file_handlers/README.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# App file handlers library
|
||||||
|
|
||||||
|
Files Upload
|
||||||
|
|
||||||
|
Handlers for request for auth management using [warp](https://github.com/seanmonstar/warp)
|
4
app_file_handlers/TODO.md
Normal file
4
app_file_handlers/TODO.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# App file handlers library
|
||||||
|
|
||||||
|
- [ ] Review & test
|
||||||
|
|
294
app_file_handlers/src/lib.rs
Normal file
294
app_file_handlers/src/lib.rs
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
// use app_auth::{AppAuthDBs, AuthError, UserCtx, WebResult, LoginRequest };
|
||||||
|
use app_auth::{AppAuthDBs, UserCtx, WebResult };
|
||||||
|
use uuid::Uuid;
|
||||||
|
// use http::Uri;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use reqtasks::ReqTasks;
|
||||||
|
|
||||||
|
use bytes::BufMut;
|
||||||
|
use futures::TryStreamExt;
|
||||||
|
|
||||||
|
use warp::{
|
||||||
|
http::{method::Method, HeaderMap, HeaderValue}, // , StatusCode},
|
||||||
|
//http::{Uri,method::Method, HeaderMap, HeaderValue, StatusCode},
|
||||||
|
// multipart::{FormData, Part},
|
||||||
|
Reply, Rejection // , reject,
|
||||||
|
};
|
||||||
|
use warp::multipart::{FormData, Part};
|
||||||
|
|
||||||
|
#[allow(clippy::missing_errors_doc)]
|
||||||
|
pub async fn member_handler(user_ctx: UserCtx) -> WebResult<impl Reply> {
|
||||||
|
Ok(format!("Member with id {}", user_ctx.user_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::missing_errors_doc)]
|
||||||
|
pub async fn admin_handler(user_ctx: UserCtx) -> WebResult<impl Reply> {
|
||||||
|
Ok(format!("Admin with id {}", user_ctx.user_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #[allow(clippy::missing_errors_doc)]
|
||||||
|
// pub async fn ui_handler (
|
||||||
|
// header: HeaderMap<HeaderValue>,
|
||||||
|
// method: Method,
|
||||||
|
// db: AppAuthDBs,
|
||||||
|
// ) -> Result<impl Reply, Rejection> {
|
||||||
|
// let req = ReqTasks::new(db.app, db.auth, header, method, "/ui", "ui", "file",);
|
||||||
|
// // let allow_origin = req.config().allow_origin;
|
||||||
|
// // Ok(warp::redirect(Uri::from_static("https://google.com")))
|
||||||
|
// // let location = http::uri::Uri::from_str(&format!("/user/{}", user_id)).unwrap();
|
||||||
|
// let location = "https://localhost:8000/ui/index.html".parse::<Uri>().unwrap();
|
||||||
|
// Ok(warp::redirect(location))
|
||||||
|
// // Ok(warp::http::Response::builder()
|
||||||
|
// // //.header("Access-Control-Allow-Origin",&allow_origin)
|
||||||
|
// // .body("".to_string())
|
||||||
|
// // .into_response())
|
||||||
|
//}
|
||||||
|
|
||||||
|
#[allow(clippy::missing_errors_doc)]
|
||||||
|
pub async fn upload_handler (
|
||||||
|
header: HeaderMap<HeaderValue>,
|
||||||
|
method: Method,
|
||||||
|
db: AppAuthDBs
|
||||||
|
) -> Result<impl Reply, Rejection> {
|
||||||
|
let req = ReqTasks::new(db.app, db.auth, header, method, "/upload", "upload", "file",);
|
||||||
|
// let allow_origin = req.config().allow_origin;
|
||||||
|
let lang = req.lang();
|
||||||
|
let mut ctx = req.ctx();
|
||||||
|
let req_module = "";
|
||||||
|
let app_module: &str;
|
||||||
|
if ! req_module.is_empty() && req_module != req.config().default_module.as_str() {
|
||||||
|
app_module = req_module;
|
||||||
|
} else {
|
||||||
|
app_module = "";
|
||||||
|
}
|
||||||
|
let mut data_hash: HashMap<String, String> = HashMap::new();
|
||||||
|
data_hash.insert("lang".to_string(), lang.to_owned());
|
||||||
|
// let mut res = String::from("");
|
||||||
|
// let res = if let Some(name) = query.get("name") {
|
||||||
|
// submitted form
|
||||||
|
match req
|
||||||
|
.render_page(
|
||||||
|
&mut ctx,
|
||||||
|
req.config().templates_path.as_str(),
|
||||||
|
"upload/index.html",
|
||||||
|
"index.html",
|
||||||
|
format!("upload/{}.toml", lang.to_owned())
|
||||||
|
.to_owned()
|
||||||
|
.as_str(),
|
||||||
|
&mut data_hash,
|
||||||
|
app_module,
|
||||||
|
)
|
||||||
|
.await {
|
||||||
|
Ok(page) =>
|
||||||
|
Ok(warp::http::Response::builder()
|
||||||
|
.body(page)
|
||||||
|
.into_response()),
|
||||||
|
/*
|
||||||
|
Ok(warp::reply::with_header(
|
||||||
|
warp::http::Response::new(page),
|
||||||
|
// "Access-Control-Allow-Origin",
|
||||||
|
// &allow_origin)),
|
||||||
|
*/
|
||||||
|
Err(_err) =>
|
||||||
|
Ok(warp::http::Response::builder()
|
||||||
|
.body("".to_string())
|
||||||
|
.into_response()),
|
||||||
|
/*
|
||||||
|
Ok(warp::reply::with_header(
|
||||||
|
warp::http::Response::new(err.to_string()),
|
||||||
|
"Access-Control-Allow-Origin",
|
||||||
|
&allow_origin)),
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn get_file_info(p: &warp::multipart::Part) -> (String, String) {
|
||||||
|
let content_type = p.content_type().unwrap_or("");
|
||||||
|
let full_file_name = p.filename().unwrap_or("");
|
||||||
|
//let mut file_name = "";
|
||||||
|
if ! full_file_name.is_empty() {
|
||||||
|
let file_name = match std::path::Path::new(&full_file_name.to_owned()).file_stem() {
|
||||||
|
Some(stem_file_name) => PathBuf::from(&stem_file_name),
|
||||||
|
None => PathBuf::from("")
|
||||||
|
};
|
||||||
|
(content_type.to_owned(), format!("{}",&file_name.display()))
|
||||||
|
} else {
|
||||||
|
(content_type.to_owned(), full_file_name.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn uploadin_handler(
|
||||||
|
form: FormData,
|
||||||
|
header: HeaderMap<HeaderValue>,
|
||||||
|
method: Method,
|
||||||
|
db: AppAuthDBs,
|
||||||
|
// parts: Result<Vec<(String, Vec<u8>)>, warp::Rejection>,
|
||||||
|
) -> Result<impl Reply, Rejection> {
|
||||||
|
let req = ReqTasks::new(db.app, db.auth, header, method, "/uploadin", "uploadin", "file",);
|
||||||
|
// ) -> WebResult<impl Reply> {
|
||||||
|
// let name = body.name;
|
||||||
|
// println!("{}", &name);
|
||||||
|
// dbg!(&req.auth_store.users.read().await);
|
||||||
|
// let allow_origin = req.config().allow_origin;
|
||||||
|
match req.user_authentication().await {
|
||||||
|
Ok(auth) => {
|
||||||
|
let mut files_path = format!("{}/{}", req.config().upload_path,&auth.user_id);
|
||||||
|
if ! std::path::Path::new(&files_path).exists() {
|
||||||
|
std::fs::create_dir(&files_path).unwrap_or_else(|e| { println!("Error create dir {}: {}", &files_path,e); files_path = String::from("");});
|
||||||
|
if files_path.is_empty() {
|
||||||
|
eprintln!("form create directory");
|
||||||
|
return Err(warp::reject::reject());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// let part: Result<Vec<(String, Vec<u8>)>, warp::Rejection> = form
|
||||||
|
// .and_then(|part| {
|
||||||
|
// let name = part.name().to_string();
|
||||||
|
// let value = part.stream().try_fold(Vec::new(), |mut vec, data| {
|
||||||
|
// vec.put(data);
|
||||||
|
// async move { Ok(vec) }
|
||||||
|
// });
|
||||||
|
// value.map_ok(move |vec| (name, vec))
|
||||||
|
// })
|
||||||
|
// .try_collect()
|
||||||
|
// .await
|
||||||
|
// .map_err(|e| {
|
||||||
|
// panic!("multipart error: {:?}", e);
|
||||||
|
// });
|
||||||
|
// // part
|
||||||
|
let parts: Vec<Part> = form.try_collect().await.map_err(|e| {
|
||||||
|
eprintln!("form error: {}", e);
|
||||||
|
warp::reject::reject()
|
||||||
|
})?;
|
||||||
|
for p in parts {
|
||||||
|
// if p.name() == "file" {
|
||||||
|
let (content_type, src_file_name) = get_file_info(&p);
|
||||||
|
// let content_type = &p.content_type();
|
||||||
|
let file_ending;
|
||||||
|
match content_type.as_str() {
|
||||||
|
// Some(file_type) => match file_type.to_owned() {
|
||||||
|
"application/pdf" => {
|
||||||
|
file_ending = "pdf";
|
||||||
|
},
|
||||||
|
"image/png" => {
|
||||||
|
file_ending = "png";
|
||||||
|
},
|
||||||
|
"image/jpg" => {
|
||||||
|
file_ending = "jpg";
|
||||||
|
},
|
||||||
|
"image/jpeg" => {
|
||||||
|
file_ending = "jpeg";
|
||||||
|
},
|
||||||
|
"image/svg+xml" => {
|
||||||
|
file_ending = "svg";
|
||||||
|
},
|
||||||
|
"application/doc" => {
|
||||||
|
file_ending = "doc";
|
||||||
|
},
|
||||||
|
"application/txt" => {
|
||||||
|
file_ending = "txt";
|
||||||
|
},
|
||||||
|
// v => {
|
||||||
|
// eprintln!("invalid file type found: {}", v);
|
||||||
|
// return Err(warp::reject::reject());
|
||||||
|
// }
|
||||||
|
//},
|
||||||
|
_ => {
|
||||||
|
eprintln!("file type {} could not be determined", &content_type);
|
||||||
|
return Err(warp::reject::reject());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
let value = p
|
||||||
|
.stream()
|
||||||
|
.try_fold(Vec::new(), |mut vec, data| {
|
||||||
|
vec.put(data);
|
||||||
|
async move { Ok(vec) }
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
eprintln!("reading file error: {}", e);
|
||||||
|
warp::reject::reject()
|
||||||
|
})?;
|
||||||
|
let file_name = format!("{}/{}_{}.{}", &files_path,src_file_name,Uuid::new_v4().to_string(), file_ending);
|
||||||
|
tokio::fs::write(&file_name, value).await.map_err(|e| {
|
||||||
|
eprint!("error writing file: {}", e);
|
||||||
|
warp::reject::reject()
|
||||||
|
})?;
|
||||||
|
println!("created file: {}", file_name);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
Ok(warp::http::Response::builder()
|
||||||
|
.body("".to_string())
|
||||||
|
.into_response())
|
||||||
|
// Err(reject::custom(AuthError::UserNotFoundError))
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
let result = format!("Error: no credentials found");
|
||||||
|
println!("{}",e);
|
||||||
|
Ok(warp::http::Response::builder()
|
||||||
|
.body(result.to_string())
|
||||||
|
.into_response())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// https://blog.logrocket.com/file-upload-and-download-in-rust/
|
||||||
|
// https://github.com/zupzup/warp-upload-download-example
|
||||||
|
|
||||||
|
// https://github.com/cetra3/mpart-async/blob/master/examples/warp.rs
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub async fn uploadfile(form: FormData) -> Result<impl Reply, Rejection> {
|
||||||
|
let parts: Vec<Part> = form.try_collect().await.map_err(|e| {
|
||||||
|
eprintln!("form error: {}", e);
|
||||||
|
warp::reject::reject()
|
||||||
|
})?;
|
||||||
|
|
||||||
|
for p in parts {
|
||||||
|
if p.name() == "file" {
|
||||||
|
let content_type = p.content_type();
|
||||||
|
let file_ending;
|
||||||
|
match content_type {
|
||||||
|
Some(file_type) => match file_type {
|
||||||
|
"application/pdf" => {
|
||||||
|
file_ending = "pdf";
|
||||||
|
}
|
||||||
|
"image/png" => {
|
||||||
|
file_ending = "png";
|
||||||
|
}
|
||||||
|
v => {
|
||||||
|
eprintln!("invalid file type found: {}", v);
|
||||||
|
return Err(warp::reject::reject());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
eprintln!("file type could not be determined");
|
||||||
|
return Err(warp::reject::reject());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = p
|
||||||
|
.stream()
|
||||||
|
.try_fold(Vec::new(), |mut vec, data| {
|
||||||
|
vec.put(data);
|
||||||
|
async move { Ok(vec) }
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
eprintln!("reading file error: {}", e);
|
||||||
|
warp::reject::reject()
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let file_name = format!("./files/{}.{}", Uuid::new_v4().to_string(), file_ending);
|
||||||
|
tokio::fs::write(&file_name, value).await.map_err(|e| {
|
||||||
|
eprint!("error writing file: {}", e);
|
||||||
|
warp::reject::reject()
|
||||||
|
})?;
|
||||||
|
println!("created file: {}", file_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok("success")
|
||||||
|
}
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user