This repository has no description
4.6 kB
164 lines
1import { err, ok, Result } from 'src/shared/core/Result';
2import { UseCase } from 'src/shared/core/UseCase';
3import {
4 ICollectionQueryRepository,
5 CollectionSortField,
6 SortOrder,
7} from '../../../domain/ICollectionQueryRepository';
8import { IProfileService } from 'src/modules/cards/domain/services/IProfileService';
9import { DIDOrHandle } from 'src/modules/atproto/domain/DIDOrHandle';
10import { IIdentityResolutionService } from 'src/modules/atproto/domain/services/IIdentityResolutionService';
11
12export interface GetCollectionsQuery {
13 curatorId: string;
14 page?: number;
15 limit?: number;
16 sortBy?: CollectionSortField;
17 sortOrder?: SortOrder;
18 searchText?: string;
19}
20
21// Enriched data for the final use case result
22export interface CollectionListItemDTO {
23 id: string;
24 uri?: string;
25 name: string;
26 description?: string;
27 updatedAt: Date;
28 createdAt: Date;
29 cardCount: number;
30 author: {
31 id: string;
32 name: string;
33 handle: string;
34 avatarUrl?: string;
35 description?: string;
36 };
37}
38export interface GetCollectionsResult {
39 collections: CollectionListItemDTO[];
40 pagination: {
41 currentPage: number;
42 totalPages: number;
43 totalCount: number;
44 hasMore: boolean;
45 limit: number;
46 };
47 sorting: {
48 sortBy: CollectionSortField;
49 sortOrder: SortOrder;
50 };
51}
52
53export class ValidationError extends Error {
54 constructor(message: string) {
55 super(message);
56 this.name = 'ValidationError';
57 }
58}
59
60export class GetCollectionsUseCase
61 implements UseCase<GetCollectionsQuery, Result<GetCollectionsResult>>
62{
63 constructor(
64 private collectionQueryRepo: ICollectionQueryRepository,
65 private profileService: IProfileService,
66 private identityResolver: IIdentityResolutionService,
67 ) {}
68
69 async execute(
70 query: GetCollectionsQuery,
71 ): Promise<Result<GetCollectionsResult>> {
72 // Set defaults
73 const page = query.page || 1;
74 const limit = Math.min(query.limit || 20, 100); // Cap at 100
75 const sortBy = query.sortBy || CollectionSortField.UPDATED_AT;
76 const sortOrder = query.sortOrder || SortOrder.DESC;
77
78 // Parse and validate curator identifier
79 const identifierResult = DIDOrHandle.create(query.curatorId);
80 if (identifierResult.isErr()) {
81 return err(new ValidationError('Invalid curator identifier'));
82 }
83
84 // Resolve to DID
85 const didResult = await this.identityResolver.resolveToDID(
86 identifierResult.value,
87 );
88 if (didResult.isErr()) {
89 return err(
90 new ValidationError(
91 `Could not resolve curator identifier: ${didResult.error.message}`,
92 ),
93 );
94 }
95
96 const resolvedDid = didResult.value.value;
97
98 try {
99 // Execute query to get raw collection data using the resolved DID
100 const result = await this.collectionQueryRepo.findByCreator(resolvedDid, {
101 page,
102 limit,
103 sortBy,
104 sortOrder,
105 searchText: query.searchText,
106 });
107
108 // Get user profile for the curator using the resolved DID
109 const profileResult = await this.profileService.getProfile(resolvedDid);
110
111 if (profileResult.isErr()) {
112 return err(
113 new Error(
114 `Failed to fetch user profile: ${profileResult.error instanceof Error ? profileResult.error.message : 'Unknown error'}`,
115 ),
116 );
117 }
118 const profile = profileResult.value;
119
120 // Transform raw data to enriched DTOs
121 const enrichedCollections: CollectionListItemDTO[] = result.items.map(
122 (item) => {
123 return {
124 id: item.id,
125 uri: item.uri,
126 name: item.name,
127 description: item.description,
128 updatedAt: item.updatedAt,
129 createdAt: item.createdAt,
130 cardCount: item.cardCount,
131 author: {
132 id: profile.id,
133 name: profile.name,
134 handle: profile.handle,
135 avatarUrl: profile.avatarUrl,
136 description: profile.bio,
137 },
138 };
139 },
140 );
141
142 return ok({
143 collections: enrichedCollections,
144 pagination: {
145 currentPage: page,
146 totalPages: Math.ceil(result.totalCount / limit),
147 totalCount: result.totalCount,
148 hasMore: page * limit < result.totalCount,
149 limit,
150 },
151 sorting: {
152 sortBy,
153 sortOrder,
154 },
155 });
156 } catch (error) {
157 return err(
158 new Error(
159 `Failed to retrieve collections: ${error instanceof Error ? error.message : 'Unknown error'}`,
160 ),
161 );
162 }
163 }
164}