A social knowledge tool for researchers built on ATProto
1import { Result, ok, err } from '../../../../../shared/core/Result';
2import { UseCase } 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 { CuratorId } from '../../../domain/value-objects/CuratorId';
8import { CardLibraryService } from '../../../domain/services/CardLibraryService';
9
10export interface RemoveCardFromLibraryDTO {
11 cardId: string;
12 curatorId: string;
13}
14
15export interface RemoveCardFromLibraryResponseDTO {
16 cardId: string;
17}
18
19export class ValidationError extends UseCaseError {
20 constructor(message: string) {
21 super(message);
22 }
23}
24
25export class RemoveCardFromLibraryUseCase
26 implements
27 UseCase<
28 RemoveCardFromLibraryDTO,
29 Result<
30 RemoveCardFromLibraryResponseDTO,
31 ValidationError | AppError.UnexpectedError
32 >
33 >
34{
35 constructor(
36 private cardRepository: ICardRepository,
37 private cardLibraryService: CardLibraryService,
38 ) {}
39
40 async execute(
41 request: RemoveCardFromLibraryDTO,
42 ): Promise<
43 Result<
44 RemoveCardFromLibraryResponseDTO,
45 ValidationError | AppError.UnexpectedError
46 >
47 > {
48 try {
49 // Validate and create CuratorId
50 const curatorIdResult = CuratorId.create(request.curatorId);
51 if (curatorIdResult.isErr()) {
52 return err(
53 new ValidationError(
54 `Invalid curator ID: ${curatorIdResult.error.message}`,
55 ),
56 );
57 }
58 const curatorId = curatorIdResult.value;
59
60 // Validate and create CardId
61 const cardIdResult = CardId.createFromString(request.cardId);
62 if (cardIdResult.isErr()) {
63 return err(
64 new ValidationError(`Invalid card ID: ${cardIdResult.error.message}`),
65 );
66 }
67 const cardId = cardIdResult.value;
68
69 // Find the card
70 const cardResult = await this.cardRepository.findById(cardId);
71 if (cardResult.isErr()) {
72 return err(AppError.UnexpectedError.create(cardResult.error));
73 }
74
75 const card = cardResult.value;
76 if (!card) {
77 return err(new ValidationError(`Card not found: ${request.cardId}`));
78 }
79
80 // Remove card from library using domain service
81 const removeFromLibraryResult =
82 await this.cardLibraryService.removeCardFromLibrary(card, curatorId);
83 if (removeFromLibraryResult.isErr()) {
84 if (removeFromLibraryResult.error instanceof AppError.UnexpectedError) {
85 return err(removeFromLibraryResult.error);
86 }
87 return err(new ValidationError(removeFromLibraryResult.error.message));
88 }
89
90 const updatedCard = removeFromLibraryResult.value;
91 if (
92 updatedCard.libraryCount == 0 &&
93 updatedCard.curatorId.equals(curatorId)
94 ) {
95 // If no curators have this card in their library and the curator is the owner, delete the card
96 const deleteResult = await this.cardRepository.delete(card.cardId);
97 if (deleteResult.isErr()) {
98 return err(AppError.UnexpectedError.create(deleteResult.error));
99 }
100 }
101
102 return ok({
103 cardId: card.cardId.getStringValue(),
104 });
105 } catch (error) {
106 return err(AppError.UnexpectedError.create(error));
107 }
108 }
109}