diff --git a/backend/src/config/test-mock.ts b/backend/src/config/test-mock.ts index e9bc4ece7..4c6509617 100644 --- a/backend/src/config/test-mock.ts +++ b/backend/src/config/test-mock.ts @@ -28,11 +28,11 @@ export const TEST_CONFIG: typeof CONFIG = { REDIS_PORT: undefined, REDIS_PASSWORD: undefined, - AWS_ACCESS_KEY_ID: '', - AWS_SECRET_ACCESS_KEY: '', - AWS_ENDPOINT: '', - AWS_REGION: '', - AWS_BUCKET: '', + AWS_ACCESS_KEY_ID: 'AWS_ACCESS_KEY_ID', + AWS_SECRET_ACCESS_KEY: 'AWS_SECRET_ACCESS_KEY', + AWS_ENDPOINT: 'AWS_ENDPOINT', + AWS_REGION: 'AWS_REGION', + AWS_BUCKET: 'AWS_BUCKET', S3_PUBLIC_GATEWAY: undefined, IMAGOR_SECRET: undefined, diff --git a/backend/src/graphql/resolvers/images.spec.ts b/backend/src/graphql/resolvers/images.spec.ts new file mode 100644 index 000000000..cb8661e41 --- /dev/null +++ b/backend/src/graphql/resolvers/images.spec.ts @@ -0,0 +1,36 @@ +import { TEST_CONFIG } from '@src/config/test-mock' + +import ImageResolver from './images' + +describe('Image', () => { + const { Image } = ImageResolver + const args = {} + const Location = + 'fsn1.your-objectstorage.com/ocelot-social-staging/original/f965ea15-1f6b-43aa-a535-927410e2585e-dsc02586.jpg' + const config = { + ...TEST_CONFIG, + AWS_ENDPOINT: 'https://fsn1.your-objectstorage.com', + S3_PUBLIC_GATEWAY: 'https://your-public-gateway.com', + IMAGOR_SECRET: 'IMAGOR_SECRET', + } + + describe('.url', () => { + it('replaces the internal domain of the S3 `Location` with a public domain', () => { + const expectedUrl = + 'https://your-public-gateway.com/iJ5iCYb-c6DnvQHTLrKcIlioWVk=/fsn1.your-objectstorage.com/ocelot-social-staging/original/f965ea15-1f6b-43aa-a535-927410e2585e-dsc02586.jpg' + expect(Image.url({ url: Location }, args, { config })).toEqual(expectedUrl) + }) + }) + + describe('.transform', () => { + describe('resize transformations', () => { + const args = { width: 320 } + + it('encodes `fit-in` imagor transformations in the URL', () => { + const expectedUrl = + 'https://your-public-gateway.com/gg1VO_owYoOkltsIPNNFV7JcuUE=/fit-in/320x5000/fsn1.your-objectstorage.com/ocelot-social-staging/original/f965ea15-1f6b-43aa-a535-927410e2585e-dsc02586.jpg' + expect(Image.transform({ url: Location }, args, { config })).toEqual(expectedUrl) + }) + }) + }) +}) diff --git a/backend/src/graphql/resolvers/images.ts b/backend/src/graphql/resolvers/images.ts index 46cfbc55a..ecdc6674e 100644 --- a/backend/src/graphql/resolvers/images.ts +++ b/backend/src/graphql/resolvers/images.ts @@ -9,27 +9,28 @@ type UrlResolver = ( args: { width?: number; height?: number }, { config: { S3_PUBLIC_GATEWAY }, - }: Context, + }: Pick, ) => string const changeDomain: (opts: { transformations: UrlResolver[] }) => UrlResolver = ({ transformations }) => - (parent, _args, context) => { + ({ url }, _args, context) => { const { config } = context const { S3_PUBLIC_GATEWAY, AWS_ENDPOINT } = config if (!(S3_PUBLIC_GATEWAY && AWS_ENDPOINT)) { - return parent.url + return url } - if (new URL(parent.url).host !== new URL(AWS_ENDPOINT).host) { + const originalUrl = new URL(url, AWS_ENDPOINT) // some S3 object storages return invalid URLs as location, so put the AWS_ENDPOINT as `base` + if (originalUrl.host !== new URL(AWS_ENDPOINT).host) { // In this case it's an external upload - maybe seeded? // Let's not change the URL in this case - return parent.url + return url } const publicUrl = new URL(S3_PUBLIC_GATEWAY) - publicUrl.pathname = new URL(parent.url).pathname - const url = publicUrl.href - return chain(...transformations)({ url }, _args, context) + publicUrl.pathname = originalUrl.pathname + const newUrl = publicUrl.href + return chain(...transformations)({ url: newUrl }, _args, context) } const sign: UrlResolver = ({ url }, _args, { config: { IMAGOR_SECRET } }) => {