Browse Source

Merge pull request #978 from pauln/feature/team-drives

Google Drive: Support Team Drives
Ifedapo .A. Olarewaju 6 years ago
parent
commit
312d078996

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

@@ -2,8 +2,9 @@ const request = require('request')
 // @ts-ignore
 const purest = require('purest')({ request })
 const logger = require('../logger')
-const DRIVE_FILE_FIELDS = 'kind,id,name,mimeType,ownedByMe,permissions(role,emailAddress),size,modifiedTime,iconLink,thumbnailLink'
+const DRIVE_FILE_FIELDS = 'kind,id,name,mimeType,ownedByMe,permissions(role,emailAddress),size,modifiedTime,iconLink,thumbnailLink,teamDriveId'
 const DRIVE_FILES_FIELDS = `kind,nextPageToken,incompleteSearch,files(${DRIVE_FILE_FIELDS})`
+const TEAM_DRIVE_FIELDS = 'teamDrives(kind,id,name,backgroundImageLink)'
 /**
  * @class
  * @implements {Provider}
@@ -24,23 +25,49 @@ class Drive {
   list (options, done) {
     const directory = options.directory || 'root'
     const trashed = options.trashed || false
+    const query = options.query || {}
+    const listTeamDrives = query.listTeamDrives || 'false'
+    const teamDriveId = query.teamDriveId || false
 
-    return this.client
-      .query()
-      .get('files')
-      .where({
+    if (listTeamDrives === 'true') {
+      // Just return a list of all Team Drives which the user can access.
+      return this.client
+        .query()
+        .get('teamdrives')
+        .where({ fields: TEAM_DRIVE_FIELDS })
+        .auth(options.token)
+        .request(done)
+    } else {
+      let where = {
         fields: DRIVE_FILES_FIELDS,
         q: `'${directory}' in parents and trashed=${trashed}`
-      })
-      .auth(options.token)
-      .request(done)
+      }
+      if (teamDriveId) {
+        // Team Drives require several extra parameters in order to work.
+        where.supportsTeamDrives = true
+        where.includeTeamDriveItems = true
+        where.teamDriveId = teamDriveId
+        where.corpora = 'teamDrive'
+        if (directory === 'root') {
+          // To list the top-level contents of a Team Drive, filter for the Team Drive id as a parent.
+          where.q = `'${teamDriveId}' in parents and trashed=${trashed}`
+        }
+      }
+
+      return this.client
+        .query()
+        .get('files')
+        .where(where)
+        .auth(options.token)
+        .request(done)
+    }
   }
 
   stats ({ id, token }, done) {
     return this.client
       .query()
       .get(`files/${id}`)
-      .where({fields: DRIVE_FILE_FIELDS})
+      .where({ fields: DRIVE_FILE_FIELDS, supportsTeamDrives: true })
       .auth(token)
       .request(done)
   }
@@ -49,7 +76,7 @@ class Drive {
     return this.client
       .query()
       .get(`files/${id}`)
-      .where({ alt: 'media' })
+      .where({ alt: 'media', supportsTeamDrives: true })
       .auth(token)
       .request()
       .on('data', onData)

+ 13 - 0
packages/@uppy/google-drive/src/DriveProviderViews.js

@@ -0,0 +1,13 @@
+const ProviderViews = require('@uppy/provider-views')
+
+module.exports = class DriveProviderViews extends ProviderViews {
+  toggleCheckbox (e, file) {
+    e.stopPropagation()
+    e.preventDefault()
+
+    // Team Drives aren't selectable; for all else, defer to the base ProviderView.
+    if (file.kind !== 'drive#teamDrive') {
+      super.toggleCheckbox(e, file)
+    }
+  }
+}

+ 51 - 3
packages/@uppy/google-drive/src/index.js

@@ -1,6 +1,6 @@
 const { Plugin } = require('@uppy/core')
 const { Provider } = require('@uppy/companion-client')
-const ProviderViews = require('@uppy/provider-views')
+const DriveProviderViews = require('./DriveProviderViews')
 const { h } = require('preact')
 
 module.exports = class GoogleDrive extends Plugin {
@@ -32,7 +32,7 @@ module.exports = class GoogleDrive extends Plugin {
   }
 
   install () {
-    this.view = new ProviderViews(this)
+    this.view = new DriveProviderViews(this)
     // Set default state for Google Drive
     this.setPluginState({
       authenticated: false,
@@ -41,7 +41,10 @@ module.exports = class GoogleDrive extends Plugin {
       directories: [],
       activeRow: -1,
       filterInput: '',
-      isSearchVisible: false
+      isSearchVisible: false,
+      hasTeamDrives: false,
+      teamDrives: [],
+      teamDriveId: ''
     })
 
     const target = this.opts.target
@@ -59,9 +62,19 @@ module.exports = class GoogleDrive extends Plugin {
     this.setPluginState({ authenticated })
     if (authenticated) {
       this.view.getFolder('root')
+      this.getTeamDrives()
     }
   }
 
+  getTeamDrives () {
+    this[this.id].get(`${this.GoogleDrive.id}/list/?listTeamDrives=true`)
+      .then((payload) => {
+        if (payload.teamDrives && payload.teamDrives.length) {
+          this.setPluginState({hasTeamDrives: true, teamDrives: payload.teamDrives})
+        }
+      })
+  }
+
   getUsername (data) {
     for (const item of data.files) {
       if (item.ownedByMe) {
@@ -105,6 +118,13 @@ module.exports = class GoogleDrive extends Plugin {
   }
 
   getItemRequestPath (item) {
+    // If it's from a Team Drive, add the Team Drive ID as a query param.
+    // The server needs the Team Drive ID to list files in a Team Drive folder.
+    if (item.teamDriveId) {
+      item.id += `?teamDriveId=${item.teamDriveId}`
+      delete item.teamDriveId
+    }
+
     return this.getItemId(item)
   }
 
@@ -117,6 +137,34 @@ module.exports = class GoogleDrive extends Plugin {
   }
 
   render (state) {
+    let pluginState = this.getPluginState()
+
+    // If the user has access to any Team Drives, handle them as needed.
+    if (pluginState.hasTeamDrives) {
+      let folders = pluginState.folders
+
+      // Remove any Team Drives we've previously pushed into the list of folders.
+      folders = folders.filter((folder) => {
+        return folder.kind !== 'drive#teamDrive'
+      })
+
+      // If viewing the Google Drive root, add Team Drives to the top of the list.
+      if (pluginState.directories.length === 1) {
+        pluginState.teamDrives.forEach((teamDrive) => {
+          folders.splice(0, 0, {
+            // Instead of a "normal" id, set it as a query param which will be handled by the server.
+            id: '?teamDriveId=' + teamDrive.id,
+            name: teamDrive.name,
+            kind: teamDrive.kind,
+            // Team Drives don't offer an icon, but do have a background image.
+            // The extra bit added onto the end crops/resizes the background image, yielding the same icon
+            // which is shown in the list of Team Drives within the Google Drive web UI.
+            iconLink: teamDrive.backgroundImageLink + '=w16-h16-n'
+          })
+        })
+      }
+      pluginState.folders = folders
+    }
     return this.view.render(state)
   }
 }