use crate::static_files::upload::*; use crate::website::WebSite; use actix_files::NamedFile; use actix_multipart::Multipart; use actix_web::{ delete, get, post, web, web::{Data, Path}, HttpResponse, Responder, }; use futures::StreamExt; use std::{ fs::{remove_file, File}, io::Write, sync::RwLock, }; #[get("/favicon.ico")] pub async fn favicon(website: web::Data<RwLock<WebSite>>) -> impl Responder { NamedFile::open( &website .read() .unwrap() .static_files_manager .dir .join("default") .join("favicon.ico"), ) } fn upload_data_from_multipart_field( field: &actix_multipart::Field, ) -> Result<UploadFileData, String> { match field.content_disposition().get_filename() { Some(fname) => match file_ext(&fname.to_string()) { Ok(ext) => Ok(UploadFileData { up_type: upload_type_from_file_ext(&ext), filename: fname.to_owned(), }), Err(msg) => return Err(msg), }, None => Err("Couldn't retrieve file extension".to_string()), } } async fn write_uploaded_file( website: &WebSite, field: &mut actix_multipart::Field, filename: &String, upload_type: UploadFileType, ) -> Result<String, String> { let root = &website.static_files_manager.dir; let sub_dir = dirname_from_type(&upload_type); let filepath = root.join(sub_dir).join(&filename); match File::create(&filepath) { Err(e) => Err(format!("Error creating file {:?} : {:?}", filepath, e)), Ok(mut f) => { // Field in turn is stream of *Bytes* object while let Some(chunk) = field.next().await { match chunk { Ok(chunk) => { if f.write_all(&chunk).is_err() { remove_file(&filepath).unwrap(); return Err("Error writing chunk".to_string()); } } Err(e) => { return Err(format!("Error writing file {} : {:?}", filename, e)); } } } Ok(filepath.into_os_string().into_string().unwrap()) } } } #[post("/post-files")] pub async fn post_files(website: Data<RwLock<WebSite>>, mut payload: Multipart) -> impl Responder { let mut uploaded_filepathes = Vec::new(); let mut website = website .write() .expect("Couldn't acquire write lock for RwLock<WebSite"); while let Some(item) = payload.next().await { match item { Ok(mut field) => { let up_data = upload_data_from_multipart_field(&field); if let Err(msg) = up_data { return HttpResponse::InternalServerError().body(msg); } let up_data = up_data.unwrap(); match write_uploaded_file(&website, &mut field, &up_data.filename, up_data.up_type) .await { Err(msg) => return HttpResponse::InternalServerError().body(msg), Ok(filepath) => uploaded_filepathes.extend( website .static_files_manager .push_path(std::path::Path::new(&filepath)), ), } } Err(e) => { return HttpResponse::InternalServerError().body(format!("FIELD ERR {:?}", e)) } } } HttpResponse::Ok().json(uploaded_filepathes) } #[get("/static-files-index")] async fn get_static_files_index(website: Data<RwLock<WebSite>>) -> impl Responder { HttpResponse::Ok().json(website.read().unwrap().static_files_manager.get_index()) } #[delete("/delete-file/{category}/{filename}")] async fn delete_static_file( website: Data<RwLock<WebSite>>, fileinfo: Path<(String, String)>, ) -> impl Responder { let mut website = website .write() .expect("Couldn't acquire write lock for RwLock<WebSite"); let (cat, fname) = fileinfo.into_inner(); let fpath = std::path::PathBuf::from(cat).join(fname); match remove_file(website.static_files_manager.dir.join(&fpath)) { Ok(_) => { website .static_files_manager .remove_path(fpath.to_string_lossy().into()); HttpResponse::Accepted().body("File was deleted") } Err(e) => HttpResponse::InternalServerError().body(format!("Error deleting file {:?}", e)), } }