A social knowledge tool for researchers built on ATProto
at main 150 lines 4.8 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 { CollectionName } from '../../../domain/value-objects/CollectionName'; 9import { CollectionDescription } from '../../../domain/value-objects/CollectionDescription'; 10import { ICollectionPublisher } from '../../ports/ICollectionPublisher'; 11import { AuthenticationError } from '../../../../../shared/core/AuthenticationError'; 12 13export interface UpdateCollectionDTO { 14 collectionId: string; 15 name: string; 16 description?: string; 17 curatorId: string; 18} 19 20export interface UpdateCollectionResponseDTO { 21 collectionId: string; 22} 23 24export class ValidationError extends UseCaseError { 25 constructor(message: string) { 26 super(message); 27 } 28} 29 30export class UpdateCollectionUseCase 31 implements 32 UseCase< 33 UpdateCollectionDTO, 34 Result< 35 UpdateCollectionResponseDTO, 36 ValidationError | AuthenticationError | AppError.UnexpectedError 37 > 38 > 39{ 40 constructor( 41 private collectionRepository: ICollectionRepository, 42 private collectionPublisher: ICollectionPublisher, 43 ) {} 44 45 async execute( 46 request: UpdateCollectionDTO, 47 ): Promise< 48 Result< 49 UpdateCollectionResponseDTO, 50 ValidationError | AuthenticationError | AppError.UnexpectedError 51 > 52 > { 53 try { 54 // Validate and create CuratorId 55 const curatorIdResult = CuratorId.create(request.curatorId); 56 if (curatorIdResult.isErr()) { 57 return err( 58 new ValidationError( 59 `Invalid curator ID: ${curatorIdResult.error.message}`, 60 ), 61 ); 62 } 63 const curatorId = curatorIdResult.value; 64 65 // Validate and create CollectionId 66 const collectionIdResult = CollectionId.createFromString( 67 request.collectionId, 68 ); 69 if (collectionIdResult.isErr()) { 70 return err( 71 new ValidationError( 72 `Invalid collection ID: ${collectionIdResult.error.message}`, 73 ), 74 ); 75 } 76 const collectionId = collectionIdResult.value; 77 78 // Find the collection 79 const collectionResult = 80 await this.collectionRepository.findById(collectionId); 81 if (collectionResult.isErr()) { 82 return err(AppError.UnexpectedError.create(collectionResult.error)); 83 } 84 85 const collection = collectionResult.value; 86 if (!collection) { 87 return err( 88 new ValidationError(`Collection not found: ${request.collectionId}`), 89 ); 90 } 91 92 // Check if user is the author 93 if (!collection.authorId.equals(curatorId)) { 94 return err( 95 new ValidationError( 96 'Only the collection author can update the collection', 97 ), 98 ); 99 } 100 101 // Update collection details using domain method 102 const updateResult = collection.updateDetails( 103 request.name, 104 request.description, 105 ); 106 if (updateResult.isErr()) { 107 return err(new ValidationError(updateResult.error.message)); 108 } 109 110 // Save updated collection 111 const saveResult = await this.collectionRepository.save(collection); 112 if (saveResult.isErr()) { 113 return err(AppError.UnexpectedError.create(saveResult.error)); 114 } 115 116 // Republish collection if it was already published 117 if (collection.isPublished) { 118 const republishResult = 119 await this.collectionPublisher.publish(collection); 120 if (republishResult.isErr()) { 121 // Propagate authentication errors 122 if (republishResult.error instanceof AuthenticationError) { 123 return err(republishResult.error); 124 } 125 return err( 126 new ValidationError( 127 `Failed to republish collection: ${republishResult.error.message}`, 128 ), 129 ); 130 } 131 132 // Update published record ID 133 collection.markAsPublished(republishResult.value); 134 135 // Save collection with updated published record ID 136 const saveUpdatedResult = 137 await this.collectionRepository.save(collection); 138 if (saveUpdatedResult.isErr()) { 139 return err(AppError.UnexpectedError.create(saveUpdatedResult.error)); 140 } 141 } 142 143 return ok({ 144 collectionId: collection.collectionId.getStringValue(), 145 }); 146 } catch (error) { 147 return err(AppError.UnexpectedError.create(error)); 148 } 149 } 150}