Ver Fonte

companion: add support to download gsuite (google docs, google sreadsheet) files

ifedapoolarewaju há 5 anos atrás
pai
commit
1e5e54bc9d

+ 2 - 4
packages/@uppy/companion/src/server/provider/drive/adapter.js

@@ -29,7 +29,7 @@ exports.getItemIcon = (item) => {
       : `${item.backgroundImageLink}${size}`
   }
 
-  if (item.thumbnailLink) {
+  if (item.thumbnailLink && !item.mimeType.startsWith('application/vnd.google')) {
     const smallerThumbnailLink = item.thumbnailLink.replace('s220', 's40')
     return smallerThumbnailLink
   }
@@ -38,9 +38,7 @@ exports.getItemIcon = (item) => {
 }
 
 exports.getItemSubList = (item) => {
-  return item.files.filter((i) => {
-    return exports.isFolder(i) || !i.mimeType.startsWith('application/vnd.google')
-  })
+  return item.files
 }
 
 exports.getItemName = (item) => {

+ 72 - 10
packages/@uppy/companion/src/server/provider/drive/index.js

@@ -102,19 +102,58 @@ class Drive extends Provider {
       .request(done)
   }
 
-  download ({ id, token }, onData) {
+  _exportGsuiteFile ({ id, token }) {
+    logger.info(`calling google file export for ${id}`, 'provider.drive.export')
     return this.client
       .query()
-      .get(`files/${id}`)
-      .qs({ alt: 'media', supportsAllDrives: true })
+      .get(`files/${id}/export`)
+      .qs({ supportsAllDrives: true, mimeType: 'application/pdf' })
       .auth(token)
       .request()
-      .on('data', (chunk) => onData(null, chunk))
-      .on('end', () => onData(null, null))
-      .on('error', (err) => {
-        logger.error(err, 'provider.drive.download.error')
+  }
+
+  _getGsuiteFileMeta ({ id, token }, onDone) {
+    logger.info(`calling Gsuite file meta for ${id}`, 'provider.drive.export.meta')
+    return this.client
+      .query()
+      .head(`files/${id}/export`)
+      .qs({ supportsAllDrives: true, mimeType: 'application/pdf' })
+      .auth(token)
+      .request(onDone)
+  }
+
+  _isGsuiteFile (mimeType) {
+    return mimeType.startsWith('application/vnd.google')
+  }
+
+  download ({ id, token }, onData) {
+    this.stats({ id, token }, (err, resp, body) => {
+      if (err) {
+        logger.error(err, 'provider.drive.download.stats.error')
         onData(err)
-      })
+        return
+      }
+
+      let requestStream
+      if (this._isGsuiteFile(body.mimeType)) {
+        requestStream = this._exportGsuiteFile({ id, token })
+      } else {
+        requestStream = this.client
+          .query()
+          .get(`files/${id}`)
+          .qs({ alt: 'media', supportsAllDrives: true })
+          .auth(token)
+          .request()
+      }
+
+      requestStream
+        .on('data', (chunk) => onData(null, chunk))
+        .on('end', () => onData(null, null))
+        .on('error', (err) => {
+          logger.error(err, 'provider.drive.download.error')
+          onData(err)
+        })
+    })
   }
 
   thumbnail (_, done) {
@@ -131,7 +170,30 @@ class Drive extends Provider {
         logger.error(err, 'provider.drive.size.error')
         return done(err)
       }
-      done(null, parseInt(body.size))
+
+      if (this._isGsuiteFile(body.mimeType)) {
+        // Google Docs file sizes can be determined
+        // while Google sheets file sizes can't be determined
+        const googleDocMimeType = 'application/vnd.google-apps.document'
+        if (body.mimeType !== googleDocMimeType) {
+          const maxExportFileSize = 10 * 1024 * 1024 // 10 MB
+          done(null, maxExportFileSize)
+          return
+        }
+
+        this._getGsuiteFileMeta({ id, token }, (err, resp) => {
+          if (err || resp.statusCode !== 200) {
+            err = this._error(err, resp)
+            logger.error(err, 'provider.drive.docs.size.error')
+            return done(err)
+          }
+
+          const size = resp.headers['content-length']
+          done(null, size ? parseInt(size) : null)
+        })
+      } else {
+        done(null, parseInt(body.size))
+      }
     })
   }
 
@@ -183,7 +245,7 @@ class Drive extends Provider {
   _error (err, resp) {
     if (resp) {
       const fallbackMessage = `request to ${this.authProvider} returned ${resp.statusCode}`
-      const errMsg = resp.body.error ? resp.body.error.message : fallbackMessage
+      const errMsg = (resp.body && resp.body.error) ? resp.body.error.message : fallbackMessage
       return resp.statusCode === 401 ? new ProviderAuthError() : new ProviderApiError(errMsg, resp.statusCode)
     }
     return err