Browse Source

Merge pull request #408 from transloadit/chore/no-state-fns

Remove functions from state
Artur Paikin 7 years ago
parent
commit
385572e056

+ 1 - 0
CHANGELOG.md

@@ -100,6 +100,7 @@ What we need to do to release Uppy 1.0
 
 To be released: 2017-11-10
 
+- [x] s3: Automatically wrap XHRUpload. **Users should remove `.use(XHRUpload)` when using S3.** (@goto-bus-stop)
 - [x] webcam: look into simplifying / improving webcam plugin (probably good to do modern browsers only) (#382 / @goto-bus-stop)
 - [ ] webcam: only show the webcam tab when browser support is available (media recorder API) (@arturi, @goto-bus-stop)
 - [ ] core: Redux PR (#216 / @arturi, @goto-bus-stop, @richardwillars)

+ 0 - 2
examples/aws-presigned-url/main.js

@@ -1,6 +1,5 @@
 const Uppy = require('uppy/lib/core/Core.js')
 const Dashboard = require('uppy/lib/plugins/Dashboard')
-const XHRUpload = require('uppy/lib/plugins/XHRUpload')
 const AwsS3 = require('uppy/lib/plugins/AwsS3')
 
 const uppy = Uppy({
@@ -12,7 +11,6 @@ uppy.use(Dashboard, {
   inline: true,
   target: 'body'
 })
-uppy.use(XHRUpload)
 uppy.use(AwsS3, {
   getUploadParameters (file) {
     // Send a request to our PHP signing endpoint.

+ 34 - 32
src/plugins/AwsS3/index.js

@@ -1,4 +1,5 @@
 const Plugin = require('../Plugin')
+const XHRUpload = require('../XHRUpload')
 
 module.exports = class AwsS3 extends Plugin {
   constructor (core, opts) {
@@ -47,37 +48,6 @@ module.exports = class AwsS3 extends Plugin {
       })
     })
 
-    this.core.setState({
-      xhrUpload: Object.assign({}, this.core.state.xhrUpload, {
-        responseUrlFieldName: 'location',
-        getResponseData (xhr) {
-          // If no response, we've hopefully done a PUT request to the file
-          // in the bucket on its full URL.
-          if (!xhr.responseXML) {
-            return { location: xhr.responseURL }
-          }
-          function getValue (key) {
-            const el = xhr.responseXML.querySelector(key)
-            return el ? el.textContent : ''
-          }
-          return {
-            location: getValue('Location'),
-            bucket: getValue('Bucket'),
-            key: getValue('Key'),
-            etag: getValue('ETag')
-          }
-        },
-        getResponseError (xhr) {
-          // If no response, we don't have a specific error message, use the default.
-          if (!xhr.responseXML) {
-            return
-          }
-          const error = xhr.responseXML.querySelector('Error > Message')
-          return new Error(error.textContent)
-        }
-      })
-    })
-
     return Promise.all(
       fileIDs.map((id) => {
         const file = this.core.getFile(id)
@@ -106,7 +76,6 @@ module.exports = class AwsS3 extends Plugin {
           method,
           formData: method.toLowerCase() === 'post',
           endpoint: url,
-          fieldName: 'file',
           metaFields: Object.keys(fields)
         }
 
@@ -134,9 +103,42 @@ module.exports = class AwsS3 extends Plugin {
 
   install () {
     this.core.addPreProcessor(this.prepareUpload)
+
+    this.core.use(XHRUpload, {
+      fieldName: 'file',
+      responseUrlFieldName: 'location',
+      getResponseData (xhr) {
+        // If no response, we've hopefully done a PUT request to the file
+        // in the bucket on its full URL.
+        if (!xhr.responseXML) {
+          return { location: xhr.responseURL }
+        }
+        function getValue (key) {
+          const el = xhr.responseXML.querySelector(key)
+          return el ? el.textContent : ''
+        }
+        return {
+          location: getValue('Location'),
+          bucket: getValue('Bucket'),
+          key: getValue('Key'),
+          etag: getValue('ETag')
+        }
+      },
+      getResponseError (xhr) {
+        // If no response, we don't have a specific error message, use the default.
+        if (!xhr.responseXML) {
+          return
+        }
+        const error = xhr.responseXML.querySelector('Error > Message')
+        return new Error(error.textContent)
+      }
+    })
   }
 
   uninstall () {
+    const uploader = this.core.getPlugin('XHRUpload')
+    this.core.removePlugin(uploader)
+
     this.core.removePreProcessor(this.prepareUpload)
   }
 }

+ 13 - 14
src/plugins/Dashboard/index.js

@@ -93,7 +93,6 @@ module.exports = class DashboardUI extends Plugin {
   addTarget (plugin) {
     const callerPluginId = plugin.id || plugin.constructor.name
     const callerPluginName = plugin.title || callerPluginId
-    // const callerPluginIcon = plugin.icon || this.opts.defaultTabIcon
     const callerPluginType = plugin.type
 
     if (callerPluginType !== 'acquirer' &&
@@ -107,9 +106,7 @@ module.exports = class DashboardUI extends Plugin {
     const target = {
       id: callerPluginId,
       name: callerPluginName,
-      // icon: callerPluginIcon,
       type: callerPluginType,
-      // render: plugin.render,
       isHidden: true
     }
 
@@ -306,19 +303,21 @@ module.exports = class DashboardUI extends Plugin {
     totalSize = prettyBytes(totalSize)
     totalUploadedSize = prettyBytes(totalUploadedSize)
 
-    const acquirers = pluginState.targets.filter(target => {
+    const attachRenderFunctionToTarget = (target) => {
       const plugin = this.core.getPlugin(target.id)
-      target.icon = plugin.icon || this.opts.defaultTabIcon
-      target.render = plugin.render
-      return target.type === 'acquirer'
-    })
+      return Object.assign({}, target, {
+        icon: plugin.icon || this.opts.defaultTabIcon,
+        render: plugin.render
+      })
+    }
 
-    const progressindicators = pluginState.targets.filter(target => {
-      const plugin = this.core.getPlugin(target.id)
-      target.icon = plugin.icon || this.opts.defaultTabIcon
-      target.render = plugin.render
-      return target.type === 'progressindicator'
-    })
+    const acquirers = pluginState.targets
+      .filter(target => target.type === 'acquirer')
+      .map(attachRenderFunctionToTarget)
+
+    const progressindicators = pluginState.targets
+      .filter(target => target.type === 'progressindicator')
+      .map(attachRenderFunctionToTarget)
 
     const startUpload = (ev) => {
       this.core.upload().catch((err) => {

+ 4 - 1
src/plugins/Transloadit/index.js

@@ -158,7 +158,10 @@ module.exports = class Transloadit extends Plugin {
           // Only send assembly metadata to the tus endpoint.
           metaFields: Object.keys(tlMeta),
           // Make sure tus doesn't resume a previous upload.
-          uploadUrl: null
+          uploadUrl: null,
+          // Disable tus-js-client fingerprinting, otherwise uploading the same file at different times
+          // will upload to the same assembly.
+          resume: false
         })
         const transloadit = {
           assembly: assembly.assembly_id

+ 28 - 36
website/src/docs/aws-s3.md

@@ -6,16 +6,11 @@ permalink: docs/aws-s3/
 ---
 
 The `AwsS3` plugin can be used to upload files directly to an S3 bucket.
-
-As of now, the `AwsS3` plugin "decorates" the XHRUpload plugin.
-To upload files directly to S3, both the XHRUpload and AwsS3 plugins must be used:
+Uploads can be signed using [uppy-server][uppy-server docs] or a custom signing function.
 
 ```js
-// No options have to be provided to the XHRUpload plugin,
-// the S3 plugin will configure it.
-uppy.use(XHRUpload)
 uppy.use(AwsS3, {
-  // Options for S3
+  // Options
 })
 ```
 
@@ -26,7 +21,6 @@ uppy.use(AwsS3, {
 When using [uppy-server][uppy-server docs] to sign S3 uploads, set this option to the root URL of the uppy-server.
 
 ```js
-uppy.use(XHRUpload)
 uppy.use(AwsS3, {
   host: 'https://uppy-server.my-app.com/'
 })
@@ -134,35 +128,33 @@ That way, no private keys to the S3 bucket need to be shared on the client.
 For example, there could be a PHP server endpoint that prepares a presigned URL for a file:
 
 ```js
-uppy
-  .use(XHRUpload)
-  .use(AwsS3, {
-    getUploadParameters (file) {
-      // Send a request to our PHP signing endpoint.
-      return fetch('/s3-sign.php', {
-        method: 'post',
-        // Send and receive JSON.
-        headers: {
-          accept: 'application/json',
-          'content-type': 'application/json'
-        },
-        body: JSON.stringify({
-          filename: file.name,
-          contentType: file.type
-        })
-      }).then((response) => {
-        // Parse the JSON response.
-        return response.json()
-      }).then((data) => {
-        // Return an object in the correct shape.
-        return {
-          method: data.method,
-          url: data.url,
-          fields: {}
-        }
+uppy.use(AwsS3, {
+  getUploadParameters (file) {
+    // Send a request to our PHP signing endpoint.
+    return fetch('/s3-sign.php', {
+      method: 'post',
+      // Send and receive JSON.
+      headers: {
+        accept: 'application/json',
+        'content-type': 'application/json'
+      },
+      body: JSON.stringify({
+        filename: file.name,
+        contentType: file.type
       })
-    }
-  })
+    }).then((response) => {
+      // Parse the JSON response.
+      return response.json()
+    }).then((data) => {
+      // Return an object in the correct shape.
+      return {
+        method: data.method,
+        url: data.url,
+        fields: {}
+      }
+    })
+  }
+})
 ```
 
 See the [aws-presigned-url example in the uppy repository](https://github.com/transloadit/uppy/tree/master/examples/aws-presigned-url) for a small example that implements both the server-side and the client-side.