metis-desk/modules/assets/src/api/application/asset-relationship.use-cases.ts
David 6c6eee8f93 feat: implement record deletion functionality across various configurations
- Added remove methods to repositories for application, certificate, folder, mail, and printer configurations.
- Implemented use cases for removing configurations, including validation for company and identity.
- Created HTTP routes for deleting configurations with appropriate request handling and error responses.
- Introduced a DeleteRecordDialog component for user confirmation before deletion.
- Updated UI pages to include delete actions for configurations with modal confirmation.
- Added integration tests to verify record deletion functionality and ensure data integrity.
- Documented the record deletion process and its implications in the project documentation.
2026-10-10 00:19:35 +02:00

89 lines
3.4 KiB
TypeScript

import { UniqueID } from "@repo/rdx-ddd";
import { Maybe, Result } from "@repo/rdx-utils";
import type { RelationshipInputDTO } from "../../common/relationships";
import { AssetCatalogError } from "../domain/asset-definition";
import { AssetRelationship } from "../domain/asset-relationship.aggregate";
import { AssetRelationshipValues } from "../domain/value-objects/asset-relationship-values.vo";
import type { IAssetRepository, InventoryContext } from "./asset.repository";
export class AssetRelationshipUseCases {
constructor(private readonly repository: IAssetRepository) {}
save(companyId: string, input: RelationshipInputDTO, actorId: string) {
const company = UniqueID.create(companyId);
const actor = UniqueID.create(actorId);
if (!(company.isSuccess && actor.isSuccess)) {
return Promise.resolve(Result.fail(new AssetCatalogError("INVALID_REQUEST")));
}
return this.repository.saveRelationship(company.data, (context) => {
const mapped = mapRelationshipInput(input, company.data, context);
if (!mapped.isSuccess) {
return Result.fail(mapped.error);
}
const previous = context.relationships.find(
(item) => item.active && item.values.key() === mapped.data.key()
);
if (previous) {
return previous.values.notes === mapped.data.notes
? Result.ok(previous)
: Result.fail(new AssetCatalogError("RELATIONSHIP_EXISTS"));
}
return AssetRelationship.create(
company.data,
mapped.data,
actor.data,
new Date().toISOString()
);
});
}
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 AssetCatalogError("INVALID_REQUEST")));
}
return this.repository.removeRelationship(company.data, identity.data);
}
end(companyId: string, id: string, 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 AssetCatalogError("INVALID_REQUEST")));
}
return this.repository.saveRelationship(company.data, (context) => {
const item = context.relationships.find((entry) => entry.id.equals(identity.data));
return item
? item.end(actor.data, new Date().toISOString())
: Result.fail(new AssetCatalogError("RELATIONSHIP_NOT_FOUND"));
});
}
}
export function mapRelationshipInput(
input: RelationshipInputDTO,
company: UniqueID,
context: InventoryContext
) {
if (
![input.sourceId, input.targetId].every((id) =>
context.assets.some((asset) => asset.id.toPrimitive() === id)
)
) {
return Result.fail(new AssetCatalogError("ASSET_NOT_FOUND"));
}
const scope = Maybe.some(company);
const type = context.catalog
.visible(scope)
.find((item) => item.id.toPrimitive() === input.typeId);
if (!(type && type.values.data.kind === "relation" && context.catalog.active(type, scope))) {
return Result.fail(new AssetCatalogError("RELATION_TYPE_UNAVAILABLE"));
}
return AssetRelationshipValues.create({
...input,
name: type.values.data.name,
inverseName: type.values.data.inverseName,
symmetric: type.values.data.symmetric,
});
}