Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
files.rs 4.48 KiB
Newer Older
Pierre Jarriges's avatar
Pierre Jarriges committed
use crate::static_files::upload::*;
use crate::website::WebSite;
peterrabbit's avatar
peterrabbit committed
use actix_files::NamedFile;
Pierre Jarriges's avatar
Pierre Jarriges committed
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,
};
peterrabbit's avatar
peterrabbit committed

#[get("/favicon.ico")]
Pierre Jarriges's avatar
Pierre Jarriges committed
pub async fn favicon(website: web::Data<std::sync::Mutex<WebSite>>) -> impl Responder {
    let static_files_manager = &website.lock().unwrap().static_files_manager;
peterrabbit's avatar
peterrabbit committed
    NamedFile::open(static_files_manager.dir.join("default").join("favicon.ico"))
}
Pierre Jarriges's avatar
Pierre Jarriges committed

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<std::sync::Mutex<WebSite>>,
    mut payload: Multipart,
) -> impl Responder {
    let mut uploaded_filepathes = Vec::new();
    let mut website = website.lock().unwrap();

    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<std::sync::Mutex<WebSite>>) -> impl Responder {
    HttpResponse::Ok().json(
        website
            .lock()
            .expect("Couldn't lock website")
            .static_files_manager
            .get_index(),
    )
}

#[delete("/delete-file/{category}/{filename}")]
async fn delete_static_file(
    website: Data<std::sync::Mutex<WebSite>>,
    fileinfo: Path<(String, String)>,
) -> impl Responder {
    let mut website = website.lock().unwrap();
    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)),
    }
}