This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

semble / src / modules / cards / tests / utils / FakeCollectionPublisher.ts
7.4 kB 233 lines
1import { ICollectionPublisher } from '../../application/ports/ICollectionPublisher'; 2import { Collection } from '../../domain/Collection'; 3import { Card } from '../../domain/Card'; 4import { PublishedRecordId } from '../../domain/value-objects/PublishedRecordId'; 5import { ok, err, Result } from '../../../../shared/core/Result'; 6import { UseCaseError } from '../../../../shared/core/UseCaseError'; 7import { AppError } from '../../../../shared/core/AppError'; 8import { CuratorId } from '../../domain/value-objects/CuratorId'; 9import { EnvironmentConfigService } from 'src/shared/infrastructure/config/EnvironmentConfigService'; 10 11export class FakeCollectionPublisher implements ICollectionPublisher { 12 private publishedCollections: Map<string, Collection> = new Map(); 13 private publishedLinks: Map< 14 string, 15 { cardId: string; linkRecord: PublishedRecordId }[] 16 > = new Map(); 17 private unpublishedCollections: Array<{ uri: string; cid: string }> = []; 18 private removedLinks: Array<{ cardId: string; collectionId: string }> = []; 19 private shouldFail: boolean = false; 20 private shouldFailUnpublish: boolean = false; 21 private collectionType = 22 new EnvironmentConfigService().getAtProtoCollections().collection; 23 24 private cardCollectionLinkType = 25 new EnvironmentConfigService().getAtProtoCollections().collectionLink; 26 27 async publish( 28 collection: Collection, 29 ): Promise<Result<PublishedRecordId, UseCaseError>> { 30 if (this.shouldFail) { 31 return err( 32 AppError.UnexpectedError.create( 33 new Error('Simulated collection publish failure'), 34 ), 35 ); 36 } 37 38 const collectionId = collection.collectionId.getStringValue(); 39 40 // Use the collection's author DID directly 41 const fakeDid = collection.authorId.value; 42 43 // Simulate publishing the collection record itself 44 const fakeCollectionUri = `at://${fakeDid}/${this.collectionType}/${collectionId}`; 45 const fakeCollectionCid = `fake-collection-cid-${collectionId}`; 46 47 const collectionRecord = PublishedRecordId.create({ 48 uri: fakeCollectionUri, 49 cid: fakeCollectionCid, 50 }); 51 52 // Store the published collection for inspection 53 this.publishedCollections.set(collectionId, collection); 54 55 console.log( 56 `[FakeCollectionPublisher] Published collection ${collectionId}`, 57 ); 58 59 return ok(collectionRecord); 60 } 61 62 async publishCardAddedToCollection( 63 card: Card, 64 collection: Collection, 65 curatorId: CuratorId, 66 ): Promise<Result<PublishedRecordId, UseCaseError>> { 67 if (this.shouldFail) { 68 return err( 69 AppError.UnexpectedError.create( 70 new Error('Simulated card-collection link publish failure'), 71 ), 72 ); 73 } 74 75 const collectionId = collection.collectionId.getStringValue(); 76 const cardId = card.cardId.getStringValue(); 77 78 // Simulate publishing a card-collection link 79 const fakeLinkUri = `at://${curatorId.value}/${this.cardCollectionLinkType}/${collectionId}-${cardId}`; 80 const fakeLinkCid = `fake-link-cid-${collectionId}-${cardId}`; 81 82 const linkRecord = PublishedRecordId.create({ 83 uri: fakeLinkUri, 84 cid: fakeLinkCid, 85 }); 86 87 // Store published link for inspection 88 const existingLinks = this.publishedLinks.get(collectionId) || []; 89 existingLinks.push({ 90 cardId, 91 linkRecord, 92 }); 93 this.publishedLinks.set(collectionId, existingLinks); 94 95 console.log( 96 `[FakeCollectionPublisher] Published card ${cardId} added to collection ${collectionId} link at ${fakeLinkUri}`, 97 ); 98 99 return ok(linkRecord); 100 } 101 102 async unpublishCardAddedToCollection( 103 recordId: PublishedRecordId, 104 ): Promise<Result<void, UseCaseError>> { 105 if (this.shouldFailUnpublish) { 106 return err( 107 AppError.UnexpectedError.create( 108 new Error('Simulated card-collection link unpublish failure'), 109 ), 110 ); 111 } 112 113 // Find and remove the link by its published record ID 114 for (const [collectionId, links] of this.publishedLinks.entries()) { 115 const linkIndex = links.findIndex( 116 (link) => link.linkRecord.uri === recordId.uri, 117 ); 118 if (linkIndex !== -1) { 119 const removedLink = links.splice(linkIndex, 1)[0]; 120 this.removedLinks.push({ 121 cardId: removedLink!.cardId, 122 collectionId, 123 }); 124 console.log( 125 `[FakeCollectionPublisher] Unpublished card-collection link ${recordId.uri}`, 126 ); 127 return ok(undefined); 128 } 129 } 130 131 console.warn( 132 `[FakeCollectionPublisher] Card-collection link not found for unpublishing: ${recordId.uri}`, 133 ); 134 return ok(undefined); 135 } 136 137 async unpublish( 138 recordId: PublishedRecordId, 139 ): Promise<Result<void, UseCaseError>> { 140 if (this.shouldFailUnpublish) { 141 return err( 142 AppError.UnexpectedError.create( 143 new Error('Simulated collection unpublish failure'), 144 ), 145 ); 146 } 147 148 // Find and remove the collection by its published record ID 149 for (const [ 150 collectionId, 151 collection, 152 ] of this.publishedCollections.entries()) { 153 if (collection.publishedRecordId?.uri === recordId.uri) { 154 this.publishedCollections.delete(collectionId); 155 this.publishedLinks.delete(collectionId); 156 this.unpublishedCollections.push({ 157 uri: recordId.uri, 158 cid: recordId.cid, 159 }); 160 console.log( 161 `[FakeCollectionPublisher] Unpublished collection ${recordId.uri}`, 162 ); 163 return ok(undefined); 164 } 165 } 166 if (this.publishedCollections.size === 0) { 167 this.unpublishedCollections.push({ 168 uri: recordId.uri, 169 cid: recordId.cid, 170 }); 171 console.log( 172 `[FakeCollectionPublisher] Unpublished collection ${recordId.uri} (not found in published collections)`, 173 ); 174 return ok(undefined); 175 } 176 177 console.warn( 178 `[FakeCollectionPublisher] Collection not found for unpublishing: ${recordId.uri}`, 179 ); 180 return ok(undefined); 181 } 182 183 setShouldFail(shouldFail: boolean): void { 184 this.shouldFail = shouldFail; 185 } 186 187 setShouldFailUnpublish(shouldFailUnpublish: boolean): void { 188 this.shouldFailUnpublish = shouldFailUnpublish; 189 } 190 191 clear(): void { 192 this.publishedCollections.clear(); 193 this.publishedLinks.clear(); 194 this.unpublishedCollections = []; 195 this.removedLinks = []; 196 this.shouldFail = false; 197 this.shouldFailUnpublish = false; 198 } 199 200 getPublishedCollections(): Collection[] { 201 return Array.from(this.publishedCollections.values()); 202 } 203 204 getPublishedLinksForCollection( 205 collectionId: string, 206 ): Array<{ cardId: string; linkRecord: PublishedRecordId }> { 207 return this.publishedLinks.get(collectionId) || []; 208 } 209 210 getUnpublishedCollections(): Array<{ uri: string; cid: string }> { 211 return this.unpublishedCollections; 212 } 213 214 getRemovedLinksForCollection( 215 collectionId: string, 216 ): Array<{ cardId: string; collectionId: string }> { 217 return this.removedLinks.filter( 218 (link) => link.collectionId === collectionId, 219 ); 220 } 221 222 getAllRemovedLinks(): Array<{ cardId: string; collectionId: string }> { 223 return this.removedLinks; 224 } 225 getAllPublishedLinks() { 226 const allLinks: Array<{ cardId: string; linkRecord: PublishedRecordId }> = 227 []; 228 for (const links of this.publishedLinks.values()) { 229 allLinks.push(...links); 230 } 231 return allLinks; 232 } 233}