vue-dropzone icon indicating copy to clipboard operation
vue-dropzone copied to clipboard

s3 and renameFile

Open smakman opened this issue 7 years ago • 12 comments

I'm trying to rename files before uploading to S3, using:

dropzoneOptions: {
  renameFile (file) {
    file.name = new Date().getTime() + '_' + file.name; // results in Uncaught TypeError: Cannot assign to read only property 'name' of object '#<File>'
    // or 
    file.upload.filename = new Date().getTime() + '_' + file.name; // results in Uncaught TypeError: Cannot set property 'filename' of undefined
  }
}

Is it even possible to rename files before they get uploaded to S3? Or this there another way to avoid files with the same name from being overwritten in S3?

smakman avatar Mar 01 '18 15:03 smakman

Gday @smakman

Sorry for the slow reply. I've not looked at this before but my understanding doing a bit of googling is that this needs to be used something like

renameFile : function(filename, file) {
    return 'SomeNewFilename'
}

let me know if that works...

rowanwins avatar Mar 12 '18 04:03 rowanwins

No worries @rowanwins. The renameFile function only receives one argument containing the file object. And it doesn't work either when returning some new value.

smakman avatar Mar 12 '18 08:03 smakman

Righto just had a bit more a play and this appears to work

        renameFile(file) {
            return file.renameFilename = "YourNewfileName"
        },

Idea stolen from here. Not terribly intuitive but appears to work 🤷

rowanwins avatar Mar 12 '18 09:03 rowanwins

Doesn't work either on my end. I can see a property called renameFilename is set on the file object, which wasn't there before, but it doesn't get used.

smakman avatar Mar 12 '18 10:03 smakman

I'm curious @smakman , are you getting an large string appended to your filename when you upload to s3? I'm uploading a lot of files to my web app, and the string length is causing 500 errors for the server.

shinwang1 avatar Apr 05 '18 17:04 shinwang1

Accessing the fileName value in the fileMeta object from within this.on('sending', ()=>{}) seems to work for me:

$('#myDropzone').dropzone({
    const date = new Date().getTime();
    init() {
        // Send file starts
        self.on('sending', (file) => {
          file.fileMeta = {
            fileName: '${date} ${file.name}',
            size: file.size,
            date
          };
    }
});

HoukasaurusRex avatar May 01 '18 03:05 HoukasaurusRex

Thanks for chiming in @Pterobyte . I wonder if you could do something hooking into the sending event emitted from the vue component, see example here.

rowanwins avatar May 01 '18 05:05 rowanwins

can't get this to work at all... tried so many solutions including using the event you just referenced @rowanwins

@Pterobyte the code you shared doesn't work for me, it doesn't appear to be valid syntax and is it even compatible with vue-dropzone?

dropzone does support file renaming and the function doesn't throw an error or anything, but the filename that is uploaded to S3 is always whatever the filename is.. seems like there's nom way to change it

this might have to do with the implementation of direct-to-s3 in this package

if anyone figures it out please reply..

vesper8 avatar May 27 '18 00:05 vesper8

I did just noticed something

renameFile doesn't work with sendFileToServer set to true, but it does work when set to false (the file is properly renamed before uploaded to S3)

vesper8 avatar May 27 '18 14:05 vesper8

This works for me:


import vue2Dropzone from 'vue2-dropzone'
import 'vue2-dropzone/dist/vue2Dropzone.min.css'

export default {
...
}

function renameFile (file) {
    l("renameFile", file)
    return "something." + file.name.toLowerCase().split('.').pop()
}

However, we also need to access the vue instance data, eg. this.user These aren't available outside of export

How can renameFile be used as a vue instance method, similar to s3UploadSuccess(), so that we can access vue data ?

mariusa avatar Aug 28 '18 09:08 mariusa

An old issue, but for anyone else who happens upon this as I did:

As far as I can tell, renameFile() does not work when uploading directly to S3.

There is one possible solution that is fairly easy though: Since the S3 upload destination is determined by your signed URL, you can rename the file in your signing method.

Your signing process has steps for creating the policy and form data, such as (PHP example):

$policy = [
            'expiration' => gmdate('Y-m-d\TG:i:s\Z', strtotime('+3 hours')),
            'conditions' => [
                ['bucket' => $s3Bucket],
                ['acl' => $acl],
                ['starts-with', '$key', ''],
                ['starts-with', '$Content-Type', ''],
                ['starts-with', '$Content-Length', ''],
                ['success_action_status' => $successStatus],
                ['x-amz-credential' => $credentials],
                ['x-amz-algorithm' => $algorithm],
                ['x-amz-date' => $date],
                ['x-amz-expires' => $expires],
                ['key' => $fileName],
            ]
        ];

Whatever you assign as the file name to 'key' is what will be used on the S3 side. Rename it before setting key and S3 will store the renamed version of whatever you are uploading regardless of the source file name.

One catch: dropzone's UI will show the original file name despite it being renamed on the S3 side.

Hope that helps someone...

humbugz avatar May 14 '19 14:05 humbugz

To follow on @humbugz answer, the following post was helpful for determining a Rails solution:

module Attachable
  extend ActiveSupport::Concern

  included do
    after_save :sanitize_attachment_uri!

    # Sanitize the URL of an uploaded file to ensure background
    # images function in CSS.
    #
    # @return [void]
    def sanitize_attachment_uri!
      return unless attachment.attached?

      new_filename =
        attachment.filename.to_s.split('.').first.parameterize +
        attachment.filename.extension

      attachment.blob.update!(filename: new_filename)
    end
  end
end

techpeace avatar Jul 08 '20 18:07 techpeace