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 { Collection, CollectionAccessType } from '../../../domain/Collection';
7import { CuratorId } from '../../../domain/value-objects/CuratorId';
8import { ICollectionPublisher } from '../../ports/ICollectionPublisher';
9
10export interface CreateCollectionDTO {
11 name: string;
12 description?: string;
13 curatorId: string;
14}
15
16export interface CreateCollectionResponseDTO {
17 collectionId: string;
18}
19
20export class ValidationError extends UseCaseError {
21 constructor(message: string) {
22 super(message);
23 }
24}
25
26export class CreateCollectionUseCase
27 implements
28 UseCase<
29 CreateCollectionDTO,
30 Result<
31 CreateCollectionResponseDTO,
32 ValidationError | AppError.UnexpectedError
33 >
34 >
35{
36 constructor(
37 private collectionRepository: ICollectionRepository,
38 private collectionPublisher: ICollectionPublisher,
39 ) {}
40
41 async execute(
42 request: CreateCollectionDTO,
43 ): Promise<
44 Result<
45 CreateCollectionResponseDTO,
46 ValidationError | AppError.UnexpectedError
47 >
48 > {
49 try {
50 // Validate and create CuratorId
51 const curatorIdResult = CuratorId.create(request.curatorId);
52 if (curatorIdResult.isErr()) {
53 return err(
54 new ValidationError(
55 `Invalid curator ID: ${curatorIdResult.error.message}`,
56 ),
57 );
58 }
59 const curatorId = curatorIdResult.value;
60
61 // Create collection
62 const collectionResult = Collection.create({
63 authorId: curatorId,
64 name: request.name,
65 description: request.description,
66 accessType: CollectionAccessType.CLOSED,
67 collaboratorIds: [],
68 createdAt: new Date(),
69 updatedAt: new Date(),
70 });
71
72 if (collectionResult.isErr()) {
73 return err(new ValidationError(collectionResult.error.message));
74 }
75
76 const collection = collectionResult.value;
77
78 // Save collection
79 const saveResult = await this.collectionRepository.save(collection);
80 if (saveResult.isErr()) {
81 return err(AppError.UnexpectedError.create(saveResult.error));
82 }
83
84 // Publish collection
85 const publishResult = await this.collectionPublisher.publish(collection);
86 if (publishResult.isErr()) {
87 return err(
88 new ValidationError(
89 `Failed to publish collection: ${publishResult.error.message}`,
90 ),
91 );
92 }
93
94 // Mark collection as published
95 collection.markAsPublished(publishResult.value);
96
97 // Save updated collection with published record ID
98 const saveUpdatedResult =
99 await this.collectionRepository.save(collection);
100 if (saveUpdatedResult.isErr()) {
101 return err(AppError.UnexpectedError.create(saveUpdatedResult.error));
102 }
103
104 return ok({
105 collectionId: collection.collectionId.getStringValue(),
106 });
107 } catch (error) {
108 return err(AppError.UnexpectedError.create(error));
109 }
110 }
111}