I have uploaded a pdf file successfully to drive using a node server. However, I can not find a way to convert it to the google doc format so that it can be downloaded later as a docx document.
here is my actual code:
const fileMetadata = {
'name': 'new file.pdf',
//'mimeType': 'application/vnd.google-apps.document'
// trying to create it as a google doc directly does
// not work either
};
const media = {
mimeType: 'application/pdf',
body: fs.createReadStream(pdf)
};
drive.files.create({
resource: fileMetadata,
media,
fields: 'id'
}, (err, createdFile) => {
if (err) {
console.error(err);
} else {
// ------- COPY AS GOOGLE DOC
drive.files.copy({
fileId: createdFile.data.id,
requestBody:{
mimeType:'application/vnd.google-apps.document'
}
}, (err, googleDocFiles) => {
if (err) {
console.log(err)
// GaxiosError: Bad Request
// error: [
// { domain: 'global', reason: 'badRequest', message: 'Bad Request' } ]
} else {
console.log(googleDocFiles)
}
})
}});
What i have tried
using the files.upload method with the same requestBody returns a 200 response, however the pdf is unchanged
I know is possible, I did it before, using the copy method however now it not working and I have no clue why *sigh
EDIT
The mimeType in the request body is responsible for the 400 error, that is very weird since I am following the steps in the documentation here:
Import to Google Docs types section
this section is explicit about importing a CSV, however in the box under that section says that I can convert a pdf to doc using the corresponding mime type
I re-installed the package and it work
Related
I am currently using imagepicker on react native. When I use android to pick image it works fine. However when I use iOS it crashes when I choose a photo.
This is the error it shows in xcode debugger:
2020-04-03 11:54:27.802434+0800 app[7218:1993193] -[NSURLResponse allHeaderFields]: unrecognized selector sent to instance 0x28281aba0
2020-04-03 11:54:27.802766+0800 app[7218:1993193] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURLResponse allHeaderFields]: unrecognized selector sent to instance 0x28281aba0'
* First throw call stack:
(0x19d01c164 0x19cd30c1c 0x19cf1a7e0 0x19d02085c 0x19d022b60 0x102b27bc8 0x102b27a90 0x102b01ce0 0x1059f5d10 0x1059f718c 0x1059fe968 0x1059ff580 0x105a0b0f0 0x19cd23714 0x19cd299c8)
libc++abi.dylib: terminating with uncaught exception of type NSException
and this is my code:
chooseImage = async (id) => {
//await this.askPermissionsAsync();
let options = {
title: 'Select Image',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response.error);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else {
const source = { uri: response.uri };
// You can also display the image using data:
// const source = { uri: 'data:image/jpeg;base64,' + response.data };
// alert(JSON.stringify(response));
let file_data = [...this.state.fileData];
file_data[id] = response.data;
let file_uri = [...this.state.fileUri];
file_uri[id] = response.uri;
this.setState({filePath:response, fileData: file_data, fileUri: file_uri});
}
});
}
I have also added the permissions in info.plist:
<key>NSCameraUsageDescription</key>
<string></string>
<key>NSPhotoLibraryUsageDescription</key>
<string></string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string></string>
<key>NSDocumentsFolderUsageDescription</key>
<string></string>
but the problem still persist in ios.
The issue was
'data:image/jpeg;base64,' + this.state.fileData[id]
while rendering it on Image tag.
This issue is indicated here:
YellowBox Crash
Image Crash with data:image/png;base64
The solution I did was to add "noData: true" on option and access directly the URI file location in the image tag.
Hope this helps
react-native link did not link the library, so the mage picker lib did not build with the app. Thats why I as getting null pointer exception because there was no lib.
Or else manually add the library.
<key>NSCameraUsageDescription</key>
<string>Access to take a photo by camera</string>
<key>NSAppleMusicUsageDescription</key>
<string>Access to pick a photo</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Access to pick a photo</string>
I'm trying to upload a file to the server using react-native-document-picker. The problem I'm facing is I don't know how to upload the file along with a text.In my app there is a portion for file upload also there is an area for writing some text.Then it will get uploaded to the server.So I've done the following.But I'm getting this error after submitting to server
unhandled promise rejection unsupported BodyInit type
updated portion of code
filepick = () => {
DocumentPicker.show({
filetype: [DocumentPickerUtil.images()],
}, (error, res) => {
if (error == null) {
console.log(
res.uri,
res.type, // mime type
res.fileName,
res.fileSize
);
this.setState({
img_uri: res.uri,
img_type: res.type,
img_name: res.fileName
})
} else {
Alert.alert('Message', 'File uploaded failed');
}
});
};
onPressSubmit() {
const data = new FormData();
data.append('file', { uri: this.state.img_uri, type:
this.state.img_type, name: this.state.img_name })
data.append('comment', { text: this.state.text });
AsyncStorage.getItem("userdetail").then(value => {
fetch(GLOBAL.ASSN_URL +`${this.props.id}`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
'Authorization': value
},
body: data
}).then((response) => {
return response.text()
}).then((responseJson) => {
var result = responseJson;
console.log(result);
});
})
}
The function filepick() is called after choosing a file from your device.Please help me to find a solution.How do I upload this to server also how to send text without stringifying it?
body: ({
file: this.state.file,
comment: this.state.text
})
Why are you wrapping body in brackets? Removing them might fix it.
Also see this, https://github.com/facebook/react-native/issues/6025 you might want to stringify the body object, since your content type is not application/json
body: JSON.stringify({
file: this.state.file,
comment: this.state.text
})
Edit
From comments we now know the following
1) You are uploading a file separately.
2) The upload response contains information about the file
3) You are saving the entity in separate server call
4) You need to save file with that entity
The solution below assumes that you have full control over server and you are also handling the file uploading endpoint. Here is the solution
You basically do not need to upload the whole file again with your entity since it is already uploaded on server, all you need to do is to save the reference of the file with entity. Their are two ways to save the reference
1) Just save either the fileName or fileUrl in your entity table and then store the name or url with entity so it will look like this
{
id: 1,
name: 'Cat',
picture: // url or name of picture
}
2) Save the uploaded file in different table, then save the id of the file with your entity, and when you fetch entities get the related file. However if the relationship between entity and file is one to many as in one entity can have many files then you will first need to save the entity and then upload the files with reference of entity. This way your entity will look like this
{
id: 1,
name: 'Cat',
pictures: [{fileName: 'cat1'}, {fileName: 'cat2'}]
}
I'm trying to sent an audio blob on some Google drive folder. To succeed I translate blob in file before sending it.
I received since the starting an error :
Error: File not found.
code: 404, errors: [ { domain: 'global',
reason: 'notFound',
message: 'File not found: 1aazd544z3FOCAsdOA5E7XcOaS3297sU.',
locationType: 'parameter',
location: 'fileId' } ] }
progressive edit : So far I have converted my audio blob in base64 string in order to ease the processing of my blob.
But, I fail always to write a file with my base 64 audio blob :
Here my driveApi.js :
// request data from req.body
var data = req.body.data ; // data variable is presented in form of base64 string
var name = req.body.word ;
(...)
// WRITE FILE AND STORE IT IN BODY HEADER PROPERTY
body: fs.writeFile((name + ".mp3"), data.substr(data.indexOf(',')+1), {encoding: 'base64'}, function(err) {
console.log('File created')
})
Three steps: create a temporary file with your base64 data out of the drive.files.create function, then give this file a specific name -e.g. tempFile, also you can customize this name with a time value. After that, pass this file on a "fs.createReadStream" method to upload it on Google drive.
Some hints:
Firstly - use path.join(__dirname, name + "-" + Date.now() +".ext" ) to create to file name
Secondly - make this process asynchronously to avoid data flow conflict (trying to create file before file is created), so call the drive.files.create after having setting a fs.writeFile function.
Thirdly - Destroy the tempFile after the operation has been done. It allows you to automatize the process.
I let you dive in the methods you need. But basically fs should do the job.
Again, be careful on the data flow and use callback to control it. Your code can crash just because the function gone up in a no-operational way.
Some links :
https://nodejs.org/api/path.html
https://nodejs.org/api/fs.html#fs_fs_writefile_file_data_options_callback
here an instance :
// datavalue = some time value
fs.writeFile(
path.join(__dirname, name + "-" + datevalues +".mp3" ),
data.substr(data.indexOf(',')+1),
{encoding: 'base64'},
// callback
function(err) {
if(err){ console.log("error writting file : " + err)}
console.log('File created')
console.log("WRITTING") // control data flow
fileCreate(name)
})
function fileCreate (name){
// upload file in specific folder
var folderId = "someID";
var fileMetadata = {
'name': name + ".mp3" ,
parents: [folderId]
}; console.log("MEDIA") // control data flow
var media = {
mimeType: 'audio/mp3',
body: fs.createReadStream(path.join(__dirname, name + "-" + datevalues +".mp3" ))
};
drive.files.create({
auth: jwToken,
resource: fileMetadata,
media: media,
fields: 'id'
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file.data.id);
}
// make a callback to a deleteFile() function // I let you search for it
});
}
How about this modification? I'm not sure the condition of blob from reactApp.js. So could you please try to use this modification? In this modification, file or blob from reactApp.js are used.
Modified script :
var stream = require('stream'); // Added
module.exports.uploadFile = function(req){
var file ;
console.log("driveApi upload reached")
function blobToFile(req){
file = req.body.blob
//A Blob() is almost a File() - it's just missing the two properties below which we will add
file.lastModifiedDate = new Date();
file.name = req.body.word;
return file;
}
var bufStream = new stream.PassThrough(); // Added
bufStream.end(file); // Or bufStream.end(### blob from reactApp.js ###) Added
console.log(typeof 42);
// upload file in specific folder
var folderId = "1aa1DD993FOCADXUDNJKLfzfXcOaS3297sU";
var fileMetadata = {
"name": req.body.word,
parents: [folderId]
}
var media = {
mimeType: "audio/mp3",
body: bufStream // Modified
}
drive.files.create({
auth: jwToken,
resource: fileMetadata,
media: media,
fields: "id"
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log("File Id: ", file.id);
}
console.log("driveApi upload accomplished")
});
}
If this didn't work, I'm sorry.
To preface, I have Google Cloud Print working through apps script. I have OAuth2 setup, and I was able to setup a Cloud Print API that prints a single file in my Google Drive to a printer on my Cloud Print.
With that said, I'm looking for a way to automate my script so that when a document gets placed in a specific folder on my Google Drive, it will print automatically. I've searched around and was unable to find anything similar. Here's my starting point (which was found here from a very helpful tutorial):
function printGoogleDocument(docId, docTitle) {
// For notes on ticket options see https://developers.google.com/cloud-print/docs/cdd?hl=en
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR"
},
duplex: {
type: "NO_DUPLEX"
},
}
};
var payload = {
"printerid": myPrinterId,
"content": docId,
"title": docTitle,
"contentType": "google.kix", // allows you to print google docs
"ticket": JSON.stringify(ticket),
};
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
method: "POST",
payload: payload,
headers: {
Authorization: 'Bearer ' + getCloudPrintService().getAccessToken()
},
"muteHttpExceptions": true
});
// If successful, should show a job here: https://www.google.com/cloudprint/#jobs
response = JSON.parse(response);
if (response.success) {
Logger.log("%s", response.message);
} else {
Logger.log("Error Code: %s %s", response.errorCode, response.message);
}
return response;
}
So when I fill in my docID and PrinterID, it works fine for a single document. But like I said, I'm trying to automate this based on new files in a Drive folder. Any suggestions?
I'm trying to use the Google API NodeJS client to upload a Google Apps Script to my drive. I am following the directions in the docs, but when the file gets uploaded to my drive, I can only upload it as plain text and not as an Apps Script.
function uploadAppScript(auth) {
return new Promise(function(resolve, reject) {
var drive = google.drive('v3')
drive.files.create({
auth: auth,
resource: {
name: 'myscript',
mimeType: 'application/vnd.google-apps.script'
},
media: {
mimeType: 'text/plain',
body: fs.createReadStream('src/myscript.gs')
},
}, function(err, result){
... //not relevant
})
})
}
The media uploads section of the README does not specify how to upload anything other than a png.
If I change the mimeType in the media object to anything other than text/plain I get the following (uninformative) error:
code: 400,
errors:
[ { domain: 'global',
reason: 'badRequest',
message: 'Bad Request' } ] }
Any ideas on how to get Drive to recognize this as an Apps Script and not a plain text file? Or is this something broken on the NodeJS client's end?
So this is apparently a bug with the google-api-nodejs-client but a maintainer of the library was able to assist me where the documentation could not. The following will allow you to upload a .gs file to Google Drive properly:
drive.files.create({
resource: {
name: 'myscript.gs',
mimeType: 'application/vnd.google-apps.script+json'
},
media: {
mimeType: 'application/vnd.google-apps.script+json',
body: JSON.stringify({
files: [
{
source: fs.readFileSync('src/myscript.gs', { encoding: 'utf-8' }),
name: 'myscript',
type: 'server_js'
}
]
})
}
}, function (err, file) {
// ...
});