Thanks I’m glad to finally have something that’s working
Yup, the transfer is taking place server side. The token and Drive meta data get posted to my server which does the downloading and transferring. However, to get thumbnails to show in the Uppy Dashboard I did do a client side request to get them (“document” being what the Picker API provides):
// get thumbnail links for all selected files
const requests = documents.map(document => {
return fetch(`https://www.googleapis.com/drive/v3/files/${document.id}?fields=thumbnailLink,id`, {
headers: {
Authorization: `Bearer ${_accessToken}`
}
})
.then(response => response.json())
})
const responses = await Promise.all(requests)
Then, converting the documents to Uppy files:
documents.forEach(document => {
uppy.addFile({
name: document.name,
type: document.mimeType,
data: {}, // file blob
meta: {
// optional, store the directory path of a file so Uppy can tell identical files in different directories apart.
relativePath: document.id
},
source: 'GooglePicker', // optional, determines the source of the file, for example, Instagram.
isRemote: true, // when true, will use the preview field to show a thumbnail in dashboard
preview: document.thumbnailLink, // from `responses`, but added to the document
remote: document
});
})
I ended up writing a custom uploader to handle the documents from Picker. The uploader gets swapped out using Uppy’s onBeforeUpload hook (Though I guess the plugin could just ignore files it doesn’t care about).
onBeforeUpload(files) { // if necessary, change which uploader to use
console.log('onBeforeUpload')
// check which uploader needs to be used
files = Object.values(files)
const file = files[0]
let requiredUploaderType
if (file.source === 'GooglePicker') {
requiredUploaderType = 'GooglePickerUploader'
} else if (file.isRemote) {
requiredUploaderType = 'RemoteUploader'
} else if (!file.isRemote) {
requiredUploaderType = 'LocalUploader'
}
// remove previous uploader
const uploader = uppy.getPlugin('uploader')
if (uploader && uploader.type !== requiredUploaderType) {
uppy.removePlugin(uploader)
} else if (uploader && uploader.type === requiredUploaderType) {
// update folder in case user opened a different one since previous upload
uploader.setOptions({
folderId: getActiveFolderID()
})
return true
}
// select uploader based on the selected files
if (requiredUploaderType === 'GooglePickerUploader') {
console.log('use googlepicker uploader instead')
uppy.use(GooglePickerUploader, {
id: 'uploader',
authToken: accessToken(),
folderId: getActiveFolderID()
})
} else if (requiredUploaderType === 'RemoteUploader') {
console.log('use remote uploader')
uppy.use(RemoteUploader, {
id: 'uploader',
accountId,
companionUrl,
folderId: getActiveFolderID()
})
} else if (requiredUploaderType === 'LocalUploader') {
console.log('use local uploader')
uppy.use(LocalUploader, {
id: 'uploader',
folderId: getActiveFolderID()
})
}
return true
}
And here’s the plugin for reference:
import Uppy from '../../../../../serve/vendor/uppy/dist/uppy.js'
/**
* An Uppy plugin to upload files from Google Picker. Files are selected using
* the Google Picker API to then be uploaded to our CDN (via the asset controller).
*
* This class is only responsible for taking the files picked and passing them to
* the asset controller.
*/
export default class GooglePickerUploader extends Uppy.BasePlugin {
constructor (uppy, opts) {
super(uppy, opts)
this.id = opts.id || 'GooglePickerUploader'
this.type = 'GooglePickerUploader'
this.authToken = opts.authToken
this.folderId = opts.folderId
}
install () {
this.uppy.addPreProcessor(this.prepareUpload)
this.uppy.addUploader(this.upload)
console.log('PickerUploader install')
}
uninstall () {
this.uppy.removePreProcessor(this.prepareUpload)
this.uppy.removeUploader(this.upload)
console.log('PickerUploader uninstall')
}
// recommended way to define functions for hooks: https://uppy.io/docs/guides/building-plugins/#upload-hooks
prepareUpload = (fileIDs) => {
console.log(this) // `this` refers to the `MyPlugin` instance.
return Promise.resolve()
}
upload = (ids) => {
console.log('google picker upload', ids.length)
const files = ids.map(id => this.uppy.getFile(id))
const uploads = files.map(file => this.uploadDocument(file))
return Promise.all(uploads)
}
uploadDocument (uppyFile) {
this.uppy.setFileState(uppyFile.id, {
progress: {
uploadStarted: Date.now(),
}
})
return new Promise((resolve, reject) => {
const form = new FormData()
form.set('oauthToken', this.authToken)
form.set('documents', JSON.stringify([uppyFile.remote]))
form.set('folderId', Number.parseInt(this.folderId))
fetch('/asset/uploadGoogleDriveFile', { method: 'POST', body: form })
.then(response => response.json())
.then(responseText => {
console.log(responseText)
if (responseText.error) {
this.uppy.setFileState(uppyFile.id, {
error: responseText.error.message
})
this.uppy.info(`${uppyFile.name} failed to upload: ${responseText.error.message}`, 'error')
reject()
} else {
this.uppy.setFileState(uppyFile.id, {
progress: {
bytesUploaded: uppyFile.size,
percentage: 100,
uploadComplete: true,
}
})
// update total/overall upload progress
const filesCompleted = this.uppy.getFiles().filter(file => file.progress.uploadComplete).length
const numFiles = this.uppy.getFiles().length
this.uppy.setState({
totalProgress: Math.round(filesCompleted / numFiles * 100)
})
resolve()
}
})
.catch(error => {
console.error(error)
})
})
}
}
Hopefully this helps. Best of luck!