Can delete uploaded disk images
This commit is contained in:
		@@ -245,7 +245,7 @@ impl AppConfig {
 | 
			
		||||
        storage_path.canonicalize().unwrap()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get iso storage directory
 | 
			
		||||
    /// Get iso files storage directory
 | 
			
		||||
    pub fn iso_storage_path(&self) -> PathBuf {
 | 
			
		||||
        self.storage_path().join("iso")
 | 
			
		||||
    }
 | 
			
		||||
@@ -265,15 +265,17 @@ impl AppConfig {
 | 
			
		||||
        self.vnc_sockets_path().join(format!("vnc-{}", name))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get VM vnc sockets directory
 | 
			
		||||
    pub fn disks_storage_path(&self) -> PathBuf {
 | 
			
		||||
    /// Get VM root disks storage directory
 | 
			
		||||
    pub fn root_vm_disks_storage_path(&self) -> PathBuf {
 | 
			
		||||
        self.storage_path().join("disks")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get specific VM disk storage directory
 | 
			
		||||
    pub fn vm_storage_path(&self, id: XMLUuid) -> PathBuf {
 | 
			
		||||
        self.disks_storage_path().join(id.as_string())
 | 
			
		||||
        self.root_vm_disks_storage_path().join(id.as_string())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get the path were VM definitions are backed up
 | 
			
		||||
    pub fn definitions_path(&self) -> PathBuf {
 | 
			
		||||
        self.storage_path().join("definitions")
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ use crate::utils::file_disks_utils::DiskFileInfo;
 | 
			
		||||
use crate::utils::files_utils;
 | 
			
		||||
use actix_multipart::form::MultipartForm;
 | 
			
		||||
use actix_multipart::form::tempfile::TempFile;
 | 
			
		||||
use actix_web::HttpResponse;
 | 
			
		||||
use actix_web::{HttpResponse, web};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, MultipartForm)]
 | 
			
		||||
pub struct UploadDiskImageForm {
 | 
			
		||||
@@ -67,3 +67,27 @@ pub async fn get_list() -> HttpResult {
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok().json(list))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
pub struct DiskFilePath {
 | 
			
		||||
    filename: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete a disk image
 | 
			
		||||
pub async fn delete(p: web::Path<DiskFilePath>) -> HttpResult {
 | 
			
		||||
    if !files_utils::check_file_name(&p.filename) {
 | 
			
		||||
        return Ok(HttpResponse::BadRequest().json("Invalid file name!"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let file_path = AppConfig::get()
 | 
			
		||||
        .disk_images_storage_path()
 | 
			
		||||
        .join(&p.filename);
 | 
			
		||||
 | 
			
		||||
    if !file_path.exists() {
 | 
			
		||||
        return Ok(HttpResponse::NotFound().json("Disk image does not exists!"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::fs::remove_file(file_path)?;
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Accepted().finish())
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -132,12 +132,12 @@ pub async fn get_list() -> HttpResult {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Deserialize)]
 | 
			
		||||
pub struct DownloadFilePath {
 | 
			
		||||
pub struct IsoFilePath {
 | 
			
		||||
    filename: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Download ISO file
 | 
			
		||||
pub async fn download_file(p: web::Path<DownloadFilePath>, req: HttpRequest) -> HttpResult {
 | 
			
		||||
pub async fn download_file(p: web::Path<IsoFilePath>, req: HttpRequest) -> HttpResult {
 | 
			
		||||
    if !files_utils::check_file_name(&p.filename) {
 | 
			
		||||
        return Ok(HttpResponse::BadRequest().json("Invalid file name!"));
 | 
			
		||||
    }
 | 
			
		||||
@@ -152,7 +152,7 @@ pub async fn download_file(p: web::Path<DownloadFilePath>, req: HttpRequest) ->
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Delete ISO file
 | 
			
		||||
pub async fn delete_file(p: web::Path<DownloadFilePath>) -> HttpResult {
 | 
			
		||||
pub async fn delete_file(p: web::Path<IsoFilePath>) -> HttpResult {
 | 
			
		||||
    if !files_utils::check_file_name(&p.filename) {
 | 
			
		||||
        return Ok(HttpResponse::BadRequest().json("Invalid file name!"));
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,8 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
    files_utils::create_directory_if_missing(AppConfig::get().disk_images_storage_path()).unwrap();
 | 
			
		||||
    files_utils::create_directory_if_missing(AppConfig::get().vnc_sockets_path()).unwrap();
 | 
			
		||||
    files_utils::set_file_permission(AppConfig::get().vnc_sockets_path(), 0o777).unwrap();
 | 
			
		||||
    files_utils::create_directory_if_missing(AppConfig::get().disks_storage_path()).unwrap();
 | 
			
		||||
    files_utils::create_directory_if_missing(AppConfig::get().root_vm_disks_storage_path())
 | 
			
		||||
        .unwrap();
 | 
			
		||||
    files_utils::create_directory_if_missing(AppConfig::get().nat_path()).unwrap();
 | 
			
		||||
    files_utils::create_directory_if_missing(AppConfig::get().definitions_path()).unwrap();
 | 
			
		||||
    files_utils::create_directory_if_missing(AppConfig::get().api_tokens_path()).unwrap();
 | 
			
		||||
@@ -344,6 +345,10 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
                "/api/disk_images/list",
 | 
			
		||||
                web::get().to(disk_images_controller::get_list),
 | 
			
		||||
            )
 | 
			
		||||
            .route(
 | 
			
		||||
                "/api/disk_images/{filename}",
 | 
			
		||||
                web::delete().to(disk_images_controller::delete),
 | 
			
		||||
            )
 | 
			
		||||
            // API tokens controller
 | 
			
		||||
            .route(
 | 
			
		||||
                "/api/token/create",
 | 
			
		||||
 
 | 
			
		||||
@@ -42,4 +42,14 @@ export class DiskImageApi {
 | 
			
		||||
      })
 | 
			
		||||
    ).data;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Delete disk image file
 | 
			
		||||
   */
 | 
			
		||||
  static async Delete(file: DiskImage): Promise<void> {
 | 
			
		||||
    await APIClient.exec({
 | 
			
		||||
      method: "DELETE",
 | 
			
		||||
      uri: `/disk_images/${file.file_name}`,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,8 @@ import React from "react";
 | 
			
		||||
import { DiskImage, DiskImageApi } from "../api/DiskImageApi";
 | 
			
		||||
import { ServerApi } from "../api/ServerApi";
 | 
			
		||||
import { useAlert } from "../hooks/providers/AlertDialogProvider";
 | 
			
		||||
import { useConfirm } from "../hooks/providers/ConfirmDialogProvider";
 | 
			
		||||
import { useLoadingMessage } from "../hooks/providers/LoadingMessageProvider";
 | 
			
		||||
import { useSnackbar } from "../hooks/providers/SnackbarProvider";
 | 
			
		||||
import { AsyncWidget } from "../widgets/AsyncWidget";
 | 
			
		||||
import { DateWidget } from "../widgets/DateWidget";
 | 
			
		||||
@@ -152,6 +154,41 @@ function DiskImageList(p: {
 | 
			
		||||
  list: DiskImage[];
 | 
			
		||||
  onReload: () => void;
 | 
			
		||||
}): React.ReactElement {
 | 
			
		||||
  const alert = useAlert();
 | 
			
		||||
  const snackbar = useSnackbar();
 | 
			
		||||
  const confirm = useConfirm();
 | 
			
		||||
  const loadingMessage = useLoadingMessage();
 | 
			
		||||
 | 
			
		||||
  // Delete disk image
 | 
			
		||||
  const deleteDiskImage = async (entry: DiskImage) => {
 | 
			
		||||
    if (
 | 
			
		||||
      !(await confirm(
 | 
			
		||||
        `Do you really want to delete this disk image (${entry.file_name}) ?`
 | 
			
		||||
      ))
 | 
			
		||||
    )
 | 
			
		||||
      return;
 | 
			
		||||
 | 
			
		||||
    loadingMessage.show("Deleting disk image file...");
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      await DiskImageApi.Delete(entry);
 | 
			
		||||
      snackbar("The disk image has been successfully deleted!");
 | 
			
		||||
      p.onReload();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      console.error(e);
 | 
			
		||||
      alert(`Failed to delete disk image!\n${e}`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    loadingMessage.hide();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  if (p.list.length === 0)
 | 
			
		||||
    return (
 | 
			
		||||
      <Typography variant="body1" style={{ textAlign: "center" }}>
 | 
			
		||||
        No disk image uploaded for now.
 | 
			
		||||
      </Typography>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
  const columns: GridColDef<(typeof p.list)[number]>[] = [
 | 
			
		||||
    { field: "file_name", headerName: "File name", flex: 3 },
 | 
			
		||||
    {
 | 
			
		||||
@@ -187,8 +224,8 @@ function DiskImageList(p: {
 | 
			
		||||
                <DownloadIcon />
 | 
			
		||||
              </IconButton>
 | 
			
		||||
            </Tooltip>
 | 
			
		||||
            <Tooltip title="Delete file">
 | 
			
		||||
              <IconButton onClick={() => deleteIso(params.row)}>
 | 
			
		||||
            <Tooltip title="Delete disk image">
 | 
			
		||||
              <IconButton onClick={() => deleteDiskImage(params.row)}>
 | 
			
		||||
                <DeleteIcon />
 | 
			
		||||
              </IconButton>
 | 
			
		||||
            </Tooltip>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user