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