Browse Source

added mime-match, restrictions is object, onBeforeFileAdded and onBeforeUpload callbacks

Artur Paikin 7 years ago
parent
commit
36568cd9c8
5 changed files with 141 additions and 92 deletions
  1. 18 4
      examples/bundled-example/main.js
  2. 10 0
      package-lock.json
  3. 1 0
      package.json
  4. 111 87
      src/core/Core.js
  5. 1 1
      src/plugins/Dashboard/index.js

+ 18 - 4
examples/bundled-example/main.js

@@ -20,10 +20,24 @@ const TUS_ENDPOINT = PROTOCOL + '://master.tus.io/files/'
 const uppy = Uppy({
   debug: true,
   autoProceed: false,
-  maxFileSize: 300000,
-  maxNumberOfFiles: 5,
-  minNumberOfFiles: 2,
-  allowedFileTypes: ['image', 'video']
+  // restrictions: {
+  //   maxFileSize: 300000,
+  //   maxNumberOfFiles: 5,
+  //   minNumberOfFiles: 2,
+  //   allowedFileTypes: ['image/*', 'video/*']
+  // },
+  onBeforeFileAdded: (currentFile, files, done) => {
+    if (currentFile.name === 'pitercss-IMG_0616.jpg') {
+      return done()
+    }
+    return done('this is not the file I was looking for')
+  },
+  onBeforeUpload: (files, done) => {
+    if (Object.keys(files).length < 2) {
+      return done('too few files')
+    }
+    done()
+  }
 })
   .use(Dashboard, {
     trigger: '#uppyModalOpener',

+ 10 - 0
package-lock.json

@@ -5215,6 +5215,11 @@
       "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=",
       "dev": true
     },
+    "mime-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/mime-match/-/mime-match-1.0.2.tgz",
+      "integrity": "sha1-P4fDHprxpf1IX7nbE0Qosju7e6g="
+    },
     "mime-types": {
       "version": "2.1.15",
       "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
@@ -8218,6 +8223,11 @@
       "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
       "dev": true
     },
+    "wildcard": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-1.1.2.tgz",
+      "integrity": "sha1-pwIEUwhNjNLv5wup02liY94XEKU="
+    },
     "win-spawn": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/win-spawn/-/win-spawn-2.0.0.tgz",

+ 1 - 0
package.json

@@ -77,6 +77,7 @@
     "drag-drop": "2.13.2",
     "es6-promise": "3.2.1",
     "lodash.throttle": "4.1.1",
+    "mime-match": "^1.0.2",
     "namespace-emitter": "1.0.0",
     "nanoraf": "3.0.1",
     "on-load": "3.2.0",

+ 111 - 87
src/core/Core.js

@@ -4,6 +4,7 @@ const UppySocket = require('./UppySocket')
 const ee = require('namespace-emitter')
 const throttle = require('lodash.throttle')
 const prettyBytes = require('prettier-bytes')
+const match = require('mime-match')
 // const en_US = require('../locales/en_US')
 // const deepFreeze = require('deep-freeze-strict')
 
@@ -35,10 +36,14 @@ class Uppy {
       // locale: en_US,
       autoProceed: true,
       debug: false,
-      maxFileSize: false,
-      maxNumberOfFiles: false,
-      minNumberOfFiles: false,
-      allowedFileTypes: false,
+      restrictions: {
+        maxFileSize: false,
+        maxNumberOfFiles: false,
+        minNumberOfFiles: false,
+        allowedFileTypes: false
+      },
+      onBeforeFileAdded: (currentFile, files, done) => done(),
+      onBeforeUpload: (files, done) => done(),
       locale: defaultLocale
     }
 
@@ -172,7 +177,7 @@ class Uppy {
   }
 
   checkRestrictions (checkMinNumberOfFiles, file, fileType) {
-    const {maxFileSize, maxNumberOfFiles, minNumberOfFiles, allowedFileTypes} = this.opts
+    const {maxFileSize, maxNumberOfFiles, minNumberOfFiles, allowedFileTypes} = this.opts.restrictions
 
     if (checkMinNumberOfFiles && minNumberOfFiles) {
       console.log(Object.keys(this.state.files).length)
@@ -190,10 +195,13 @@ class Uppy {
       }
     }
 
-    if (allowedFileTypes && allowedFileTypes.indexOf(fileType[0]) < 0) {
-      const allowedFileTypesString = allowedFileTypes.join(', ')
-      this.emit('informer', `${this.i18n('youCanOnlyUploadFileTypes')} ${allowedFileTypesString}`, 'error', 5000)
-      return false
+    if (allowedFileTypes) {
+      const isCorrectFileType = allowedFileTypes.filter(match(fileType.join('/'))).length > 0
+      if (!isCorrectFileType) {
+        const allowedFileTypesString = allowedFileTypes.join(', ')
+        this.emit('informer', `${this.i18n('youCanOnlyUploadFileTypes')} ${allowedFileTypesString}`, 'error', 5000)
+        return false
+      }
     }
 
     if (maxFileSize) {
@@ -207,63 +215,70 @@ class Uppy {
   }
 
   addFile (file) {
-    Utils.getFileType(file).then((fileType) => {
-      const isFileAllowed = this.checkRestrictions(false, file, fileType)
-      if (!isFileAllowed) return
-
-      const updatedFiles = Object.assign({}, this.state.files)
-      const fileName = file.name || 'noname'
-      const fileExtension = Utils.getFileNameAndExtension(fileName)[1]
-      const isRemote = file.isRemote || false
-
-      const fileID = Utils.generateFileID(fileName)
-      const fileTypeGeneral = fileType[0]
-      const fileTypeSpecific = fileType[1]
-
-      const newFile = {
-        source: file.source || '',
-        id: fileID,
-        name: fileName,
-        extension: fileExtension || '',
-        meta: {
-          name: fileName
-        },
-        type: {
-          general: fileTypeGeneral,
-          specific: fileTypeSpecific
-        },
-        data: file.data,
-        progress: {
-          percentage: 0,
-          bytesUploaded: 0,
-          bytesTotal: file.data.size || 0,
-          uploadComplete: false,
-          uploadStarted: false
-        },
-        size: file.data.size || 'N/A',
-        isRemote: isRemote,
-        remote: file.remote || '',
-        preview: file.preview
+    this.opts.onBeforeFileAdded(file, this.getState().files, (err) => {
+      if (err) {
+        this.emit('informer', err, 'error', 5000)
+        return
       }
 
-      if (Utils.isPreviewSupported(fileTypeSpecific) && !isRemote) {
-        newFile.preview = Utils.getThumbnail(file)
-      }
+      Utils.getFileType(file).then((fileType) => {
+        const updatedFiles = Object.assign({}, this.state.files)
+        const fileName = file.name || 'noname'
+        const fileExtension = Utils.getFileNameAndExtension(fileName)[1]
+        const isRemote = file.isRemote || false
+
+        const fileID = Utils.generateFileID(fileName)
+        const fileTypeGeneral = fileType[0]
+        const fileTypeSpecific = fileType[1]
+
+        const newFile = {
+          source: file.source || '',
+          id: fileID,
+          name: fileName,
+          extension: fileExtension || '',
+          meta: {
+            name: fileName
+          },
+          type: {
+            general: fileTypeGeneral,
+            specific: fileTypeSpecific
+          },
+          data: file.data,
+          progress: {
+            percentage: 0,
+            bytesUploaded: 0,
+            bytesTotal: file.data.size || 0,
+            uploadComplete: false,
+            uploadStarted: false
+          },
+          size: file.data.size || 'N/A',
+          isRemote: isRemote,
+          remote: file.remote || '',
+          preview: file.preview
+        }
 
-      updatedFiles[fileID] = newFile
-      this.setState({files: updatedFiles})
+        if (Utils.isPreviewSupported(fileTypeSpecific) && !isRemote) {
+          newFile.preview = Utils.getThumbnail(file)
+        }
 
-      this.bus.emit('file-added', fileID)
-      this.log(`Added file: ${fileName}, ${fileID}, mime type: ${fileType}`)
+        const isFileAllowed = this.checkRestrictions(false, newFile, fileType)
+        if (!isFileAllowed) return
 
-      if (this.opts.autoProceed && !this.scheduledAutoProceed) {
-        this.scheduledAutoProceed = setTimeout(() => {
-          this.scheduledAutoProceed = null
-          this.upload().catch((err) => {
-            console.error(err.stack || err.message)
-          })
-        }, 4)
-      }
+        updatedFiles[fileID] = newFile
+        this.setState({files: updatedFiles})
+
+        this.bus.emit('file-added', fileID)
+        this.log(`Added file: ${fileName}, ${fileID}, mime type: ${fileType}`)
+
+        if (this.opts.autoProceed && !this.scheduledAutoProceed) {
+          this.scheduledAutoProceed = setTimeout(() => {
+            this.scheduledAutoProceed = null
+            this.upload().catch((err) => {
+              console.error(err.stack || err.message)
+            })
+          }, 4)
+        }
+      })
     })
   }
 
@@ -635,36 +650,45 @@ class Uppy {
 
   upload () {
     const isMinNumberOfFilesReached = this.checkRestrictions(true)
-    if (!isMinNumberOfFilesReached) return Promise.resolve()
-
-    this.emit('core:upload')
-
-    const waitingFileIDs = []
-    Object.keys(this.state.files).forEach((fileID) => {
-      const file = this.state.files[fileID]
-      // TODO: replace files[file].isRemote with some logic
-      //
-      // filter files that are now yet being uploaded / haven’t been uploaded
-      // and remote too
-      if (!file.progress.uploadStarted || file.isRemote) {
-        waitingFileIDs.push(file.id)
+    if (!isMinNumberOfFilesReached) {
+      return Promise.reject('Minimum number of files has not been reached')
+    }
+
+    return this.opts.onBeforeUpload(this.getState().files, (err) => {
+      if (err) {
+        this.emit('informer', err, 'error', 5000)
+        return Promise.reject(`onBeforeUpload: ${err}`)
       }
-    })
 
-    const promise = Utils.runPromiseSequence(
-      [...this.preProcessors, ...this.uploaders, ...this.postProcessors],
-      waitingFileIDs
-    )
+      this.emit('core:upload')
+
+      const waitingFileIDs = []
+      Object.keys(this.state.files).forEach((fileID) => {
+        const file = this.state.files[fileID]
+        // TODO: replace files[file].isRemote with some logic
+        //
+        // filter files that are now yet being uploaded / haven’t been uploaded
+        // and remote too
+        if (!file.progress.uploadStarted || file.isRemote) {
+          waitingFileIDs.push(file.id)
+        }
+      })
 
-    // Not returning the `catch`ed promise, because we still want to return a rejected
-    // promise from this method if the upload failed.
-    promise.catch((err) => {
-      this.emit('core:error', err)
-    })
+      const promise = Utils.runPromiseSequence(
+        [...this.preProcessors, ...this.uploaders, ...this.postProcessors],
+        waitingFileIDs
+      )
 
-    return promise.then(() => {
-      // return number of uploaded files
-      this.emit('core:success', waitingFileIDs)
+      // Not returning the `catch`ed promise, because we still want to return a rejected
+      // promise from this method if the upload failed.
+      promise.catch((err) => {
+        this.emit('core:error', err)
+      })
+
+      return promise.then(() => {
+        // return number of uploaded files
+        this.emit('core:success', waitingFileIDs)
+      })
     })
   }
 }

+ 1 - 1
src/plugins/Dashboard/index.js

@@ -314,7 +314,7 @@ module.exports = class DashboardUI extends Plugin {
     const startUpload = (ev) => {
       this.core.upload().catch((err) => {
         // Log error.
-        console.error(err.stack || err.message)
+        console.error(err.stack || err.message || err)
       })
     }