rowanwins / vue-dropzone

A Vue.js component for Dropzone.js - a drag’n’drop file uploads utility with image previews
https://rowanwins.github.io/vue-dropzone/docs/dist
MIT License
2.02k stars 1.4k forks source link

s3 and renameFile #299

Open smakman opened 6 years ago

smakman commented 6 years ago

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?

rowanwins commented 6 years ago

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...

smakman commented 6 years ago

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.

rowanwins commented 6 years ago

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 🤷

smakman commented 6 years ago

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.

shinwang1 commented 6 years ago

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.

HoukasaurusRex commented 6 years ago

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
          };
    }
});
rowanwins commented 6 years ago

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.

vesper8 commented 6 years ago

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 commented 6 years ago

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)

mariusa commented 6 years ago

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 ?

humbugz commented 5 years ago

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...

techpeace commented 4 years ago

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