Files
EFC-DESK-V2/Classes/Helpers.cs

415 lines
14 KiB
C#

using System;
using System.IO;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Xml;
using System.Xml.Linq;
namespace EFCDesk.Classes
{
public static class Helpers
{
// Lista de extensiones permitidas
private static readonly HashSet<string> ExtensionesPermitidas = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
".jpg",
".jpeg",
".png",
".gif",
".bmp",
".pdf",
".txt",
".csv"
};
// Lista de extensiones prohibidas (opcional, para mayor seguridad)
private static readonly HashSet<string> ExtensionesProhibidas = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
".exe",
".bat",
".cmd",
".msi",
".sh",
".js",
".vbs",
".ps1",
".jar",
".com",
".msp",
".scr",
".docm",
".xlsm",
".pptm"
};
public static bool ValidarArchivo(string rutaArchivo)
{
string extension = Path.GetExtension(rutaArchivo);
// Revisar primero si está en la lista prohibida
if (ExtensionesProhibidas.Contains(extension))
{
return false;
}
//// Solo permitir si está en la lista de permitidas
//return ExtensionesPermitidas.Contains(extension);
return true;
}
/// <summary>
/// Obtiene el tamaño de un archivo en bytes.
/// </summary>
/// <param name="rutaArchivo">Ruta completa del archivo.</param>
/// <returns>Tamaño en bytes, o -1 si el archivo no existe.</returns>
public static long ObtenerTamanoEnBytes(string rutaArchivo)
{
if (!File.Exists(rutaArchivo))
return -1;
FileInfo info = new FileInfo(rutaArchivo);
return info.Length;
}
/// <summary>
/// Obtiene el tamaño de un archivo en formato legible (KB, MB, GB).
/// </summary>
/// <param name="rutaArchivo">Ruta completa del archivo.</param>
/// <returns>Cadena con el tamaño formateado, o mensaje de error.</returns>
public static string ObtenerTamanoFormateado(string rutaArchivo)
{
if (!File.Exists(rutaArchivo))
return "El archivo no existe";
long bytes = new FileInfo(rutaArchivo).Length;
string[] sufijos = { "B", "KB", "MB", "GB", "TB" };
int indice = 0;
double tamaño = bytes;
while (tamaño >= 1024 && indice < sufijos.Length - 1)
{
tamaño /= 1024;
indice++;
}
return $"{tamaño:0.##} {sufijos[indice]}";
}
/// <summary>
/// Obtiene la url del endpoint para obtener el pedimento.
/// </summary>
/// <returns>Cadena del endpoint.</returns>
public static string ObtenerEndpointPedimentos()
{
return @"/api/v1/customs/pedimentos/?pedimento_app=";
}
/// <summary>
/// Obtiene la url del endpoint para obtener el documento.
/// </summary>
/// <returns>Cadena del endpoint.</returns>
public static string ObtenerEndpointDocumentos()
{
return @"/api/v1/record/documents/";
}
public static string CrearEndpointpedimentoDesk()
{
// return @"/api/v1/customs/pedimentos/bulk-create-pedimento_desk/";
// return @"/api/v1/customs/pedimentos/bulk-upload-record-zip/";
return @"/api/v1/customs/pedimentos/bulk-upload-record-zip-async/";
}
/// <summary>
/// Espera hasta que todos los archivos dentro de la carpeta estén libres (no en uso)
/// </summary>
public static bool EsperarArchivosListos(string carpetaRaiz, int timeoutSegundos = 30)
{
var archivos = Directory.GetFiles(carpetaRaiz, "*.*", SearchOption.AllDirectories);
var inicio = DateTime.Now;
while ((DateTime.Now - inicio).TotalSeconds < timeoutSegundos)
{
bool todosListos = true;
foreach (var archivo in archivos)
{
try
{
using (FileStream stream = new FileStream(archivo, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
// Archivo disponible
}
}
catch (IOException)
{
todosListos = false;
break;
}
}
if (todosListos)
return true;
Thread.Sleep(500);
}
return false;
}
/// <summary>
/// Obtiene la carpeta raíz según aplicaWinsaii
/// </summary>
public static (string RutaRaiz, string NombreRaiz) ObtenerCarpetaRaiz(string ruta)
{
SQLiteHelper sqliteHelper = new SQLiteHelper(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "historico.db"));
ConfiguracionExpediente config = ConfiguracionExpediente.ObtenerDesdeBaseDeDatos(sqliteHelper);
bool aplicaWinsaii = config.UsarEstructuraPedimentosWinsaai;
string? carpetaActual = EsCarpeta(ruta) ? ruta : Path.GetDirectoryName(ruta);
string carpetaBase = Path.GetFullPath(config.FolderParaGenerarExpediente);
carpetaActual = Path.GetFullPath(carpetaActual);
string[] segmentosBase = carpetaBase.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
string[] segmentosActual = carpetaActual.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
int nivelDeseado = aplicaWinsaii ? segmentosBase.Length + 2 : segmentosBase.Length + 1;
if (segmentosActual.Length > nivelDeseado)
segmentosActual = segmentosActual.Take(nivelDeseado).ToArray();
string carpetaRaiz = string.Join(Path.DirectorySeparatorChar.ToString(), segmentosActual);
if (!Path.IsPathRooted(carpetaRaiz))
carpetaRaiz = Path.DirectorySeparatorChar + carpetaRaiz;
string nombreRaiz = Path.GetFileName(carpetaRaiz);
return (carpetaRaiz, nombreRaiz);
}
public static bool EsCarpeta(string ruta)
{
return Directory.Exists(ruta);
}
public static string DominioExpedienteElectronico()
{
string efc = Properties.Settings.Default.urlEFC as string;
return efc;
}
public static bool EsValidaNomeclaturaCarpeta(string pathCarpeta)
{
var nombre = Path.GetFileName(pathCarpeta);
string pattern = @"^\d{2}-\d{4}-\d{7}$|^\d{2}-\d{2}-\d{4}-\d{7}$";
bool esValido = System.Text.RegularExpressions.Regex.IsMatch(nombre, pattern);
if (!esValido)
{
return false;
}
return true;
}
public static bool EsValidaNomeclaturaSAAIM3(string pathArchivo)
{
var nombre = Path.GetFileName(pathArchivo);
string pattern = @"^[m|M]\d{7}\.\d{3}$";
bool esValido = System.Text.RegularExpressions.Regex.IsMatch(nombre, pattern);
if (!esValido)
{
return false;
}
return true;
}
public static bool EsArchivoXMl(string rutaArchivo)
{
try
{
string extension = Path.GetExtension(rutaArchivo);
if (!extension.Equals(".xml", StringComparison.OrdinalIgnoreCase))
return false;
XDocument xdoc = XDocument.Load(rutaArchivo);
}
catch (XmlException exception)
{
Globales.logger.LogError("Helpers - EsArchivoXML", exception);
return false;
}
catch (Exception ex)
{
Globales.logger.LogError("Helpers - EsArchivoXML", ex);
return false;
}
return true;
}
public static byte[] CrearZipEnMemoria(string nombreArchivo, byte[] contenido)
{
try
{
using (var memoryStream = new MemoryStream())
{
using (var zip = new System.IO.Compression.ZipArchive(memoryStream, System.IO.Compression.ZipArchiveMode.Create, leaveOpen: true))
{
// Aquí puedes agregar archivos al archivo ZIP si es necesario
var entry = zip.CreateEntry(nombreArchivo);
using (var entryStream = entry.Open())
{
entryStream.Write(contenido, 0, contenido.Length);
}
}
return memoryStream.ToArray();
}
}
catch (Exception ex)
{
// Manejo de la excepción (puedes registrar el error o lanzar una excepción personalizada)
Globales.logger.LogError("Helpers", ex);
return Array.Empty<byte>();
}
}
public static string CalcularHashMD5(string rutaArchivo)
{
using (var md5 = MD5.Create())
{
using (var stream = File.OpenRead(rutaArchivo))
{
var hashBytes = md5.ComputeHash(stream);
StringBuilder sb = new StringBuilder();
foreach (var b in hashBytes)
{
sb.Append(b.ToString("x2"));
}
return sb.ToString();
}
}
}
/// <summary>
/// Crea un ZIP de un solo archivo en una carpeta temporal única.
/// </summary>
/// <param name="rutaArchivo">Archivo a comprimir.</param>
/// <param name="nombreArchivoZip">Nombre del ZIP que se generará.</param>
/// <param name="autoLimpiar">Si es true, borra la carpeta temporal automáticamente después de crear el ZIP.</param>
/// <returns>Ruta completa del ZIP generado.</returns>
public static string CrearZipArchivoEnTemp(string rutaArchivo, string nombreArchivoZip, bool autoLimpiar = false)
{
// Obtiene la ruta raíz de la carpeta temporal del sistema
string tempRoot = Path.Combine(Path.GetTempPath(), "temp-efc-desk");
//string tempRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),"tempEFCDesk");
// Crea una subcarpeta temporal única
string tempFolder = Path.Combine(tempRoot, Guid.NewGuid().ToString().ToLower().Replace("-","").Substring(0,8));
Directory.CreateDirectory(tempFolder);
// Ruta completa del archivo ZIP dentro de la carpeta temporal
string zipPath = Path.Combine(tempFolder, nombreArchivoZip);
try
{
// Verifica que el archivo exista
if (!File.Exists(rutaArchivo))
{
throw new FileNotFoundException($"El archivo no existe: {rutaArchivo}");
}
// Crea el ZIP y agrega el archivo
using (var zip = ZipFile.Open(zipPath, ZipArchiveMode.Create))
{
zip.CreateEntryFromFile(rutaArchivo, Path.GetFileName(rutaArchivo));
}
return zipPath;
}
catch (Exception ex)
{
Globales.logger.LogError("Helpers - CrearZipArchivoEnTemp", ex);
return "";
}
finally
{
if (autoLimpiar)
{
try
{
// Espera un momento para asegurarse de que el ZIP no esté bloqueado
System.Threading.Thread.Sleep(3000);
// Borra toda la carpeta temporal
if (Directory.Exists(tempFolder))
{
Directory.Delete(tempFolder, true);
}
}
catch (Exception ex)
{
Globales.logger.LogError("Helpers - No se pudo limpiar la carpeta temporal", ex);
}
}
}
}
public static string CrearZipMultipleArchivos(string[] rutasArchivos, string nombreArchivoZip, bool autoLimpiar = false)
{
string tempRoot = Path.Combine(Path.GetTempPath(), "temp-efc-desk");
string tempFolder = Path.Combine(tempRoot, Guid.NewGuid().ToString().ToLower().Replace("-", "").Substring(0, 8));
Directory.CreateDirectory(tempFolder);
string zipPath = Path.Combine(tempFolder, nombreArchivoZip);
try
{
using (var zip = ZipFile.Open(zipPath, ZipArchiveMode.Create))
{
foreach (var rutaArchivo in rutasArchivos)
{
if (File.Exists(rutaArchivo))
{
zip.CreateEntryFromFile(rutaArchivo, Path.GetFileName(rutaArchivo));
}
}
}
return zipPath;
}
catch (Exception ex)
{
Globales.logger.LogError("Helpers - CrearZipMultipleArchivos", ex);
return "";
}
finally
{
if (autoLimpiar)
{
try
{
System.Threading.Thread.Sleep(3000);
if (Directory.Exists(tempFolder))
{
Directory.Delete(tempFolder, true);
}
}
catch (Exception ex)
{
Globales.logger.LogError("Helpers - No se pudo limpiar carpeta temporal en CrearZipMultipleArchivos", ex);
}
}
}
}
}
}