- Add SoftwareInstallationValues value object for encapsulating software installation data. - Create HTTP routes for managing software installations, including GET, POST, and DELETE operations. - Implement Sequelize repository for software installations, handling database interactions. - Add migration script for creating necessary database tables for software installations. - Create persistence mapper for transforming between domain models and database rows. - Define snapshot schema for software installations to ensure data consistency. - Introduce common schemas for software installations to validate API requests and responses. - Develop UI components for displaying and managing software installations, including history dialogs and forms. - Implement API client for interacting with software installation endpoints. - Write tests for software installations panel and form components to ensure functionality.
225 lines
6.7 KiB
TypeScript
225 lines
6.7 KiB
TypeScript
import { UniqueID } from "@repo/rdx-ddd";
|
|
|
|
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[])?][] = [
|
|
[
|
|
"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.",
|
|
],
|
|
];
|
|
const TEMPLATES: readonly [string, 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", "software_edition", "description"]],
|
|
["application", "Aplicación", ["provider", "url", "description"]],
|
|
["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",
|
|
],
|
|
],
|
|
];
|
|
/** 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) {
|
|
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 = (fields.length > 3 ? 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: false, ...(sectionId ? { sectionId } : {}) };
|
|
});
|
|
|
|
add(`template:${key}`, {
|
|
kind: "template",
|
|
...(key === "support" || key === "os" ? { usage: key } : {}),
|
|
name,
|
|
description: "",
|
|
fields: references,
|
|
...(sections.length
|
|
? { sections: sections.map(({ id, name, description }) => ({ id, name, description })) }
|
|
: {}),
|
|
});
|
|
}
|
|
|
|
return current;
|
|
}
|