I'm working with the google node api. I am trying to do the following:
- Read the contents of a google drive spreadsheet
- Interpret some of the data (I convert the csv to an object using node-csv)
- Then upload the file with the new contents
I have working code that does all of this, I'll share it in a minute.
The problem is the code can only read a spreadsheet file from google drive when I create it in google drive, when I update the file it's unreadable from the API (works in google drive itself). So the steps listed above work, then when I run it again the updated file is "not found". Note I'm not changing the id of the file at all.
Here's some code, drive.files
and csv
are being processed with Promises Bluebird's promisifyAll()
function which adds the Async
promise functions to the library.
function getDriveFile(drive, id){
return drive.files.getAsync({ fileId: id })
.spread(function(data, response){
console.log(data)
return data.exportLinks['text/csv']
}).then(function(csvDownload){
return request({
"method":"GET",
"url": csvDownload,
"qs":{
"exportFormat": "csv",
"key": id,
"gid": 0
},
"headers":{
"Authorization": "Bearer " + drive._options.auth.credentials.access_token
}
}).spread(function(response, body){
return body
})
})
}
function driveGetAndParse(drive, fileId, fileName){
return getDriveFile(drive, fileId).then(function(file){
if(file.match("<!DOCTYPE html>")) throw new Error(fileName + " is not found")
debug("fetched google drive %s doc", fileName)
return csv.parseAsync(file, {columns: true})
})
}
driveGetAndParse(drive, docId, "My super special doc"),
// one function that updates the file if there's and ID else inserts
function upload(drive, item){
if(item.title) debug("uploading file '%s' to google drive", item.title)
var options = {
addParents: uloadparent,
newRevision: false,
convert: true,
media: {
mimeType: 'text/csv',
body: item.content,
}
}
if(item.id) options.fileId = item.id
if(item.title) options.resourcetitle = item.title
if(options.fileId){
return drive.files.updateAsync(options)
.spread(function(data, response){
return data
})
}else{
return drive.files.insertAsync(options)
.spread(function(data, response){
return data
})
}
}
The only real difference in the admin between the two files is that the uploaded doc has no extra cells it's just the cells with content that were uploaded.
If your thinking it's a permissions problem, right? Works in google drive but not the API. I was thinking the same.
To be clear, I can get the files information using drive.files.get
I just can't download the file itself using the data.exportLinks['text/csv']
.
I retrieved the files metadata before and after the upload, the readable downloadable and the undownloadable file. Here's the diff between those two responses.
I'm unsure if this is a problem with them way I'm uploading, or a problem with the way I'm downloading.
There is a download link, and when I'm logged into google drive and drop it in the browser I can download the file just fine.
Attempts:
- I just tried to add
options.media.mimeType = "application/vnd.google-apps.spreadsheet"
for updating, thinking that it might be an issue with setting an existing doc totext/csv
. - Tried the same thing with
options.convert = false
thinking that it is converting an already-existing document.
Update:
If I revert the file back using google drive I can read the file again. Progress? Something must be wrong with the file contents / API itself?
Code change:
I split the insert
/ update
functions and have them intersect at upload
.
function insert(drive, item){
debug("inserting google drive file")
return drive.files.insertAsync({
addParents: uloadparent,
newRevision: false,
convert: true,
media: {
mimeType: 'text/csv',
body: item.content,
}
}).spread(function(data, response){
return data
})
}
function update(drive, item){
debug("updating google drive file")
return drive.files.updateAsync({
fileId: item.id,
addParents: uloadparent,
newRevision: false,
convert: true,
media: {
mimeType: 'text/csv',
body: item.content,
}
}).spread(function(data, response){
return data
})
}
function upload(drive, item){
if(item.title) debug("uploading %s", item.title)
if(item.id) return update(drive, item)
return insert(drive, item)
}