Skip to content

Commit

Permalink
feat(core): Pass RequestContext to AssetNamingStrategy functions
Browse files Browse the repository at this point in the history
BREAKING CHANGE: The AssetNamingStrategy `generateSourceFileName()` & `generatePreviewFileName()`
function signatures have changed: the first argument is now the
RequestContext of the current request.
  • Loading branch information
michaelbromley committed Oct 27, 2020
1 parent a46ea5d commit 48ae372
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 39 deletions.
19 changes: 10 additions & 9 deletions packages/asset-server-plugin/src/hashed-asset-naming-strategy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DefaultAssetNamingStrategy } from '@vendure/core';
import { DefaultAssetNamingStrategy, RequestContext } from '@vendure/core';
import { createHash } from 'crypto';
import path from 'path';

Expand All @@ -18,19 +18,20 @@ import path from 'path';
* @docsCategory AssetServerPlugin
*/
export class HashedAssetNamingStrategy extends DefaultAssetNamingStrategy {
generateSourceFileName(originalFileName: string, conflictFileName?: string): string {
const filename = super.generateSourceFileName(originalFileName, conflictFileName);
generateSourceFileName(ctx: RequestContext, originalFileName: string, conflictFileName?: string): string {
const filename = super.generateSourceFileName(ctx, originalFileName, conflictFileName);
return path.join('source', this.getHashedDir(filename), filename);
}
generatePreviewFileName(originalFileName: string, conflictFileName?: string): string {
const filename = super.generatePreviewFileName(originalFileName, conflictFileName);
generatePreviewFileName(
ctx: RequestContext,
originalFileName: string,
conflictFileName?: string,
): string {
const filename = super.generatePreviewFileName(ctx, originalFileName, conflictFileName);
return path.join('preview', this.getHashedDir(filename), filename);
}

private getHashedDir(filename: string): string {
return createHash('md5')
.update(filename)
.digest('hex')
.slice(0, 2);
return createHash('md5').update(filename).digest('hex').slice(0, 2);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { RequestContext } from '../../api/common/request-context';
import { InjectableStrategy } from '../../common/types/injectable-strategy';

/**
Expand All @@ -19,7 +20,7 @@ export interface AssetNamingStrategy extends InjectableStrategy {
* file name should then be generated. This process will repeat until a unique file name has
* been returned.
*/
generateSourceFileName(originalFileName: string, conflictFileName?: string): string;
generateSourceFileName(ctx: RequestContext, originalFileName: string, conflictFileName?: string): string;

/**
* @description
Expand All @@ -28,5 +29,5 @@ export interface AssetNamingStrategy extends InjectableStrategy {
*
* The same mechanism of checking for conflicts is used as described above.
*/
generatePreviewFileName(sourceFileName: string, conflictFileName?: string): string;
generatePreviewFileName(ctx: RequestContext, sourceFileName: string, conflictFileName?: string): string;
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,39 @@
import { RequestContext } from '../../api/common/request-context';

import { DefaultAssetNamingStrategy } from './default-asset-naming-strategy';

describe('DefaultAssetNamingStrategy', () => {
const ctx = RequestContext.empty();

describe('generateSourceFileName()', () => {
it('normalizes file names', () => {
const strategy = new DefaultAssetNamingStrategy();

expect(strategy.generateSourceFileName('foo.jpg')).toBe('foo.jpg');
expect(strategy.generateSourceFileName('curaçao.jpg')).toBe('curacao.jpg');
expect(strategy.generateSourceFileName('dấu hỏi.jpg')).toBe('dau-hoi.jpg');
expect(strategy.generateSourceFileName(ctx, 'foo.jpg')).toBe('foo.jpg');
expect(strategy.generateSourceFileName(ctx, 'curaçao.jpg')).toBe('curacao.jpg');
expect(strategy.generateSourceFileName(ctx, 'dấu hỏi.jpg')).toBe('dau-hoi.jpg');
});

it('increments conflicting file names', () => {
const strategy = new DefaultAssetNamingStrategy();

expect(strategy.generateSourceFileName('foo.jpg', 'foo.jpg')).toBe('foo__02.jpg');
expect(strategy.generateSourceFileName('foo.jpg', 'foo__02.jpg')).toBe('foo__03.jpg');
expect(strategy.generateSourceFileName('foo.jpg', 'foo__09.jpg')).toBe('foo__10.jpg');
expect(strategy.generateSourceFileName('foo.jpg', 'foo__99.jpg')).toBe('foo__100.jpg');
expect(strategy.generateSourceFileName('foo.jpg', 'foo__999.jpg')).toBe('foo__1000.jpg');
expect(strategy.generateSourceFileName(ctx, 'foo.jpg', 'foo.jpg')).toBe('foo__02.jpg');
expect(strategy.generateSourceFileName(ctx, 'foo.jpg', 'foo__02.jpg')).toBe('foo__03.jpg');
expect(strategy.generateSourceFileName(ctx, 'foo.jpg', 'foo__09.jpg')).toBe('foo__10.jpg');
expect(strategy.generateSourceFileName(ctx, 'foo.jpg', 'foo__99.jpg')).toBe('foo__100.jpg');
expect(strategy.generateSourceFileName(ctx, 'foo.jpg', 'foo__999.jpg')).toBe('foo__1000.jpg');
});

it('increments conflicting file names with no extension', () => {
const strategy = new DefaultAssetNamingStrategy();

expect(strategy.generateSourceFileName('ext45000000000505', 'ext45000000000505')).toBe(
expect(strategy.generateSourceFileName(ctx, 'ext45000000000505', 'ext45000000000505')).toBe(
'ext45000000000505__02',
);
expect(strategy.generateSourceFileName('ext45000000000505', 'ext45000000000505__02')).toBe(
expect(strategy.generateSourceFileName(ctx, 'ext45000000000505', 'ext45000000000505__02')).toBe(
'ext45000000000505__03',
);
expect(strategy.generateSourceFileName('ext45000000000505', 'ext45000000000505__09')).toBe(
expect(strategy.generateSourceFileName(ctx, 'ext45000000000505', 'ext45000000000505__09')).toBe(
'ext45000000000505__10',
);
});
Expand All @@ -39,25 +43,25 @@ describe('DefaultAssetNamingStrategy', () => {
it('adds the preview suffix', () => {
const strategy = new DefaultAssetNamingStrategy();

expect(strategy.generatePreviewFileName('foo.jpg')).toBe('foo__preview.jpg');
expect(strategy.generatePreviewFileName(ctx, 'foo.jpg')).toBe('foo__preview.jpg');
});

it('preserves the extension of supported image files', () => {
const strategy = new DefaultAssetNamingStrategy();

expect(strategy.generatePreviewFileName('foo.jpg')).toBe('foo__preview.jpg');
expect(strategy.generatePreviewFileName('foo.jpeg')).toBe('foo__preview.jpeg');
expect(strategy.generatePreviewFileName('foo.png')).toBe('foo__preview.png');
expect(strategy.generatePreviewFileName('foo.webp')).toBe('foo__preview.webp');
expect(strategy.generatePreviewFileName('foo.tiff')).toBe('foo__preview.tiff');
expect(strategy.generatePreviewFileName(ctx, 'foo.jpg')).toBe('foo__preview.jpg');
expect(strategy.generatePreviewFileName(ctx, 'foo.jpeg')).toBe('foo__preview.jpeg');
expect(strategy.generatePreviewFileName(ctx, 'foo.png')).toBe('foo__preview.png');
expect(strategy.generatePreviewFileName(ctx, 'foo.webp')).toBe('foo__preview.webp');
expect(strategy.generatePreviewFileName(ctx, 'foo.tiff')).toBe('foo__preview.tiff');
});

it('adds a png extension for unsupported images and other files', () => {
const strategy = new DefaultAssetNamingStrategy();

expect(strategy.generatePreviewFileName('foo.svg')).toBe('foo__preview.svg.png');
expect(strategy.generatePreviewFileName('foo.gif')).toBe('foo__preview.gif.png');
expect(strategy.generatePreviewFileName('foo.pdf')).toBe('foo__preview.pdf.png');
expect(strategy.generatePreviewFileName(ctx, 'foo.svg')).toBe('foo__preview.svg.png');
expect(strategy.generatePreviewFileName(ctx, 'foo.gif')).toBe('foo__preview.gif.png');
expect(strategy.generatePreviewFileName(ctx, 'foo.pdf')).toBe('foo__preview.pdf.png');
});
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { normalizeString } from '@vendure/common/lib/normalize-string';
import path from 'path';

import { RequestContext } from '../../api/common/request-context';

import { AssetNamingStrategy } from './asset-naming-strategy';

/**
Expand All @@ -13,7 +15,7 @@ import { AssetNamingStrategy } from './asset-naming-strategy';
export class DefaultAssetNamingStrategy implements AssetNamingStrategy {
private readonly numberingRe = /__(\d+)(\.[^.]+)?$/;

generateSourceFileName(originalFileName: string, conflictFileName?: string): string {
generateSourceFileName(ctx: RequestContext, originalFileName: string, conflictFileName?: string): string {
const normalized = normalizeString(originalFileName, '-');
if (!conflictFileName) {
return normalized;
Expand All @@ -22,7 +24,7 @@ export class DefaultAssetNamingStrategy implements AssetNamingStrategy {
}
}

generatePreviewFileName(sourceFileName: string, conflictFileName?: string): string {
generatePreviewFileName(ctx: RequestContext, sourceFileName: string, conflictFileName?: string): string {
const previewSuffix = '__preview';
const previewFileName = this.isSupportedImageFormat(sourceFileName)
? this.addSuffix(sourceFileName, previewSuffix)
Expand Down
12 changes: 6 additions & 6 deletions packages/core/src/service/services/asset.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ export class AssetService {
return new MimeTypeError(filename, mimetype);
}
const { assetPreviewStrategy, assetStorageStrategy } = assetOptions;
const sourceFileName = await this.getSourceFileName(filename);
const previewFileName = await this.getPreviewFileName(sourceFileName);
const sourceFileName = await this.getSourceFileName(ctx, filename);
const previewFileName = await this.getPreviewFileName(ctx, sourceFileName);

const sourceFileIdentifier = await assetStorageStrategy.writeFileFromStream(sourceFileName, stream);
const sourceFile = await assetStorageStrategy.readFileToBuffer(sourceFileIdentifier);
Expand Down Expand Up @@ -280,17 +280,17 @@ export class AssetService {
return this.connection.getRepository(ctx, Asset).save(asset);
}

private async getSourceFileName(fileName: string): Promise<string> {
private async getSourceFileName(ctx: RequestContext, fileName: string): Promise<string> {
const { assetOptions } = this.configService;
return this.generateUniqueName(fileName, (name, conflict) =>
assetOptions.assetNamingStrategy.generateSourceFileName(name, conflict),
assetOptions.assetNamingStrategy.generateSourceFileName(ctx, name, conflict),
);
}

private async getPreviewFileName(fileName: string): Promise<string> {
private async getPreviewFileName(ctx: RequestContext, fileName: string): Promise<string> {
const { assetOptions } = this.configService;
return this.generateUniqueName(fileName, (name, conflict) =>
assetOptions.assetNamingStrategy.generatePreviewFileName(name, conflict),
assetOptions.assetNamingStrategy.generatePreviewFileName(ctx, name, conflict),
);
}

Expand Down

0 comments on commit 48ae372

Please sign in to comment.