metis-desk/modules/resources/src/api/application/resource.use-cases.ts

166 lines
5.5 KiB
TypeScript
Raw Normal View History

2026-10-05 11:13:51 +00:00
import { UniqueID } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils";
import { Resource } from "../domain/resource.aggregate";
import { ResourceCatalogError } from "../domain/resource-definition";
import type { ResourceInput } from "../domain/resource-values";
import { ResourceValues } from "../domain/value-objects/resource-values.vo";
2026-10-05 11:13:51 +00:00
import type { IResourceRepository } from "./resource.repository";
import { mapResourceInput } from "./resource-input.mapper";
2026-10-10 10:01:58 +00:00
2026-10-05 11:13:51 +00:00
export class ResourceUseCases {
constructor(private readonly repository: IResourceRepository) {}
2026-10-10 10:01:58 +00:00
remove(companyId: string, id: string) {
const company = UniqueID.create(companyId);
const identity = UniqueID.create(id);
if (!(company.isSuccess && identity.isSuccess)) {
return Promise.resolve(Result.fail(new ResourceCatalogError("INVALID_REQUEST")));
}
return this.repository.remove(company.data, identity.data);
}
setActive(companyId: string, id: string, active: boolean, actorId: string) {
const company = UniqueID.create(companyId);
const identity = UniqueID.create(id);
const actor = UniqueID.create(actorId);
if (!(company.isSuccess && identity.isSuccess && actor.isSuccess)) {
return Promise.resolve(Result.fail(new ResourceCatalogError("INVALID_REQUEST")));
}
return this.repository.save(company.data, (context) => {
2026-10-24 23:19:17 +00:00
const previous = context.resources.find(
(resource) => resource.belongsToCompany(company.data) && resource.id.equals(identity.data)
);
if (!previous) {
return Result.fail(new ResourceCatalogError("RESOURCE_NOT_FOUND"));
}
const values = ResourceValues.create(
{ ...previous.values.toPrimitive(), active },
previous.specification
);
if (!values.isSuccess) {
return Result.fail(values.error);
}
return previous.update(values.data, actor.data, new Date().toISOString());
});
}
2026-10-24 23:19:17 +00:00
async get(companyId: string) {
2026-10-05 11:13:51 +00:00
const company = UniqueID.create(companyId);
2026-10-10 10:01:58 +00:00
2026-10-05 11:13:51 +00:00
if (!company.isSuccess) {
2026-10-24 23:19:17 +00:00
return Result.fail(new ResourceCatalogError("INVALID_REQUEST"));
2026-10-05 11:13:51 +00:00
}
2026-10-10 10:01:58 +00:00
2026-10-24 23:19:17 +00:00
const result = await this.repository.get(company.data);
return result.isSuccess
? Result.ok({
...result.data,
resources: result.data.resources.filter((resource) =>
resource.belongsToCompany(company.data)
),
})
: result;
2026-10-05 11:13:51 +00:00
}
2026-10-10 10:01:58 +00:00
2026-10-05 11:13:51 +00:00
save(companyId: string, id: string | undefined, input: ResourceInput, actorId: string) {
const company = UniqueID.create(companyId);
const actor = UniqueID.create(actorId);
const identity = id ? UniqueID.create(id) : undefined;
2026-10-10 10:01:58 +00:00
2026-10-05 11:13:51 +00:00
if (!(company.isSuccess && actor.isSuccess) || (identity && !identity.isSuccess)) {
return Promise.resolve(Result.fail(new ResourceCatalogError("INVALID_REQUEST")));
}
2026-10-10 10:01:58 +00:00
return this.repository.save(
company.data,
2026-10-24 23:19:17 +00:00
(loaded) => {
const context = {
...loaded,
resources: loaded.resources.filter((resource) => resource.belongsToCompany(company.data)),
};
const previous = identity?.isSuccess
? context.resources.find((resource) => resource.id.equals(identity.data))
: undefined;
if (id && !previous) {
return Result.fail(new ResourceCatalogError("RESOURCE_NOT_FOUND"));
}
const mapped = mapResourceInput(input, company.data, context, previous);
if (!mapped.isSuccess) {
return Result.fail(mapped.error);
}
const current = mapped.data.values.toPrimitive();
if (
current.integration?.kind === "mailbox" &&
context.resources.some((item) => {
const old = item.values.toPrimitive();
return (
!item.id.equals(previous?.id) &&
old.integration?.kind === "mailbox" &&
old.characteristics[old.integration.addressFieldId] ===
current.characteristics[
current.integration?.kind === "mailbox" ? current.integration.addressFieldId : ""
]
);
})
) {
return Result.fail(new ResourceCatalogError("NAME_EXISTS"));
}
if (
context.resources.some(
(item) =>
!item.id.equals(previous?.id) &&
item.values.toPrimitive().templateId ===
mapped.data.values.toPrimitive().templateId &&
sameAccessContext(item.values.toPrimitive().integration, current.integration) &&
item.values.name.toPrimitive().toLocaleLowerCase("es") ===
mapped.data.values.name.toPrimitive().toLocaleLowerCase("es")
)
) {
return Result.fail(new ResourceCatalogError("NAME_EXISTS"));
}
const now = new Date().toISOString();
return previous
? previous.update(mapped.data.values, actor.data, now)
: Resource.create(
company.data,
mapped.data.specification,
mapped.data.values,
actor.data,
now
);
},
id ? undefined : { templateId: input.templateId, actorId: actor.data }
);
2026-10-05 11:13:51 +00:00
}
}
2026-10-05 15:01:32 +00:00
function sameAccessContext(
first: ResourceInput["integration"],
second: ResourceInput["integration"]
) {
if (first?.kind !== "access" || second?.kind !== "access") {
return true;
}
2026-10-10 10:01:58 +00:00
2026-10-05 15:01:32 +00:00
return (
first.resourceTypeId === second.resourceTypeId &&
first.systemId === second.systemId &&
first.environmentId === second.environmentId
);
}