validate_directory_structure 0.2.5

A powerful tool to validate directory(Files and folders) structures.
Documentation
use std::{
    collections::{HashMap, HashSet},
    fs,
};

use std::path::Path;

use super::{
    get_base_name::get_base_name,
    types::{AlertFileStructure, AlertType, FileTypes, Folder, ItemType},
};

pub fn validate_missing_items(
    path: &str,
    folders: Option<&Vec<Folder>>,
    missing_items: &mut Vec<AlertFileStructure>,
    required_extensions: &Vec<&str>,
    list_of_files_found: &mut HashMap<String, String>,
) {
    let base_path = Path::new(path);

    if let Some(folders) = folders {
        for folder in folders {
            let folder_names = &folder.names;
            let mut folder_exists = false;

            // Check if any of the folder names exist in the filesystem
            for folder_name in folder_names {
                let folder_path = base_path.join(folder_name);
                if folder_path.exists() && folder_path.is_dir() {
                    folder_exists = true;

                    // Validate files in the folder
                    if let Some(files) = &folder.files {
                        validate_files(
                            &folder_path,
                            files,
                            missing_items,
                            required_extensions.clone(),
                            folder.id.as_ref().unwrap_or(&"".to_string()),
                            list_of_files_found,
                        );
                    }

                    // Recursively validate subfolders
                    if let Some(subfolders) = &folder.folders {
                        validate_missing_items(
                            folder_path.to_str().unwrap(),
                            Some(subfolders),
                            missing_items,
                            required_extensions,
                            list_of_files_found,
                        );
                    }
                    break; // Stop checking other names if one matches
                }
            }

            // If the folder is required and doesn't exist, add it to missing_items
            if !folder_exists {
                if folder.required {
                    missing_items.push(AlertFileStructure {
                        path: base_path
                            .join(&folder_names[0])
                            .to_string_lossy()
                            .to_string(),
                        item_type: ItemType::Folder,
                        alert_type: AlertType::MissingItem,
                    });
                    continue;
                }
                missing_items.push(AlertFileStructure {
                    path: base_path
                        .join(&folder_names[0])
                        .to_string_lossy()
                        .to_string(),
                    item_type: ItemType::Folder,
                    alert_type: AlertType::Warning,
                });
            }
        }
    }
}

fn validate_files(
    folder_path: &Path,
    files: &Vec<FileTypes>,
    missing_items: &mut Vec<AlertFileStructure>,
    required_extensions: Vec<&str>,
    id_folder: &String,
    list_of_files_found: &mut HashMap<String, String>,
) {
    let dir_entries: HashSet<String> = fs::read_dir(folder_path)
        .unwrap()
        .filter_map(|entry| {
            let entry = entry.unwrap();
            if entry.path().is_file() {
                Some(entry.file_name().to_string_lossy().to_string())
            } else {
                None
            }
        })
        .collect();

    for file in files {
        let mut extensions_missing: Vec<(&str, bool)> = vec![];
        let file_names = &file.names;

        for ext in required_extensions.iter() {
            // let file_name_match = RefCell::new(("", ""));
            let mut file_name_match: (String, String) = (String::new(), String::new());

            let mut full_file_name: String = "".to_string();

            let exist_full_name_file = file_names.iter().any(|file_name| {
                full_file_name = format!("{}.{}", file_name, ext);
                let result = dir_entries.contains(&full_file_name);
                if result {
                    file_name_match.0 = file_name.to_owned();
                    file_name_match.1 = file.id.clone().unwrap_or_default();
                }

                result
            });
            if !exist_full_name_file {
                extensions_missing.push((&ext, if file.required { true } else { false }));
            } else {
                list_of_files_found.insert(
                    format!("{}-{}", id_folder, file_name_match.1),
                    format!(
                        "{}/{}",
                        folder_path.to_string_lossy(),
                        get_base_name(file_name_match.0.as_str())
                    ),
                );
            }
        }

        if extensions_missing.len() > 0 {
            for extension_missing in extensions_missing {
                missing_items.push(AlertFileStructure {
                    path: folder_path
                        .join(format!("{}.{}", file_names[0], extension_missing.0))
                        .to_string_lossy()
                        .to_string(),
                    item_type: ItemType::File,
                    alert_type: if extension_missing.1 {
                        AlertType::MissingItem
                    } else {
                        AlertType::Warning
                    },
                });
            }
        }
    }
}