From 17d4ae59270aa615ad912fc57490f177b880bf04 Mon Sep 17 00:00:00 2001 From: Toan Nguyen Date: Sat, 13 Feb 2021 14:04:23 +0700 Subject: [PATCH] feat: implement describeMedia method --- .../media/sponsored-brands-media-operation.ts | 20 +++++- src/operations/media/types.test.ts | 27 ++++++++ src/operations/media/types.ts | 61 +++++++++++++++++++ .../sponsored-brands-media-operation.test.ts | 38 ++++++++++++ 4 files changed, 145 insertions(+), 1 deletion(-) diff --git a/src/operations/media/sponsored-brands-media-operation.ts b/src/operations/media/sponsored-brands-media-operation.ts index 70edb0dd9..6c00e2037 100644 --- a/src/operations/media/sponsored-brands-media-operation.ts +++ b/src/operations/media/sponsored-brands-media-operation.ts @@ -1,5 +1,11 @@ import { Operation } from '../operation' -import { CompleteMediaParam, CreateUploadLocaltionParam, MediaId, UploadLocation } from './types' +import { + CompleteMediaParam, + CreateUploadLocaltionParam, + MediaId, + MediaResource, + UploadLocation, +} from './types' import { Decode } from '../../decorators' export class SponsoredBrandsMediaOperation extends Operation { @@ -30,4 +36,16 @@ export class SponsoredBrandsMediaOperation extends Operation { public completeMedia(param: CompleteMediaParam) { return this.client.put(`${this.resource}/complete`, param) } + + /** + * API to poll for media status. + * In order to attach media to campaign, media should be in either PendingDeepValidation or Available status. + * Available status guarantees that media has completed processing and published for usage. + * Though media can be attached to campaign once the status of the media transitions to PendingDeepValidation, media could still fail additional validation and transition to Failed status. + * For example in the context of SBV, SBV campaign can be created when status transitions to PendingDeepValidation, it could result in SBV campaign to be rejected later if media transitions to Failed status. + */ + @Decode(MediaResource) + public describeMedia(mediaId: MediaId) { + return this.client.get(this.paramsFilterTransformer('/describe', { mediaId })) + } } diff --git a/src/operations/media/types.test.ts b/src/operations/media/types.test.ts index 6e1bb37b5..1aa3e704e 100644 --- a/src/operations/media/types.test.ts +++ b/src/operations/media/types.test.ts @@ -52,3 +52,30 @@ describe('CompleteMediaParam', () => { expect(isRight(res)).toBeTruthy() }) }) + +describe('MediaResource', () => { + it('should pass', () => { + const res = t.MediaResource.decode({ + mediaId: 'string', + status: 'Processing', + statusMetadata: [ + { + code: 'string', + message: 'string', + }, + ], + publishedMediaUrl: 'string', + }) + + expect(isRight(res)).toBeTruthy() + }) + + it('should pass without optional paramaters', () => { + const res = t.MediaResource.decode({ + mediaId: 'string', + status: 'Processing', + }) + + expect(isRight(res)).toBeTruthy() + }) +}) diff --git a/src/operations/media/types.ts b/src/operations/media/types.ts index 3bdf3b110..267c33de4 100644 --- a/src/operations/media/types.ts +++ b/src/operations/media/types.ts @@ -34,3 +34,64 @@ export type CompleteMediaParam = t.TypeOf */ export const MediaId = t.string export type MediaId = t.TypeOf + +export const MediaStatus = t.union([ + /** + * The media is being processed. + */ + t.literal('Processing'), + + /** + * The media is pending additional validation carried out during media conversion. + */ + t.literal('PendingDeepValidation'), + + /** + * Media has successfully finished validation and conversion and the media is published. + */ + t.literal('Available'), + + /** + * Media processing failed. + */ + t.literal('Failed'), +]) +export type MediaStatus = t.TypeOf + +export const MediaStatusMetadata = t.type({ + code: t.string, + message: t.string, +}) +export type MediaStatusMetadata = t.TypeOf + +/** + * Media Resource. + */ +export const MediaResource = t.intersection([ + t.type({ + /** + * The Media identifier. + */ + mediaId: MediaId, + + /** + * Media status. + */ + status: MediaStatus, + }), + t.partial({ + /** + * Additional status metadata. + * It is only available when status is Failed and statusMetadata provides additional detail on why media status is Failed. + * statusMetadata is comprised of code and message. + */ + statusMetadata: t.array(MediaStatusMetadata), + + /** + * The preview URL of the media. + * It is only available when status is Available. + */ + publishedMediaUrl: t.string, + }), +]) +export type MediaResource = t.TypeOf diff --git a/test/operations/media/sponsored-brands-media-operation.test.ts b/test/operations/media/sponsored-brands-media-operation.test.ts index ed4d3b3de..85a5bdd6c 100644 --- a/test/operations/media/sponsored-brands-media-operation.test.ts +++ b/test/operations/media/sponsored-brands-media-operation.test.ts @@ -1,6 +1,7 @@ import { CompleteMediaParam, CreateUploadLocaltionParam, + MediaId, SponsoredBrandsMediaOperation, } from '../../../src' import { OperationProvider } from '../../../src/operations/operation-provider' @@ -44,4 +45,41 @@ describe('SponsoredBrandsMediaOperation', () => { expect(res).toBeDefined() }) }) + + /** + * TODO: Need check on Production API again. Sandbox API return an error: + * ResourceNotFoundError: Could not find resource for full path: https://advertising-api-test.amazon.com/v2/media/describe?mediaId=ABC + */ + describe.skip('describeMedia', () => { + it(`should retrieve media resource by media id`, async () => { + const mediaId: MediaId = 'ABC' + const res = await operation.describeMedia(mediaId) + + expect(res.mediaId).toBe(mediaId) + }) + + it(`should retrieve meta data when media status is failed `, async () => { + expect.assertions(2) + + const mediaId: MediaId = 'ABC' + const res = await operation.describeMedia(mediaId) + + expect(res.mediaId).toBe(mediaId) + if (res.status === 'Failed') { + expect(res).toHaveProperty('statusMetadata') + } + }) + + it(`should retrieve published media url when media status is available `, async () => { + expect.assertions(2) + + const mediaId: MediaId = 'ABC' + const res = await operation.describeMedia(mediaId) + + expect(res.mediaId).toBe(mediaId) + if (res.status === 'Available') { + expect(res).toHaveProperty('publishedMediaUrl') + } + }) + }) })