diff --git a/docs/pages/packages/moments.mdx b/docs/pages/packages/moments.mdx index c059c41d..8db96f12 100644 --- a/docs/pages/packages/moments.mdx +++ b/docs/pages/packages/moments.mdx @@ -7,6 +7,7 @@ ## Features - Create a Moment attached to a Drop or a specific POAP +- Update a Moment - Fetch multiple Moments - Fetch a single Moment diff --git a/examples/moments/backend/src/index.ts b/examples/moments/backend/src/index.ts index c27ef3c3..b972bf81 100644 --- a/examples/moments/backend/src/index.ts +++ b/examples/moments/backend/src/index.ts @@ -5,6 +5,7 @@ import { AuthenticationProviderHttp, } from '@poap-xyz/providers'; import { create_moment } from './methods/create_moment'; +import { patch_moment } from './methods/patch_moment'; import { fetch_multiple_moments } from './methods/fetch_multiple_moments'; import { fetch_single_moment } from './methods/fetch_single_moment'; import { fetch_moments_by_drop_ids } from './methods/fetch_moments_by_drop_ids'; @@ -38,6 +39,8 @@ async function main(): Promise { await fetch_single_moment(client); // Fetch moments by drop ids await fetch_moments_by_drop_ids(client); + // Patch Moment + await patch_moment(client); } main().catch(() => { diff --git a/examples/moments/backend/src/methods/patch_moment.ts b/examples/moments/backend/src/methods/patch_moment.ts new file mode 100644 index 00000000..e568d00b --- /dev/null +++ b/examples/moments/backend/src/methods/patch_moment.ts @@ -0,0 +1,15 @@ +import { MomentsClient, PatchMomentInput } from '@poap-xyz/moments'; + +export const patch_moment = async (client: MomentsClient): Promise => { + const momentId = "b08fad41-7154-499f-88f9-abea66ceab48" + const input: PatchMomentInput = { + cid: "0001-7ce5368171cc3d988157d7dab3d313d7bd43de3e-365e5b83699adce0825021d011f1bf73bd5ef9369d06e49645afbea2ef34f54e0557c1d4742c8bd6d1f7a02be4aa483c03888af0aa143d5aa7351e2baaf931231c.moment", + }; + + try { + await client.patchMoment(momentId, input); + console.log('Patch successful'); + } catch (error) { + console.log(error); + } +}; diff --git a/packages/drops/package.json b/packages/drops/package.json index 4b8e744b..08aa28f3 100644 --- a/packages/drops/package.json +++ b/packages/drops/package.json @@ -1,6 +1,6 @@ { "name": "@poap-xyz/drops", - "version": "0.2.6", + "version": "0.2.7", "description": "Drops module for the poap.js library", "main": "dist/cjs/index.cjs", "module": "dist/esm/index.mjs", @@ -29,7 +29,7 @@ "node": ">=18" }, "dependencies": { - "@poap-xyz/providers": "0.2.6", - "@poap-xyz/utils": "0.2.6" + "@poap-xyz/providers": "0.2.7", + "@poap-xyz/utils": "0.2.7" } } diff --git a/packages/moments/package.json b/packages/moments/package.json index 3ccc864d..0b77c5e6 100644 --- a/packages/moments/package.json +++ b/packages/moments/package.json @@ -1,6 +1,6 @@ { "name": "@poap-xyz/moments", - "version": "0.2.6", + "version": "0.2.7", "description": "Moments module for the poap.js library", "main": "dist/cjs/index.cjs", "module": "dist/esm/index.mjs", @@ -26,8 +26,8 @@ "build": "rollup -c --bundleConfigAsCjs" }, "dependencies": { - "@poap-xyz/providers": "0.2.6", - "@poap-xyz/utils": "0.2.6", + "@poap-xyz/providers": "0.2.7", + "@poap-xyz/utils": "0.2.7", "uuid": "^9.0.0" }, "engines": { diff --git a/packages/moments/src/client/MomentsClient.spec.ts b/packages/moments/src/client/MomentsClient.spec.ts index 5835f527..b65a820a 100644 --- a/packages/moments/src/client/MomentsClient.spec.ts +++ b/packages/moments/src/client/MomentsClient.spec.ts @@ -4,6 +4,7 @@ import { MomentsClient } from './MomentsClient'; import { CreateMomentInput } from './dtos/create/CreateInput'; import { CreateSteps } from './dtos/create/CreateSteps'; import { v4 } from 'uuid'; +import { PatchMomentInput } from './dtos/patch/PatchInput'; describe('MomentsClient', () => { const MOMENT_ID = 'this-is-a-moment-id'; @@ -16,6 +17,8 @@ describe('MomentsClient', () => { const FILE_2_TYPE = 'image/jpeg'; const MEDIA_UPLOAD_URL = 'this-is-a-media-upload-url'; const DESCRIPTION = 'This is a description'; + const MOMENT_CID = + '0001-7ce5368171cc3d988157d7dab3d313d7bd43de3e-365e5b83699adce0825021d011f1bf73bd5ef9369d06e49645afbea2ef34f54e0557c1d4742c8bd6d1f7a02be4aa483c03888af0aa143d5aa7351e2baaf931231c.moment'; const MEDIAS_TO_CREATE = [ { fileBinary: FILE_1, @@ -108,4 +111,25 @@ describe('MomentsClient', () => { expect(onStepUpdate).toHaveBeenCalledTimes(4); }); }); + describe('updateMoment', () => { + it('should update a moment', async () => { + // GIVEN + const client = new MomentsClient( + poapMomentsAPIMocked, + compassProviderMocked, + ); + const input: PatchMomentInput = { + cid: MOMENT_CID, + }; + poapMomentsAPIMocked.patchMoment.mockResolvedValue(); + + // WHEN + await client.patchMoment(MOMENT_ID, input); + + // THEN + expect(poapMomentsAPIMocked.patchMoment).toHaveBeenCalledWith(MOMENT_ID, { + cid: MOMENT_CID, + }); + }); + }); }); diff --git a/packages/moments/src/client/MomentsClient.ts b/packages/moments/src/client/MomentsClient.ts index 69b57081..6dcbb772 100644 --- a/packages/moments/src/client/MomentsClient.ts +++ b/packages/moments/src/client/MomentsClient.ts @@ -22,6 +22,7 @@ import { MomentsSortFields, } from './dtos/fetch/FetchMomentsInput'; import { CreateMedia } from './dtos/create/CreateMedia'; +import { PatchMomentInput } from './dtos/patch/PatchInput'; export class MomentsClient { constructor( @@ -65,6 +66,7 @@ export class MomentsClient { response.dropId, response.tokenId, response.description, + response.cid, ); } @@ -196,6 +198,10 @@ export class MomentsClient { return result; } + public async patchMoment(id: string, input: PatchMomentInput): Promise { + await this.poapMomentsApi.patchMoment(id, input); + } + private getMomentFromMomentResponse(momentResponse: MomentResponse): Moment { return new Moment( momentResponse.id, @@ -204,6 +210,7 @@ export class MomentsClient { momentResponse.drop_id, momentResponse.token_id, momentResponse.description, + momentResponse.cid, ); } } diff --git a/packages/moments/src/client/dtos/patch/PatchInput.ts b/packages/moments/src/client/dtos/patch/PatchInput.ts new file mode 100644 index 00000000..8f19df6f --- /dev/null +++ b/packages/moments/src/client/dtos/patch/PatchInput.ts @@ -0,0 +1,8 @@ +/** + * Interface representing the input needed to patch a moment. + * @interface + * @property {string} cid - The cid of the moment in Registry. + */ +export interface PatchMomentInput { + cid?: string; +} diff --git a/packages/moments/src/domain/Moment.ts b/packages/moments/src/domain/Moment.ts index 7fd3fd14..37dede43 100644 --- a/packages/moments/src/domain/Moment.ts +++ b/packages/moments/src/domain/Moment.ts @@ -32,6 +32,11 @@ export class Moment { */ public readonly description?: string; + /** + * The cid of the moment in Registry + */ + public readonly cid?: string; + constructor( id: string, author: string, @@ -39,6 +44,7 @@ export class Moment { dropId: number, tokenId?: number, description?: string, + cid?: string, ) { this.id = id; this.author = author; @@ -46,5 +52,6 @@ export class Moment { this.dropId = dropId; this.tokenId = tokenId; this.description = description; + this.cid = cid; } } diff --git a/packages/moments/src/index.ts b/packages/moments/src/index.ts index 8ae5db7b..0acc1e49 100644 --- a/packages/moments/src/index.ts +++ b/packages/moments/src/index.ts @@ -1,6 +1,7 @@ export { Moment } from './domain/Moment'; export { MomentsClient } from './client/MomentsClient'; export { CreateMomentInput } from './client/dtos/create/CreateInput'; +export { PatchMomentInput } from './client/dtos/patch/PatchInput'; export { CreateSteps } from './client/dtos/create/CreateSteps'; export { FetchMomentsInput } from './client/dtos/fetch/FetchMomentsInput'; export { MomentsClientFactory } from './client/MomentsClientFactory/MomentsClientFactory'; diff --git a/packages/moments/src/queries/PaginatedMoments.ts b/packages/moments/src/queries/PaginatedMoments.ts index 1c2b8066..4269bf13 100644 --- a/packages/moments/src/queries/PaginatedMoments.ts +++ b/packages/moments/src/queries/PaginatedMoments.ts @@ -16,10 +16,9 @@ export const PAGINATED_MOMENTS_QUERY = ` created_on drop_id id - gateways - media_key token_id description + cid } } `; @@ -29,10 +28,9 @@ export interface MomentResponse { created_on: string; drop_id: number; id: string; - gateways: string[]; - media_key: string; token_id: number; description?: string; + cid?: string; } export interface MomentsQueryResponse { diff --git a/packages/poaps/package.json b/packages/poaps/package.json index 26e09c91..146bcea5 100644 --- a/packages/poaps/package.json +++ b/packages/poaps/package.json @@ -1,6 +1,6 @@ { "name": "@poap-xyz/poaps", - "version": "0.2.6", + "version": "0.2.7", "description": "Poaps module for the poap.js library", "main": "dist/cjs/index.cjs", "module": "dist/esm/index.mjs", @@ -26,8 +26,8 @@ "build": "rollup -c --bundleConfigAsCjs" }, "dependencies": { - "@poap-xyz/providers": "0.2.6", - "@poap-xyz/utils": "0.2.6" + "@poap-xyz/providers": "0.2.7", + "@poap-xyz/utils": "0.2.7" }, "engines": { "node": ">=18" diff --git a/packages/providers/package.json b/packages/providers/package.json index 37aff9a1..b276748f 100644 --- a/packages/providers/package.json +++ b/packages/providers/package.json @@ -1,6 +1,6 @@ { "name": "@poap-xyz/providers", - "version": "0.2.6", + "version": "0.2.7", "description": "Providers module for the poap.js library", "main": "dist/cjs/index.cjs", "module": "dist/esm/index.mjs", @@ -26,7 +26,7 @@ "build": "rollup -c --bundleConfigAsCjs" }, "dependencies": { - "@poap-xyz/utils": "0.2.6", + "@poap-xyz/utils": "0.2.7", "axios": "^1.3.5", "lodash.chunk": "^4.2.0" }, diff --git a/packages/providers/src/core/PoapMomentsApi/PoapMomentsApi.ts b/packages/providers/src/core/PoapMomentsApi/PoapMomentsApi.ts index 6db77867..3fe8fb01 100644 --- a/packages/providers/src/core/PoapMomentsApi/PoapMomentsApi.ts +++ b/packages/providers/src/core/PoapMomentsApi/PoapMomentsApi.ts @@ -2,6 +2,7 @@ import axios, { AxiosError } from 'axios'; import { InvalidMediaError } from '../../ports/MomentsApiProvider/errors/InvalidMediaError'; import { CreateMomentResponse } from '../../ports/MomentsApiProvider/types/CreateMomentResponse'; import { CreateMomentInput } from '../../ports/MomentsApiProvider/types/CreateMomentInput'; +import { PatchMomentInput } from '../../ports/MomentsApiProvider/types/PatchMomentInput'; import { MomentsApiProvider } from '../../ports/MomentsApiProvider/MomentsApiProvider'; import { AuthenticationProvider } from '../../ports/AuthenticationProvider/AuthenticationProvider'; import { MediaStatus } from '../../ports/MomentsApiProvider/types/MediaStatus'; @@ -164,6 +165,22 @@ export class PoapMomentsApi implements MomentsApiProvider { } } + /** + * Update a moment using the provided input + * @param {string} id - The moment id + * @param {PatchMomentInput} input - The input for updating a moment + */ + public async patchMoment(id: string, input: PatchMomentInput): Promise { + await fetch(`${this.baseUrl}/moments/${id}`, { + method: 'PATCH', + body: JSON.stringify(input), + headers: { + 'Content-Type': 'application/json', + Authorization: await this.getAuthorizationToken(), + }, + }); + } + private async getAuthorizationToken(): Promise { if (!this.authenticationProvider) { throw new Error( diff --git a/packages/providers/src/ports/MomentsApiProvider/MomentsApiProvider.ts b/packages/providers/src/ports/MomentsApiProvider/MomentsApiProvider.ts index 039e4cb5..d6f213af 100644 --- a/packages/providers/src/ports/MomentsApiProvider/MomentsApiProvider.ts +++ b/packages/providers/src/ports/MomentsApiProvider/MomentsApiProvider.ts @@ -1,5 +1,6 @@ import { CreateMomentInput } from './types/CreateMomentInput'; import { CreateMomentResponse } from './types/CreateMomentResponse'; +import { PatchMomentInput } from './types/PatchMomentInput'; import { MediaStatus } from './types/MediaStatus'; /** @@ -55,4 +56,14 @@ export interface MomentsApiProvider { * @returns {Promise} - A Promise that resolves with the media processing status */ fetchMediaStatus(mediaKey: string): Promise; + + /** + * Updates a moment on the API. + * @async + * @function + * @name MomentsApiProvider#patchMoment + * @param {string} id - The Moment id. + * @param {PatchMomentInput} input - The input data for updating a moment. + */ + patchMoment(id: string, input: PatchMomentInput): Promise; } diff --git a/packages/providers/src/ports/MomentsApiProvider/types/CreateMomentResponse.ts b/packages/providers/src/ports/MomentsApiProvider/types/CreateMomentResponse.ts index d8f602bf..432550e8 100644 --- a/packages/providers/src/ports/MomentsApiProvider/types/CreateMomentResponse.ts +++ b/packages/providers/src/ports/MomentsApiProvider/types/CreateMomentResponse.ts @@ -25,4 +25,9 @@ export interface CreateMomentResponse { * The description of the moment. */ description?: string; + + /** + * The cid of the moment in Registry. + */ + cid?: string; } diff --git a/packages/providers/src/ports/MomentsApiProvider/types/PatchMomentInput.ts b/packages/providers/src/ports/MomentsApiProvider/types/PatchMomentInput.ts new file mode 100644 index 00000000..aa28d405 --- /dev/null +++ b/packages/providers/src/ports/MomentsApiProvider/types/PatchMomentInput.ts @@ -0,0 +1,10 @@ +/** + * Object describing the input required to update a Moment. + * @typedef {Object} PatchMomentInput + * @property {string} cid - The cid of the moment in Registry under the format: + * {--.} allows you to fetch and verify the + * content of the moment in Registry. + */ +export interface PatchMomentInput { + cid?: string; +} diff --git a/packages/providers/test/PoapMomentsApi.spec.ts b/packages/providers/test/PoapMomentsApi.spec.ts index 4716623b..6c87c167 100644 --- a/packages/providers/test/PoapMomentsApi.spec.ts +++ b/packages/providers/test/PoapMomentsApi.spec.ts @@ -6,6 +6,9 @@ import { InvalidMediaError } from '../src/ports/MomentsApiProvider/errors/Invali import { mock, MockProxy } from 'jest-mock-extended'; import { MediaStatus } from '../src/ports/MomentsApiProvider/types/MediaStatus'; import { CreateMomentInput } from '../src/ports/MomentsApiProvider/types/CreateMomentInput'; +import { enableFetchMocks } from 'jest-fetch-mock'; + +enableFetchMocks(); describe('PoapMomentsApi', () => { const BASE_URL = 'https://moments.test'; @@ -131,4 +134,41 @@ describe('PoapMomentsApi', () => { await expect(api.createMoment(createMomentInput)).rejects.toThrow(); }); }); + + describe('patchMoment', () => { + const id = '1'; + const patchMomentInput = { + cid: '0001-7ce5368171cc3d988157d7dab3d313d7bd43de3e-365e5b83699adce0825021d011f1bf73bd5ef9369d06e49645afbea2ef34f54e0557c1d4742c8bd6d1f7a02be4aa483c03888af0aa143d5aa7351e2baaf931231c.moment', + }; + + it('should call fetch with correct parameters for PATCH request', async () => { + fetchMock.mockOnce(() => + Promise.resolve({ + ok: true, + status: 200, + body: JSON.stringify({}), + }), + ); + + const result = await api.patchMoment(id, patchMomentInput); + + expect(result).toBe(undefined); + expect(fetch).toHaveBeenCalledWith( + `${BASE_URL}/moments/${id}`, + { + method: 'PATCH', + body: JSON.stringify(patchMomentInput), + headers: { + 'Content-Type': 'application/json', + Authorization: expect.any(String), + }, + } + ); + }); + + it('should throw error when AuthenticationProvider is not provided', async () => { + api = new PoapMomentsApi({}); + await expect(api.patchMoment(id, patchMomentInput)).rejects.toThrow(); + }); + }); }); diff --git a/packages/utils/package.json b/packages/utils/package.json index d1ff7554..dafaf3ae 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@poap-xyz/utils", - "version": "0.2.6", + "version": "0.2.7", "description": "Utils module for the poap.js library", "main": "dist/cjs/index.cjs", "module": "dist/esm/index.mjs", diff --git a/yarn.lock b/yarn.lock index 5dff79bc..137bc9eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -884,8 +884,8 @@ __metadata: version: 0.0.0-use.local resolution: "@poap-xyz/drops@workspace:packages/drops" dependencies: - "@poap-xyz/providers": 0.2.6 - "@poap-xyz/utils": 0.2.6 + "@poap-xyz/providers": 0.2.7 + "@poap-xyz/utils": 0.2.7 languageName: unknown linkType: soft @@ -901,8 +901,8 @@ __metadata: version: 0.0.0-use.local resolution: "@poap-xyz/moments@workspace:packages/moments" dependencies: - "@poap-xyz/providers": 0.2.6 - "@poap-xyz/utils": 0.2.6 + "@poap-xyz/providers": 0.2.7 + "@poap-xyz/utils": 0.2.7 "@types/uuid": ^9.0.2 uuid: ^9.0.0 languageName: unknown @@ -912,16 +912,16 @@ __metadata: version: 0.0.0-use.local resolution: "@poap-xyz/poaps@workspace:packages/poaps" dependencies: - "@poap-xyz/providers": 0.2.6 - "@poap-xyz/utils": 0.2.6 + "@poap-xyz/providers": 0.2.7 + "@poap-xyz/utils": 0.2.7 languageName: unknown linkType: soft -"@poap-xyz/providers@*, @poap-xyz/providers@0.2.6, @poap-xyz/providers@workspace:packages/providers": +"@poap-xyz/providers@*, @poap-xyz/providers@0.2.7, @poap-xyz/providers@workspace:packages/providers": version: 0.0.0-use.local resolution: "@poap-xyz/providers@workspace:packages/providers" dependencies: - "@poap-xyz/utils": 0.2.6 + "@poap-xyz/utils": 0.2.7 axios: ^1.3.5 axios-mock-adapter: ^1.21.4 jest-fetch-mock: ^3.0.3 @@ -929,7 +929,7 @@ __metadata: languageName: unknown linkType: soft -"@poap-xyz/utils@*, @poap-xyz/utils@0.2.6, @poap-xyz/utils@workspace:packages/utils": +"@poap-xyz/utils@*, @poap-xyz/utils@0.2.7, @poap-xyz/utils@workspace:packages/utils": version: 0.0.0-use.local resolution: "@poap-xyz/utils@workspace:packages/utils" languageName: unknown