A social knowledge tool for researchers built on ATProto
at main 127 lines 4.1 kB view raw
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 { 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'; 11 12export interface RemoveCardFromCollectionDTO { 13 cardId: string; 14 collectionIds: string[]; 15 curatorId: string; 16} 17 18export interface RemoveCardFromCollectionResponseDTO { 19 cardId: string; 20} 21 22export class ValidationError extends UseCaseError { 23 constructor(message: string) { 24 super(message); 25 } 26} 27 28export class RemoveCardFromCollectionUseCase 29 implements 30 UseCase< 31 RemoveCardFromCollectionDTO, 32 Result< 33 RemoveCardFromCollectionResponseDTO, 34 ValidationError | AuthenticationError | AppError.UnexpectedError 35 > 36 > 37{ 38 constructor( 39 private cardRepository: ICardRepository, 40 private cardCollectionService: CardCollectionService, 41 ) {} 42 43 async execute( 44 request: RemoveCardFromCollectionDTO, 45 ): Promise< 46 Result< 47 RemoveCardFromCollectionResponseDTO, 48 ValidationError | AuthenticationError | AppError.UnexpectedError 49 > 50 > { 51 try { 52 // Validate and create CuratorId 53 const curatorIdResult = CuratorId.create(request.curatorId); 54 if (curatorIdResult.isErr()) { 55 return err( 56 new ValidationError( 57 `Invalid curator ID: ${curatorIdResult.error.message}`, 58 ), 59 ); 60 } 61 const curatorId = curatorIdResult.value; 62 63 // Validate and create CardId 64 const cardIdResult = CardId.createFromString(request.cardId); 65 if (cardIdResult.isErr()) { 66 return err( 67 new ValidationError(`Invalid card ID: ${cardIdResult.error.message}`), 68 ); 69 } 70 const cardId = cardIdResult.value; 71 72 // Validate and create CollectionIds 73 const collectionIds: CollectionId[] = []; 74 for (const collectionIdStr of request.collectionIds) { 75 const collectionIdResult = 76 CollectionId.createFromString(collectionIdStr); 77 if (collectionIdResult.isErr()) { 78 return err( 79 new ValidationError( 80 `Invalid collection ID: ${collectionIdResult.error.message}`, 81 ), 82 ); 83 } 84 collectionIds.push(collectionIdResult.value); 85 } 86 87 // Find the card 88 const cardResult = await this.cardRepository.findById(cardId); 89 if (cardResult.isErr()) { 90 return err(AppError.UnexpectedError.create(cardResult.error)); 91 } 92 93 const card = cardResult.value; 94 if (!card) { 95 return err(new ValidationError(`Card not found: ${request.cardId}`)); 96 } 97 98 // Remove card from collections using domain service 99 const removeFromCollectionsResult = 100 await this.cardCollectionService.removeCardFromCollections( 101 card, 102 collectionIds, 103 curatorId, 104 ); 105 if (removeFromCollectionsResult.isErr()) { 106 // Propagate authentication errors 107 if (removeFromCollectionsResult.error instanceof AuthenticationError) { 108 return err(removeFromCollectionsResult.error); 109 } 110 if ( 111 removeFromCollectionsResult.error instanceof AppError.UnexpectedError 112 ) { 113 return err(removeFromCollectionsResult.error); 114 } 115 return err( 116 new ValidationError(removeFromCollectionsResult.error.message), 117 ); 118 } 119 120 return ok({ 121 cardId: card.cardId.getStringValue(), 122 }); 123 } catch (error) { 124 return err(AppError.UnexpectedError.create(error)); 125 } 126 } 127}