metis-desk/modules/resources/src/api/application/resource-input.mapper.ts

180 lines
5.8 KiB
TypeScript
Raw Normal View History

2026-10-05 11:13:51 +00:00
import type { UniqueID } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils";
import type { Resource } from "../domain/resource.aggregate";
import { ResourceCatalogError } from "../domain/resource-definition";
import type { ResourceInput } from "../domain/resource-values";
2026-10-09 08:38:19 +00:00
import { ResourceSpecification, ResourceValues } from "../domain/value-objects/resource-values.vo";
2026-10-05 11:13:51 +00:00
2026-10-20 11:20:22 +00:00
import { directoryDomainInput } from "./directory-domain-input";
2026-10-05 11:13:51 +00:00
import type { InventoryContext } from "./resource.repository";
export function mapResourceInput(
input: ResourceInput,
companyId: UniqueID,
context: InventoryContext,
previous?: Resource
) {
if (previous && previous.values.toPrimitive().templateId !== input.templateId.toLowerCase()) {
return Result.fail(new ResourceCatalogError("TEMPLATE_FIXED"));
}
2026-10-05 15:01:32 +00:00
const captured = previous
? Result.ok(previous.specification)
: captureResourceSpecification(input, companyId, context);
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (!captured.isSuccess) {
return captured;
}
const specification = captured.data;
2026-10-20 11:20:22 +00:00
const directory = directoryDomainInput(input, context.catalog);
if (!directory.isSuccess) {
return directory;
}
const normalized = directory.data
? {
...input,
characteristics: {
...directory.data.characteristics,
[directory.data.dnsId]: directory.data.identity.dnsName,
[directory.data.netbiosId]: directory.data.identity.netbiosName ?? "",
},
}
: input;
const compatibleInput = withMailboxIntegration(normalized, context);
2026-10-05 15:01:32 +00:00
const templateKey = context.catalog.definitions
.find((item) => item.id.toPrimitive() === input.templateId.toLowerCase())
?.stockKey.getOrUndefined();
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (templateKey === "template:access" && compatibleInput.integration?.kind !== "access") {
return Result.fail(new ResourceCatalogError("REFERENCE_UNAVAILABLE"));
}
const references = validateReferences(compatibleInput, context);
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (!references.isSuccess) {
return references;
}
const values = ResourceValues.create(compatibleInput, specification);
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
return values.isSuccess ? Result.ok({ specification, values: values.data }) : values;
}
export function captureResourceSpecification(
input: Pick<ResourceInput, "templateId">,
2026-10-05 15:01:32 +00:00
companyId: UniqueID,
context: Pick<InventoryContext, "catalog">,
options: { existing?: boolean } = {}
2026-10-05 15:01:32 +00:00
) {
const template = context.catalog
.visible(Maybe.some(companyId))
.find((item) => item.id.toPrimitive() === input.templateId.toLowerCase());
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (
!template ||
template.values.data.kind !== "template" ||
!(options.existing || context.catalog.active(template, Maybe.some(companyId)))
2026-10-05 15:01:32 +00:00
) {
return Result.fail(new ResourceCatalogError("TEMPLATE_UNAVAILABLE"));
}
const fields = template.values.data.fields.map((binding) => {
const field = context.catalog.definitions.find(
(item) => item.id.toPrimitive() === binding.fieldId
);
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (!field || field.values.data.kind !== "field") {
throw new Error("Plantilla persistida inconsistente.");
2026-10-05 11:13:51 +00:00
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
return {
fieldId: field.id.toPrimitive(),
name: field.values.data.name,
type: field.values.data.type,
unit: field.values.data.unit,
choices: [...field.values.data.choices],
required: binding.required,
...(binding.sectionId ? { sectionId: binding.sectionId } : {}),
2026-10-05 15:01:32 +00:00
};
});
const created = ResourceSpecification.create({
templateId: template.id.toPrimitive(),
templateName: template.values.data.name,
...(template.values.data.sections ? { sections: [...template.values.data.sections] } : {}),
2026-10-05 15:01:32 +00:00
fields,
});
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (!created.isSuccess) {
return created;
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
return created;
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
function withMailboxIntegration(input: ResourceInput, context: InventoryContext): ResourceInput {
const compatibleInput = { ...input };
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (!compatibleInput.integration) {
const template = context.catalog.definitions.find(
(item) => item.id.toPrimitive() === input.templateId.toLowerCase()
);
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (template?.stockKey.getOrUndefined() === "template:mailbox") {
const addressFieldId = context.catalog.definitions
.find((item) => item.stockKey.getOrUndefined() === "field:email")
?.id.toPrimitive();
const contextFieldId = context.catalog.definitions
.find((item) => item.stockKey.getOrUndefined() === "field:context")
?.id.toPrimitive();
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (!(addressFieldId && contextFieldId)) {
throw new Error("Campos de buzón ausentes.");
2026-10-05 11:13:51 +00:00
}
2026-10-05 15:01:32 +00:00
compatibleInput.integration = {
kind: "mailbox",
addressFieldId,
contextFieldId,
mailboxKind: "corporate",
accountId: null,
2026-10-05 11:13:51 +00:00
};
}
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
return compatibleInput;
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
function validateReferences(compatibleInput: ResourceInput, context: InventoryContext) {
const integration = compatibleInput.integration;
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
if (integration) {
const expected =
integration.kind === "mailbox"
? ([[integration.accountId, "account"]] as const)
: ([
[integration.resourceTypeId, "resource_type"],
[integration.systemId, "system"],
[integration.environmentId, "environment"],
] as const);
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
for (const [id, kind] of expected) {
if (
id &&
!context.references.some((item) => item.id === id.toLowerCase() && item.kind === kind)
) {
return Result.fail(new ResourceCatalogError("REFERENCE_UNAVAILABLE"));
}
}
if (
integration.kind === "access" &&
integration.environmentId &&
!context.references.some(
(item) =>
item.id === integration.environmentId?.toLowerCase() &&
item.systemId === integration.systemId
)
) {
return Result.fail(new ResourceCatalogError("REFERENCE_UNAVAILABLE"));
}
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
return Result.ok(true);
2026-10-05 11:13:51 +00:00
}