A social knowledge tool for researchers built on ATProto
at development 123 lines 3.7 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 { ICollectionRepository } from '../../../domain/ICollectionRepository'; 6import { CollectionId } from '../../../domain/value-objects/CollectionId'; 7import { CuratorId } from '../../../domain/value-objects/CuratorId'; 8import { ICollectionPublisher } from '../../ports/ICollectionPublisher'; 9 10export interface DeleteCollectionDTO { 11 collectionId: string; 12 curatorId: string; 13} 14 15export interface DeleteCollectionResponseDTO { 16 collectionId: string; 17} 18 19export class ValidationError extends UseCaseError { 20 constructor(message: string) { 21 super(message); 22 } 23} 24 25export class DeleteCollectionUseCase 26 implements 27 UseCase< 28 DeleteCollectionDTO, 29 Result< 30 DeleteCollectionResponseDTO, 31 ValidationError | AppError.UnexpectedError 32 > 33 > 34{ 35 constructor( 36 private collectionRepository: ICollectionRepository, 37 private collectionPublisher: ICollectionPublisher, 38 ) {} 39 40 async execute( 41 request: DeleteCollectionDTO, 42 ): Promise< 43 Result< 44 DeleteCollectionResponseDTO, 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 CollectionId 61 const collectionIdResult = CollectionId.createFromString( 62 request.collectionId, 63 ); 64 if (collectionIdResult.isErr()) { 65 return err( 66 new ValidationError( 67 `Invalid collection ID: ${collectionIdResult.error.message}`, 68 ), 69 ); 70 } 71 const collectionId = collectionIdResult.value; 72 73 // Find the collection 74 const collectionResult = 75 await this.collectionRepository.findById(collectionId); 76 if (collectionResult.isErr()) { 77 return err(AppError.UnexpectedError.create(collectionResult.error)); 78 } 79 80 const collection = collectionResult.value; 81 if (!collection) { 82 return err( 83 new ValidationError(`Collection not found: ${request.collectionId}`), 84 ); 85 } 86 87 // Check if user is the author 88 if (!collection.authorId.equals(curatorId)) { 89 return err( 90 new ValidationError( 91 'Only the collection author can delete the collection', 92 ), 93 ); 94 } 95 96 // Unpublish collection if it was published 97 if (collection.isPublished && collection.publishedRecordId) { 98 const unpublishResult = await this.collectionPublisher.unpublish( 99 collection.publishedRecordId, 100 ); 101 if (unpublishResult.isErr()) { 102 return err( 103 new ValidationError( 104 `Failed to unpublish collection: ${unpublishResult.error.message}`, 105 ), 106 ); 107 } 108 } 109 110 // Delete collection from repository 111 const deleteResult = await this.collectionRepository.delete(collectionId); 112 if (deleteResult.isErr()) { 113 return err(AppError.UnexpectedError.create(deleteResult.error)); 114 } 115 116 return ok({ 117 collectionId: collection.collectionId.getStringValue(), 118 }); 119 } catch (error) { 120 return err(AppError.UnexpectedError.create(error)); 121 } 122 } 123}