This repository has no description
1import { Result, ok, err } from '../../../../../shared/core/Result';
2import { BaseUseCase } from '../../../../../shared/core/UseCase';
3import { UseCaseError } from '../../../../../shared/core/UseCaseError';
4import { AppError } from '../../../../../shared/core/AppError';
5import { ICardRepository } from '../../../domain/ICardRepository';
6import { CardId } from '../../../domain/value-objects/CardId';
7import { CollectionId } from '../../../domain/value-objects/CollectionId';
8import { CuratorId } from '../../../domain/value-objects/CuratorId';
9import { CardCollectionService } from '../../../domain/services/CardCollectionService';
10import { AuthenticationError } from '../../../../../shared/core/AuthenticationError';
11import { IEventPublisher } from '../../../../../shared/application/events/IEventPublisher';
12
13export interface RemoveCardFromCollectionDTO {
14 cardId: string;
15 collectionIds: string[];
16 curatorId: string;
17}
18
19export interface RemoveCardFromCollectionResponseDTO {
20 cardId: string;
21}
22
23export class ValidationError extends UseCaseError {
24 constructor(message: string) {
25 super(message);
26 }
27}
28
29export class RemoveCardFromCollectionUseCase extends BaseUseCase<
30 RemoveCardFromCollectionDTO,
31 Result<
32 RemoveCardFromCollectionResponseDTO,
33 ValidationError | AuthenticationError | AppError.UnexpectedError
34 >
35> {
36 constructor(
37 private cardRepository: ICardRepository,
38 private cardCollectionService: CardCollectionService,
39 eventPublisher: IEventPublisher,
40 ) {
41 super(eventPublisher);
42 }
43
44 async execute(
45 request: RemoveCardFromCollectionDTO,
46 ): Promise<
47 Result<
48 RemoveCardFromCollectionResponseDTO,
49 ValidationError | AuthenticationError | AppError.UnexpectedError
50 >
51 > {
52 try {
53 // Validate and create CuratorId
54 const curatorIdResult = CuratorId.create(request.curatorId);
55 if (curatorIdResult.isErr()) {
56 return err(
57 new ValidationError(
58 `Invalid curator ID: ${curatorIdResult.error.message}`,
59 ),
60 );
61 }
62 const curatorId = curatorIdResult.value;
63
64 // Validate and create CardId
65 const cardIdResult = CardId.createFromString(request.cardId);
66 if (cardIdResult.isErr()) {
67 return err(
68 new ValidationError(`Invalid card ID: ${cardIdResult.error.message}`),
69 );
70 }
71 const cardId = cardIdResult.value;
72
73 // Validate and create CollectionIds
74 const collectionIds: CollectionId[] = [];
75 for (const collectionIdStr of request.collectionIds) {
76 const collectionIdResult =
77 CollectionId.createFromString(collectionIdStr);
78 if (collectionIdResult.isErr()) {
79 return err(
80 new ValidationError(
81 `Invalid collection ID: ${collectionIdResult.error.message}`,
82 ),
83 );
84 }
85 collectionIds.push(collectionIdResult.value);
86 }
87
88 // Find the card
89 const cardResult = await this.cardRepository.findById(cardId);
90 if (cardResult.isErr()) {
91 return err(AppError.UnexpectedError.create(cardResult.error));
92 }
93
94 const card = cardResult.value;
95 if (!card) {
96 return err(new ValidationError(`Card not found: ${request.cardId}`));
97 }
98
99 // Remove card from collections using domain service
100 const removeFromCollectionsResult =
101 await this.cardCollectionService.removeCardFromCollections(
102 card,
103 collectionIds,
104 curatorId,
105 );
106 if (removeFromCollectionsResult.isErr()) {
107 // Propagate authentication errors
108 if (removeFromCollectionsResult.error instanceof AuthenticationError) {
109 return err(removeFromCollectionsResult.error);
110 }
111 if (
112 removeFromCollectionsResult.error instanceof AppError.UnexpectedError
113 ) {
114 return err(removeFromCollectionsResult.error);
115 }
116 return err(
117 new ValidationError(removeFromCollectionsResult.error.message),
118 );
119 }
120
121 // Publish events for each updated collection
122 const updatedCollections = removeFromCollectionsResult.value;
123 for (const collection of updatedCollections) {
124 const publishResult = await this.publishEventsForAggregate(collection);
125 if (publishResult.isErr()) {
126 console.error(
127 'Failed to publish events for collection:',
128 publishResult.error,
129 );
130 // Don't fail the operation if event publishing fails
131 }
132 }
133
134 return ok({
135 cardId: card.cardId.getStringValue(),
136 });
137 } catch (error) {
138 return err(AppError.UnexpectedError.create(error));
139 }
140 }
141}