A social knowledge tool for researchers built on ATProto
at main 161 lines 5.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 { CuratorId } from '../../../domain/value-objects/CuratorId'; 8import { CardTypeEnum } from '../../../domain/value-objects/CardType'; 9import { CardContent } from '../../../domain/value-objects/CardContent'; 10import { ICardPublisher } from '../../ports/ICardPublisher'; 11import { AuthenticationError } from '../../../../../shared/core/AuthenticationError'; 12 13export interface UpdateNoteCardDTO { 14 cardId: string; 15 note: string; 16 curatorId: string; 17} 18 19export interface UpdateNoteCardResponseDTO { 20 cardId: string; 21} 22 23export class ValidationError extends UseCaseError { 24 constructor(message: string) { 25 super(message); 26 } 27} 28 29export class UpdateNoteCardUseCase 30 implements 31 UseCase< 32 UpdateNoteCardDTO, 33 Result< 34 UpdateNoteCardResponseDTO, 35 ValidationError | AuthenticationError | AppError.UnexpectedError 36 > 37 > 38{ 39 constructor( 40 private cardRepository: ICardRepository, 41 private cardPublisher: ICardPublisher, 42 ) {} 43 44 async execute( 45 request: UpdateNoteCardDTO, 46 ): Promise< 47 Result< 48 UpdateNoteCardResponseDTO, 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 // Find the card 74 const cardResult = await this.cardRepository.findById(cardId); 75 if (cardResult.isErr()) { 76 return err(AppError.UnexpectedError.create(cardResult.error)); 77 } 78 79 const card = cardResult.value; 80 if (!card) { 81 return err(new ValidationError(`Card not found: ${request.cardId}`)); 82 } 83 84 // Verify it's a note card 85 if (card.type.value !== CardTypeEnum.NOTE) { 86 return err( 87 new ValidationError('Card is not a note card and cannot be updated'), 88 ); 89 } 90 91 // Get the note content and verify authorship 92 const noteContent = card.content.noteContent; 93 if (!noteContent) { 94 return err( 95 new ValidationError('Card does not have valid note content'), 96 ); 97 } 98 99 if (!card.curatorId.equals(curatorId)) { 100 return err( 101 new ValidationError('Only the author can update this note card'), 102 ); 103 } 104 105 // Update the note content 106 const updatedNoteContentResult = noteContent.updateText(request.note); 107 if (updatedNoteContentResult.isErr()) { 108 return err(new ValidationError(updatedNoteContentResult.error.message)); 109 } 110 111 // Create new card content with updated note 112 const updatedCardContentResult = CardContent.createNoteContent( 113 request.note, 114 ); 115 if (updatedCardContentResult.isErr()) { 116 return err(new ValidationError(updatedCardContentResult.error.message)); 117 } 118 119 // Update the card content 120 const updateResult = card.updateContent(updatedCardContentResult.value); 121 if (updateResult.isErr()) { 122 return err(new ValidationError(updateResult.error.message)); 123 } 124 125 // Publish the updated card to library first 126 const publishResult = await this.cardPublisher.publishCardToLibrary( 127 card, 128 curatorId, 129 card.publishedRecordId, 130 ); 131 if (publishResult.isErr()) { 132 // Propagate authentication errors 133 if (publishResult.error instanceof AuthenticationError) { 134 return err(publishResult.error); 135 } 136 return err(AppError.UnexpectedError.create(publishResult.error)); 137 } 138 139 // Mark the card in library as published with the new record ID 140 const markPublishedResult = card.markCardInLibraryAsPublished( 141 curatorId, 142 publishResult.value, 143 ); 144 if (markPublishedResult.isErr()) { 145 return err(new ValidationError(markPublishedResult.error.message)); 146 } 147 148 // Save the updated card to repository 149 const saveResult = await this.cardRepository.save(card); 150 if (saveResult.isErr()) { 151 return err(AppError.UnexpectedError.create(saveResult.error)); 152 } 153 154 return ok({ 155 cardId: card.cardId.getStringValue(), 156 }); 157 } catch (error) { 158 return err(AppError.UnexpectedError.create(error)); 159 } 160 } 161}