Keystone-classic: Local files are uploaded without extension

Created on 8 Aug 2018  路  10Comments  路  Source: keystonejs/keystone-classic

Hello! I have an issue with uploading files via Admin UI to the FS storage.

Expected behavior


Before updating to Keystone release version 4.0.0 the filenames were generated randomly and had extension in the end.

Actual/Current behavior


Now they are uploaded without an extension.

Steps to reproduce the actual/current behavior


var storage = new keystone.Storage({
    adapter: keystone.Storage.Adapters.FS,
    fs: {
        path: keystone.expandPath('./public/uploads/vendors'),
    },
});

Vendor.add({
    logo: {
        type: Types.File,
        storage: storage,
    },
})

Environment

| Software | Version
| ---------------- | -------
| Keystone | 4.0.0
| Node.js | 10.8.0
| Browser | Chrome 67.0.3396.99 (64-bit)

4.x candidate bug

Most helpful comment

It's because a file extention is not been passed to the randomFilename function my solution was to add this line to this file.

filename = sanitize(filename) + path.parse(file.originalname).ext;

https://github.com/keystonejs/keystone/blob/20a7723b6a3682f1c4e87750e832de564d83a590/lib/storage/adapters/fs/index.js#L97

All 10 comments

Same issue here!

It's because a file extention is not been passed to the randomFilename function my solution was to add this line to this file.

filename = sanitize(filename) + path.parse(file.originalname).ext;

https://github.com/keystonejs/keystone/blob/20a7723b6a3682f1c4e87750e832de564d83a590/lib/storage/adapters/fs/index.js#L97

I have the same problem , any news about how to fix ??

I have the same problem , any news about how to fix ??

I did something like this to fix this:

var storage = new keystone.Storage({
    adapter: keystone.Storage.Adapters.FS,
    schema : {
        originalname: true
    },
    fs: {
        path: keystone.expandPath('./public/uploads/vendors'),
        generateFilename: (file) => {
            const ext = file.originalname.substr(file.originalname.lastIndexOf('.') + 1);
            return `${file.filename}.${ext}`;
        }
    },
});

Same issue. But i didn't understand after what this bug started? A upload a lot of files and all files was with ext. Need research.

@Twansparant 's solution worked for me (didn't need the schema key - not sure what that does?). Another solution is to use the keystone-storage-namefunctions.originalFilename function, since that includes the extension, like so:

const keystone = require('keystone');
const keystone_namegen = require('keystone-storage-namefunctions');

const storage = new keystone.Storage({
    adapter: keystone.Storage.Adapters.FS,
    fs: {
        path: 'uploads',
        publicPath: '/public/uploads/',
        generateFilename: keystone_namegen.originalFilename,
    }
});

I've faced with the same issues during working with keystone-storage-s3

Mine workaround is to use mime-types as fallback for extensions

var crypto = require('crypto');
var mime = require('mime-types')

exports.randomFilename = function (file, i, callback) {
    crypto.randomBytes(16, function (err, data) {
        if (err) return callback(err);
        return callback(null, filenameFromBuffer(data, file.extension || mime.extension(file.mimetype)));
    });
};

and then reuse randomFilename as generateFilename

var keystone = require('keystone');
var _ = require( "lodash" );
var generateFileName = require('./generateFilename');

var createStorage = function(config) {
    return new keystone.Storage({
        adapter: require('keystone-storage-adapter-s3'),
        s3: _.merge({
            key: process.env.S3_KEY, // required; defaults to process.env.S3_KEY
            secret: process.env.S3_SECRET, // required; defaults to process.env.S3_SECRET
            bucket: process.env.S3_BUCKET, // required; defaults to process.env.S3_BUCKET
            region: process.env.S3_REGION, // optional; defaults to process.env.S3_REGION, or if that's not specified, us-east-1
            uploadParams: { // optional; add S3 upload params; see below for details
                ACL: 'public-read',
            },
            generateFilename: generateFileName.randomFilename,
        }, config),
        schema: {
            url: true
        }
    });
}

module.exports = createStorage;

Same issue (v4.2.1).

I've faced with the same issues during working with keystone-storage-s3

Mine workaround is to use mime-types as fallback for extensions

var crypto = require('crypto');
var mime = require('mime-types')

exports.randomFilename = function (file, i, callback) {
  crypto.randomBytes(16, function (err, data) {
      if (err) return callback(err);
      return callback(null, filenameFromBuffer(data, file.extension || mime.extension(file.mimetype)));
  });
};

and then reuse randomFilename as generateFilename

var keystone = require('keystone');
var _ = require( "lodash" );
var generateFileName = require('./generateFilename');

var createStorage = function(config) {
  return new keystone.Storage({
      adapter: require('keystone-storage-adapter-s3'),
      s3: _.merge({
          key: process.env.S3_KEY, // required; defaults to process.env.S3_KEY
          secret: process.env.S3_SECRET, // required; defaults to process.env.S3_SECRET
          bucket: process.env.S3_BUCKET, // required; defaults to process.env.S3_BUCKET
          region: process.env.S3_REGION, // optional; defaults to process.env.S3_REGION, or if that's not specified, us-east-1
          uploadParams: { // optional; add S3 upload params; see below for details
              ACL: 'public-read',
          },
          generateFilename: generateFileName.randomFilename,
      }, config),
      schema: {
          url: true
      }
  });
}

module.exports = createStorage;

Hi @AlexanderMoroz !
I understand that in the first snippet of code you added || mime.extension(file.mimetype) to keystone-store-namefunctions/index.js (line 54).

In what file did you add in the second snippet of code to make it work?

Thanks for posting this!

For those of you using keystone-storage-adapter-s3 , just edit keystone-storage-namefunctions/index.js

Like @AlexanderMoroz said, put var mime = require('mime-types'); at the top and replace line 54 with return callback(null, filenameFromBuffer(data, file.extension || mime.extension(file.mimetype)));

Files are uploading with their proper extension. :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jacqueslareau picture jacqueslareau  路  5Comments

ttsirkia picture ttsirkia  路  4Comments

kamontat picture kamontat  路  5Comments

calebmcelroy picture calebmcelroy  路  3Comments

javierpelozo picture javierpelozo  路  5Comments