diff --git a/README.md b/README.md index fd87a8e..2b0bb1b 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ The constructor of the MulterGoogleCloudStorage class can be passed an optional |`projectId`|`string`|`"test-prj-1234"`| |`filename`| `function`|`(request, file, callback): void`| |`bucket`|`string`|`"mybucketname"`| +|`contentType`|`function`|`(request, file): string`| #### Custom file naming If you need to customize the naming of files then you are able to provide a function that will be called before uploading the file. The third argument of the function must be a standard node callback so pass any error in the first argument (or null on sucess) and the string name of the file on success. @@ -77,4 +78,3 @@ If you need to customize the naming of files then you are able to provide a func getFilename(req, file, cb) { cb(null,`${uuid()}_${file.originalname}`); } - diff --git a/lib/index.d.ts b/lib/index.d.ts index 01c0fe2..aab83f4 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1,14 +1,18 @@ +/// import * as multer from 'multer'; import { ConfigurationObject } from '@google-cloud/storage'; +import { Request } from 'express'; export default class MulterGoogleCloudStorage implements multer.StorageEngine { private gcobj; private gcsBucket; private options; getFilename(req: any, file: any, cb: any): void; getDestination(req: any, file: any, cb: any): void; + getContentType: ContentTypeFunction; constructor(opts?: ConfigurationObject & { filename?: any; bucket?: string; + contentType?: ContentTypeFunction; }); _handleFile: (req: any, file: any, cb: any) => void; _removeFile: (req: any, file: any, cb: any) => void; @@ -17,3 +21,4 @@ export declare function storageEngine(opts?: ConfigurationObject & { filename?: any; bucket?: string; }): MulterGoogleCloudStorage; +export declare type ContentTypeFunction = (req: Request, file: Express.Multer.File) => string | undefined; diff --git a/lib/index.js b/lib/index.js index e6b5a90..8724b53 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,9 +2,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); var uuid = require("uuid/v1"); var storage = require('@google-cloud/storage'); -var MulterGoogleCloudStorage = (function () { +var MulterGoogleCloudStorage = /** @class */ (function () { function MulterGoogleCloudStorage(opts) { var _this = this; + this.getContentType = function (req, file) { + return undefined; + }; this._handleFile = function (req, file, cb) { _this.getDestination(req, file, function (err, destination) { if (err) { @@ -15,7 +18,14 @@ var MulterGoogleCloudStorage = (function () { return cb(err); } var gcFile = _this.gcsBucket.file(filename); - file.stream.pipe(gcFile.createWriteStream({ predefinedAcl: _this.options.acl || 'private' })) + var streamOpts = { + predefinedAcl: _this.options.acl || 'private' + }; + var contentType = _this.getContentType(req, file); + if (contentType) { + streamOpts.metadata = { contentType: contentType }; + } + file.stream.pipe(gcFile.createWriteStream(streamOpts)) .on('error', function (err) { return cb(err); }) .on('finish', function (file) { return cb(null, { path: "https://" + _this.options.bucket + ".storage.googleapis.com/" + filename, @@ -30,6 +40,7 @@ var MulterGoogleCloudStorage = (function () { }; opts = opts || {}; this.getFilename = (opts.filename || this.getFilename); + this.getContentType = (opts.contentType || this.getContentType); opts.bucket = (opts.bucket || process.env.GCS_BUCKET || null); opts.projectId = opts.projectId || process.env.GCLOUD_PROJECT || null; opts.keyFilename = opts.keyFilename || process.env.GCS_KEYFILE || null; diff --git a/lib/index.js.map b/lib/index.js.map index 065c974..fb11625 100644 --- a/lib/index.js.map +++ b/lib/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/index.test.d.ts b/lib/index.test.d.ts index e69de29..cb0ff5c 100644 --- a/lib/index.test.d.ts +++ b/lib/index.test.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/index.test.js.map b/lib/index.test.js.map index 5f9bf19..3005370 100644 --- a/lib/index.test.js.map +++ b/lib/index.test.js.map @@ -1 +1 @@ -{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":";;AAAA,6BAA8B;AAC9B,iCAAoC;AAGpC,QAAQ,CAAC,uBAAuB,EAAE;IAC9B,MAAM,CAAC;QACH,OAAO,CAAC,MAAM,EAAE,CAAC;QACjB,IAAM,WAAW,GAAG,cAAQ,MAAM,CAAC,EAAC,MAAM,EAAE,cAAO,CAAC,EAAC,CAAA,CAAA,CAAC,CAAC;QACvD,OAAO,CAAC,YAAY,CAAC,uBAAuB,EAAE,WAAW,CAAC,CAAC;QAE3D,OAAO,CAAC,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,MAAM,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAC;QAE/C,IAAM,wBAAwB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC;QAC5D,IAAM,YAAY,GAAG,IAAI,wBAAwB,EAAE,CAAC;QAEpD,aAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACrD,aAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACrD,aAAM,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,EAAE,EAAjB,CAAiB,CAAC,CAAC;AACnC,CAAC,CAAC,CAAA"} \ No newline at end of file +{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":";;AAAA,6BAA8B;AAC9B,iCAAoC;AAGpC,QAAQ,CAAC,uBAAuB,EAAE;IAC9B,MAAM,CAAC;QACH,OAAO,CAAC,MAAM,EAAE,CAAC;QACjB,IAAM,WAAW,GAAG,cAAQ,OAAO,EAAC,MAAM,EAAE,cAAO,CAAC,EAAC,CAAA,CAAA,CAAC,CAAC;QACvD,OAAO,CAAC,YAAY,CAAC,uBAAuB,EAAE,WAAW,CAAC,CAAC;QAE3D,OAAO,CAAC,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,cAAc,GAAG,MAAM,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAC;QAE/C,IAAM,wBAAwB,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC;QAC5D,IAAM,YAAY,GAAG,IAAI,wBAAwB,EAAE,CAAC;QAEpD,aAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACrD,aAAM,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACrD,aAAM,CAAC,YAAY,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,cAAM,OAAA,OAAO,CAAC,OAAO,EAAE,EAAjB,CAAiB,CAAC,CAAC;AACnC,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/package.json b/package.json index af47eed..0a03344 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "license": "MIT", "dependencies": { "@google-cloud/storage": "^1.1.1", + "@types/express": "^4.16.1", "@types/google-cloud__storage": "^1.1.1", "multer": "^1.3.0", "uuid": "^3.1.0" diff --git a/src/index.ts b/src/index.ts index 467a899..562ab11 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,15 @@ import * as multer from 'multer'; -import { Storage, Bucket, ConfigurationObject } from '@google-cloud/storage'; +import * as Storage from '@google-cloud/storage'; +import { Bucket, ConfigurationObject } from '@google-cloud/storage'; import * as uuid from 'uuid/v1'; -const storage: (options?:ConfigurationObject)=>Storage = require('@google-cloud/storage'); +import { Request } from 'express'; +const storage: (options?:ConfigurationObject)=>Storage = require('@google-cloud/storage'); export default class MulterGoogleCloudStorage implements multer.StorageEngine { private gcobj: Storage; private gcsBucket: Bucket; - private options: ConfigurationObject & { acl?: string, bucket?: string }; + private options: ConfigurationObject & { acl?: string, bucket?: string, contentType?: ContentTypeFunction }; getFilename(req, file, cb) { cb(null,`${uuid()}_${file.originalname}`); @@ -16,10 +18,15 @@ export default class MulterGoogleCloudStorage implements multer.StorageEngine { cb( null, '' ); } - constructor(opts?: ConfigurationObject & { filename?: any, bucket?:string }) { + public getContentType: ContentTypeFunction = (req, file) => { + return undefined; + } + + constructor(opts?: ConfigurationObject & { filename?: any, bucket?:string, contentType?: ContentTypeFunction }) { opts = opts || {}; - + this.getFilename = (opts.filename || this.getFilename); + this.getContentType = (opts.contentType || this.getContentType); opts.bucket = (opts.bucket || process.env.GCS_BUCKET || null); opts.projectId = opts.projectId || process.env.GCLOUD_PROJECT || null; @@ -59,14 +66,25 @@ export default class MulterGoogleCloudStorage implements multer.StorageEngine { return cb(err); } var gcFile = this.gcsBucket.file(filename); - file.stream.pipe(gcFile.createWriteStream({ predefinedAcl: this.options.acl || 'private' })) + + const streamOpts: Storage.WriteStreamOptions = { + predefinedAcl: this.options.acl || 'private' + }; + + const contentType = this.getContentType(req, file); + + if (contentType) { + streamOpts.metadata = {contentType}; + } + + file.stream.pipe( + gcFile.createWriteStream(streamOpts)) .on('error', (err) => cb(err)) .on('finish', (file) => cb(null, { path: `https://${this.options.bucket}.storage.googleapis.com/${filename}`, filename: filename }) ); - }); }); @@ -78,6 +96,8 @@ export default class MulterGoogleCloudStorage implements multer.StorageEngine { } export function storageEngine(opts?: ConfigurationObject & { filename?: any, bucket?:string }){ - + return new MulterGoogleCloudStorage(opts); -} \ No newline at end of file +} + +export type ContentTypeFunction = (req: Request, file: Express.Multer.File) => string | undefined;