170 lines
5.0 KiB
Rust
170 lines
5.0 KiB
Rust
use crate::app_config::AppConfig;
|
|
use crate::constants;
|
|
use crate::controllers::HttpResult;
|
|
use crate::utils::files_utils;
|
|
use actix_files::NamedFile;
|
|
use actix_multipart::form::tempfile::TempFile;
|
|
use actix_multipart::form::MultipartForm;
|
|
use actix_web::{web, HttpRequest, HttpResponse};
|
|
use futures_util::StreamExt;
|
|
use std::fs::File;
|
|
use std::io::Write;
|
|
use std::os::unix::fs::MetadataExt;
|
|
|
|
#[derive(Debug, MultipartForm)]
|
|
pub struct UploadIsoForm {
|
|
#[multipart(rename = "file")]
|
|
files: Vec<TempFile>,
|
|
}
|
|
|
|
/// Upload iso file
|
|
pub async fn upload_file(MultipartForm(mut form): MultipartForm<UploadIsoForm>) -> HttpResult {
|
|
if form.files.is_empty() {
|
|
log::error!("Missing uploaded ISO file!");
|
|
return Ok(HttpResponse::BadRequest().json("Missing file!"));
|
|
}
|
|
|
|
let file = form.files.remove(0);
|
|
|
|
if file.size > constants::ISO_MAX_SIZE {
|
|
log::error!("Uploaded ISO file is too large!");
|
|
return Ok(HttpResponse::BadRequest().json("File is too large!"));
|
|
}
|
|
|
|
if let Some(m) = &file.content_type {
|
|
if !constants::ALLOWED_ISO_MIME_TYPES.contains(&m.to_string().as_str()) {
|
|
log::error!("Uploaded ISO file has an invalid mimetype!");
|
|
return Ok(HttpResponse::BadRequest().json("Invalid mimetype!"));
|
|
}
|
|
}
|
|
|
|
let file_name = match &file.file_name {
|
|
None => {
|
|
log::error!("Uploaded ISO file does not have a name!");
|
|
return Ok(HttpResponse::BadRequest().json("Missing file name!"));
|
|
}
|
|
Some(f) => f,
|
|
};
|
|
|
|
if !files_utils::check_file_name(file_name) {
|
|
log::error!("Bad file name for uploaded iso!");
|
|
return Ok(HttpResponse::BadRequest().json("Bad file name!"));
|
|
}
|
|
|
|
let dest_file = AppConfig::get().iso_storage_path().join(file_name);
|
|
log::info!("Will save ISO file {:?}", dest_file);
|
|
|
|
if dest_file.exists() {
|
|
log::error!("Conflict with uploaded iso file name!");
|
|
return Ok(HttpResponse::Conflict().json("The file already exists!"));
|
|
}
|
|
|
|
file.file.persist(&dest_file)?;
|
|
|
|
// Set file permissions
|
|
files_utils::set_file_permission(dest_file, 0o644)?;
|
|
|
|
Ok(HttpResponse::Accepted().finish())
|
|
}
|
|
|
|
#[derive(serde::Deserialize)]
|
|
pub struct DownloadFromURLReq {
|
|
url: String,
|
|
filename: String,
|
|
}
|
|
|
|
/// Upload ISO file from URL
|
|
pub async fn upload_from_url(req: web::Json<DownloadFromURLReq>) -> HttpResult {
|
|
if !files_utils::check_file_name(&req.filename) || !req.filename.ends_with(".iso") {
|
|
return Ok(HttpResponse::BadRequest().json("Invalid file name!"));
|
|
}
|
|
|
|
let dest_file = AppConfig::get().iso_storage_path().join(&req.filename);
|
|
|
|
if dest_file.exists() {
|
|
return Ok(HttpResponse::Conflict().json("A similar file already exists!"));
|
|
}
|
|
|
|
let response = reqwest::get(&req.url).await?;
|
|
|
|
if let Some(len) = response.content_length() {
|
|
if len > constants::ISO_MAX_SIZE as u64 {
|
|
return Ok(HttpResponse::BadRequest().json("File is too large!"));
|
|
}
|
|
}
|
|
|
|
if let Some(ct) = response.headers().get("content-type") {
|
|
if !constants::ALLOWED_ISO_MIME_TYPES.contains(&ct.to_str()?) {
|
|
return Ok(HttpResponse::BadRequest().json("Invalid file mimetype!"));
|
|
}
|
|
}
|
|
|
|
let mut stream = response.bytes_stream();
|
|
|
|
let mut file = File::create(dest_file)?;
|
|
|
|
while let Some(item) = stream.next().await {
|
|
let bytes = item?;
|
|
file.write_all(&bytes)?;
|
|
}
|
|
|
|
Ok(HttpResponse::Accepted().finish())
|
|
}
|
|
|
|
#[derive(serde::Serialize)]
|
|
struct IsoFile {
|
|
filename: String,
|
|
size: u64,
|
|
}
|
|
|
|
/// Get ISO files list
|
|
pub async fn get_list() -> HttpResult {
|
|
let mut list = vec![];
|
|
for entry in AppConfig::get().iso_storage_path().read_dir()? {
|
|
let entry = entry?;
|
|
list.push(IsoFile {
|
|
filename: entry.file_name().to_string_lossy().to_string(),
|
|
size: entry.path().metadata()?.size(),
|
|
})
|
|
}
|
|
|
|
Ok(HttpResponse::Ok().json(list))
|
|
}
|
|
|
|
#[derive(serde::Deserialize)]
|
|
pub struct DownloadFilePath {
|
|
filename: String,
|
|
}
|
|
|
|
/// Download ISO file
|
|
pub async fn download_file(p: web::Path<DownloadFilePath>, req: HttpRequest) -> HttpResult {
|
|
if !files_utils::check_file_name(&p.filename) {
|
|
return Ok(HttpResponse::BadRequest().json("Invalid file name!"));
|
|
}
|
|
|
|
let file_path = AppConfig::get().iso_storage_path().join(&p.filename);
|
|
|
|
if !file_path.exists() {
|
|
return Ok(HttpResponse::NotFound().json("File does not exists!"));
|
|
}
|
|
|
|
Ok(NamedFile::open(file_path)?.into_response(&req))
|
|
}
|
|
|
|
/// Delete ISO file
|
|
pub async fn delete_file(p: web::Path<DownloadFilePath>) -> HttpResult {
|
|
if !files_utils::check_file_name(&p.filename) {
|
|
return Ok(HttpResponse::BadRequest().json("Invalid file name!"));
|
|
}
|
|
|
|
let file_path = AppConfig::get().iso_storage_path().join(&p.filename);
|
|
|
|
if !file_path.exists() {
|
|
return Ok(HttpResponse::NotFound().json("File does not exists!"));
|
|
}
|
|
|
|
std::fs::remove_file(file_path)?;
|
|
|
|
Ok(HttpResponse::Accepted().finish())
|
|
}
|