metis-desk/modules/resources/src/api/domain/resource-catalog-seed.ts
David 0e8e15c9c2 feat: Implement account deletion functionality with UI and API integration
- Added `removeAccessAccount` function to handle account deletion in the database, ensuring no external references exist.
- Created `deleteAccount` API function to facilitate account deletion requests from the client.
- Developed `AccountDeleteDialog` component for user confirmation before account deletion, integrating with the delete API.
- Introduced resource image handling with validation for PNG uploads, including UI components for image selection and preview.
- Implemented resource icon template evolution logic to maintain icon bindings without overwriting existing fields.
- Added scripts for auditing account deletion and usage checks, ensuring robust testing of the new features.
2026-10-27 11:39:53 +01:00

304 lines
8.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { UniqueID } from "@repo/rdx-ddd";
import { BUILTIN_RESOURCE_TEMPLATE_ICONS } from "../../common/resource-template-icons";
import { evolveOperatingSystemTemplate } from "./evolve-operating-system-template";
import { evolveResourceIconTemplates } from "./evolve-resource-icon-templates";
import type { ResourceCatalog } from "./resource-catalog.aggregate";
import type { ResourceDefinitionSpec, ResourceFieldType } from "./resource-definition";
import { ResourceDefinitionValues } from "./value-objects/resource-definition-values.vo";
const FIELDS: readonly [string, string, ResourceFieldType, string, (readonly string[])?][] = [
[
"os_family",
"Familia del sistema operativo",
"text",
"Familia comercial del producto. Ejemplo: Windows Server.",
],
[
"os_product_version",
"Versión principal del producto",
"text",
"Versión comercial, no la versión instalada. Ejemplo: 2022 o 24.04 LTS.",
],
[
"os_edition_state",
"Estado de edición",
"choice",
"Distingue edición conocida, no aplicable y desconocida. Ejemplo: known para Pro.",
["known", "not_applicable", "unknown"],
],
[
"email",
"Dirección de correo",
"text",
"Indica la dirección completa del buzón. Ejemplo: soporte@empresa.es.",
],
[
"provider",
"Proveedor",
"text",
"Indica el proveedor o fabricante del servicio. Ejemplo: Microsoft 365.",
],
[
"context",
"Contexto",
"text",
"Aclara el uso, área o persona a la que está destinado. Ejemplo: facturación.",
],
["unc", "Ruta UNC", "text", "Usa la ruta de red completa. Ejemplo: \\servidor\\contabilidad."],
[
"server",
"Servidor (referencia documental)",
"text",
"Anota el servidor que publica el recurso, si se conoce. Ejemplo: FS-01.",
],
[
"description",
"Descripción",
"text",
"Añade los detalles necesarios para identificar o utilizar el recurso. Ejemplo: acceso solo para administración.",
],
[
"url",
"URL",
"text",
"Incluye la dirección web de acceso o de documentación. Ejemplo: https://portal.empresa.es.",
],
[
"holder",
"Titular",
"text",
"Indica la persona u organización titular del certificado. Ejemplo: Empresa S. L.",
],
[
"issuer",
"Emisor",
"text",
"Indica la entidad que emitió el certificado. Ejemplo: Let's Encrypt.",
],
[
"expires",
"Caducidad",
"date",
"Indica la fecha en la que deja de ser válido. Ejemplo: 2027-06-30.",
],
[
"fingerprint",
"Huella digital",
"text",
"Copia la huella o identificador único del certificado. Ejemplo: SHA-256 A1:B2:C3:…",
],
[
"purpose",
"Finalidad",
"text",
"Explica qué servicio, proceso o equipo utiliza este recurso. Ejemplo: firma de facturas.",
],
[
"reference",
"Referencia",
"text",
"Registra el identificador, número de contrato o referencia del proveedor. Ejemplo: contrato MS-2026-014.",
],
[
"software_product",
"Producto de software",
"text",
"Indica el nombre comercial del producto licenciado. Ejemplo: Microsoft 365 Business Premium.",
],
[
"software_edition",
"Edición o plan",
"text",
"Indica la edición, nivel o plan contratado. Ejemplo: Enterprise E3.",
],
[
"license_model",
"Modalidad de licencia",
"choice",
"Selecciona cómo se adquiere o mantiene la licencia. Ejemplo: Suscripción.",
["Suscripción", "Perpetua", "OEM", "Otra"],
],
[
"license_metric",
"Criterio de licenciamiento",
"choice",
"Selecciona la unidad con la que se calcula la cobertura contratada. Ejemplo: Por usuario.",
["Por usuario", "Por dispositivo", "Por servidor", "Concurrente", "Corporativa", "Otro"],
],
[
"license_quantity",
"Cantidad contratada",
"number",
"Indica el número de licencias o unidades cubiertas. Ejemplo: 25.",
],
[
"renews",
"Fecha de renovación",
"date",
"Indica la próxima fecha prevista de renovación. Ejemplo: 2027-01-01.",
],
[
"auto_renew",
"Renovación automática",
"boolean",
"Marca si la renovación se realiza automáticamente. Ejemplo: Sí si el proveedor carga el siguiente periodo.",
],
[
"domain_dns",
"Nombre DNS",
"text",
"Nombre DNS del dominio. Ejemplo: empresa.local. IDN: introducir el nombre ASCII punycode.",
],
[
"domain_netbios",
"Nombre NetBIOS",
"text",
"Nombre corto del dominio, opcional, hasta 15 caracteres. Ejemplo: EMPRESA.",
],
[
"icon",
"Icono",
"image",
"Imagen PNG estática de hasta 512 × 512 píxeles y 2 MiB. Representa el producto. Ejemplo: icono de la aplicación.",
],
];
const TEMPLATES: readonly [
keyof typeof BUILTIN_RESOURCE_TEMPLATE_ICONS,
string,
readonly string[],
][] = [
["mailbox", "Buzón de correo", ["email", "provider", "context"]],
["access", "Recurso de acceso", ["reference"]],
["shared_folder", "Carpeta compartida", ["unc", "server", "description"]],
["support", "Herramienta de asistencia remota", ["provider", "url", "description"]],
[
"os",
"Sistema operativo",
[
"provider",
"os_family",
"os_product_version",
"os_edition_state",
"software_edition",
"description",
"url",
"icon",
],
],
["application", "Aplicación", ["provider", "url", "description", "icon"]],
["certificate", "Certificado digital", ["holder", "issuer", "expires", "fingerprint", "purpose"]],
[
"software_license",
"Licencia de software",
[
"software_product",
"software_edition",
"provider",
"license_model",
"license_metric",
"license_quantity",
"reference",
"expires",
"renews",
"auto_renew",
"description",
"icon",
],
],
["windows_domain", "Dominio Windows", ["domain_dns", "domain_netbios"]],
];
/** Solo alimenta definiciones; no crea recursos ni migra registros anteriores. */
const SECTION_FIELDS: readonly [string, readonly string[]][] = [
["Identificación", ["holder", "issuer", "fingerprint"]],
["Producto", ["software_product", "software_edition", "provider"]],
["Contratación", ["license_model", "license_metric", "license_quantity", "reference"]],
["Vigencia y renovación", ["expires", "renews", "auto_renew"]],
["Uso y observaciones", ["purpose", "description"]],
];
export function seedResourceCatalog(catalog: ResourceCatalog) {
const evolveIcons = !catalog.definitions.some(
(item) => item.stockKey.getOrUndefined() === "field:icon"
);
const evolveOs = !catalog.definitions.some(
(item) => item.stockKey.getOrUndefined() === "field:os_edition_state"
);
let current = catalog;
const add = (key: string, input: ResourceDefinitionSpec) => {
const values = ResourceDefinitionValues.create(input);
if (!values.isSuccess) {
throw new Error("Definición inicial de recursos inválida.");
}
const result = current.seed(key, values.data);
if (!result.isSuccess) {
throw new Error("Catálogo inicial de recursos inconsistente.");
}
current = result.data;
};
for (const [key, name, type, description, choices] of FIELDS) {
add(`field:${key}`, {
kind: "field",
name,
description,
type,
unit: "",
choices: [...(choices ?? [])],
});
}
for (const [key, name, fields] of TEMPLATES) {
const sectionFields = fields;
const sections = (["certificate", "software_license"].includes(key) ? SECTION_FIELDS : [])
.filter(([, keys]) => keys.some((field) => sectionFields.includes(field)))
.map(([name, keys]) => ({
id: UniqueID.generateNewID().toPrimitive(),
name,
description: "",
keys,
}));
const references = fields.map((field) => {
const id = current.definitions
.find((item) => item.stockKey.getOrUndefined() === `field:${field}`)
?.id.toPrimitive();
if (!id) {
throw new Error("Campo inicial de recursos ausente.");
}
const sectionId = sections.find((section) => section.keys.includes(field))?.id;
return {
fieldId: id,
required: key === "windows_domain" && field === "domain_dns",
...(sectionId ? { sectionId } : {}),
};
});
add(`template:${key}`, {
kind: "template",
icon: BUILTIN_RESOURCE_TEMPLATE_ICONS[key],
...(key === "software_license"
? { usage: "license" as const }
: key === "support" || key === "os"
? { usage: key }
: {}),
name,
description: "",
fields: references,
...(sections.length
? { sections: sections.map(({ id, name, description }) => ({ id, name, description })) }
: {}),
});
}
if (evolveOs) {
current = evolveOperatingSystemTemplate(current);
}
return evolveIcons ? evolveResourceIconTemplates(current) : current;
}