Post a file with urlFetchApp to a google web app - google-apps-script

I am trying to post any type of file using Google Apps Script to a web app but I am not familiar with doPost.
My code looks like this:
function call(){
var file = getFile('/2.html'); //gets a file from my Google Drive (no point in posting all the code here for that)
var options = {
'method' : 'post',
'payload' : {file : file}
};
var response = UrlFetchApp.fetch('https://script.google.com/macros/s/AKfycbx0aIU_XjOHPXh0P6y2dTMmvGpI6WAuac_Cq5BOGw7nDLRlodT-/exec',options)
Logger.log(response)
This seems to work, although I have read I need to base64 encode a file for it to work properly. That's something I don't really understand.
On the web app side I made a doPost(e) but no matter what I tried to do with 'e' I can't work out what kind of object it is and how to process it. All I want to do really is to save it to Google Drive.
You may be wondering why I am going to these lengths to post the file to disk via a web app when I could save it directly. The reason is I am trying to do the process asynchronously using UrlFetchApp.fetchAll() so I can speed up the process of writing many files to disk at once.

If variable file is of type File, Get Blob from File and base64 encode it:
var options = {
'method' : 'post',
'payload' : Utilities.base64EncodeWebSafe(file.getBlob().getBytes())
};
On receiver web -app, Decode it back:
const doPost = e => {
const file = DriveApp.createFile(
Utilities.newBlob(
Utilities.base64DecodeWebSafe(
e.postData.contents
)
)
)
}

Thanks to #TheMaster. I made some modifications to the code because it resulted in an error because a file name was needed. you'll need your own apps script web app url to go here [APPS SCRIPT WEB APP URL]:
const doPost = e => {
const file = DriveApp.createFile(
Utilities.newBlob(
Utilities.base64DecodeWebSafe(
e.parameter.file
),e.parameter.contentType,e.parameter.fileName
)
)
}
function sendFile(file){
var fileName = file.getName();
var contentType = file.getBlob().getContentType();
var url = "[APPS SCRIPT WEB APP URL]";
var payload = {
fileName: fileName,
contentType : contentType,
file: Utilities.base64EncodeWebSafe(file.getBlob().getBytes())
};
var options = {
method: "POST",
payload: payload,
muteHttpExceptions : true,
};
var res = UrlFetchApp.fetch(url, options).getContentText();
}

Related

Adding a doPost and doGet into google app script ("GAS") code

I am a total newbie when it comes to programming.
I have put a very simple switchbot script into google app script ("GAS") to make the switchbot bot do a press. While it can run when clicking on the "run" button in GAS, when sending a http post (i.e. via android's HTTP Shortcut app) to GAS, it connects but the action fails.
I do understand later that a doPost or doGet is required to run it when sending a post to the script from an external source, but after trying various methods with doPost and doGet, I still have no idea how to integrate it or where to put it into the code.
The code is below:
function main() {
var headers = {
"Authorization" : "SWITCHBOT_TOKEN_KEY",
"Content-type" : "application/json; charset=utf-8"
};
var data = {
"command" : "press",
"parameter" : "default",
"commandType": "command"
};
var options = {
'method' : 'post',
"headers" : headers,
muteHttpExceptions : true,
"payload" : JSON.stringify(data)
};
var deviceid = "INSERT_SWITCHBOT_DEVICEID";
var url1 = https://api.switch-bot.com/v1.0/devices/${deviceid}/commands;
var response = UrlFetchApp.fetch( url1, options );
var json = JSON.parse( response.getContentText() );
console.log( json )
}
Any assistance or lesson on how to do / understand this would be great!
Tried checking and looking at various codes with dePost and doGet and integrating it into the code but all seems not work.
While it connects to GAS via the deployed web app link, I am not able to get the actual script running. It simply logs it as failed in the GAS.

How to use Drive v3 in google app script?

I have the following code that I would like to use Drive v3 in App Script
function myFunction() {
let id = "<YOUR ODS FILE ID>";
let file = DriveApp.getFileById(id);
let fileBlob = file.getBlob();
newFile = {
name: "New File",
mimeType: "application/vnd.google-apps.spreadsheet"
}
try{
Drive.Files.create(newFile, fileBlob);
}catch(e){
Logger.log("Error");
Logger.log(e);
}
}
However by default the google app script only makes v2 available. The documentation does not seem so easy to do this migration directly in App Script.
How can I use Drive v3 in this code directly in the google app script?
I believe your goal as follows.
You want to convert the file of let file = DriveApp.getFileById(id) (ODS file from let id = "<YOUR ODS FILE ID>") as Google Spreadsheet.
You want to achieve this using Drive API v3 with UrlFetchApp of Google Apps Script.
Modification points:
Although, unfortunately, I'm not sure about the file size of let file = DriveApp.getFileById(id) from your question, I think that in your situation, the file content is required to be sent as multipart/form-data. Ref
At Advanced Google services, this multipart/form-data is achieved at the internal server side. But, when you want to achieve this using UrlFetchApp, it is required to create the request body.
When above points are reflected to the sample script, it becomes as follows.
Sample script:
In this case, Drive API is used. So please enable Drive API at Advanced Google services.
function myFunction() {
const fileId = "<YOUR ODS FILE ID>"; // Please set the file ID.
const metadata = {
name: "New File",
mimeType: MimeType.GOOGLE_SHEETS,
// parents: ["### folder ID ###"], // If you want to put the converted Spreadsheet to the specific folder, please use this.
};
const payload = {
metadata: Utilities.newBlob(JSON.stringify(metadata), "application/json"),
file: DriveApp.getFileById(fileId).getBlob(),
};
const options = {
method: "post",
payload: payload,
headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() },
};
const url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart"
const res = UrlFetchApp.fetch(url, options).getContentText();
console.log(res);
// DriveApp.createFile(blob) // This is used for automatically detecting the scope of "https://www.googleapis.com/auth/drive".
}
Note:
At uploadType=multipart method, the official document says as follows.
Use this upload type to quickly transfer a small file (5 MB or less) and metadata that describes the file, in a single request.
When you want to use the file more than 5 MB for this, please use the resumable upload. Ref
By the way, in your script, it seems that the ODF file on your Google Drive is used. In this case, you can also achieve your goal using the method of "Files: copy" in Drive API v3. The sample script is as follows.
function myFunction2() {
const fileId = "<YOUR ODS FILE ID>"; // Please set the file ID.
const url = `https://www.googleapis.com/drive/v3/files/${fileId}/copy`;
const params = {
method: "post",
headers: {authorization: `Bearer ${ScriptApp.getOAuthToken()}`},
contentType: "application/json",
payload: JSON.stringify({name: "New name", mimeType: MimeType.GOOGLE_SHEETS})
};
const res = UrlFetchApp.fetch(url, params);
console.log(res.getContentText())
}
References:
Files: create
Upload file data
fetch(url, params)
Files: copy

Is there a way to convert API PDF Code response into PDF in Google App Script?

Using API I can obtain the PDF Coding for the invoice - in python I could write this response string directly in pdf and create therefore formatted document.
Is there a way to write this PDF code into PDF in google app script and get pdf formatted file?
Python Code Example (I need the same in google app script)
for list_invoice in list_invoices['invoices']:
response = requests.get('https://books.zoho.com/api/v3/invoices/'+str(list_invoice['invoice_id'])+'?organization_id=41285962&accept=pdf',
headers = {
"Content-Type" : "application/x-www-form-urlencoded;charset=UTF-8",
"Authorization" : "Zoho-oauthtoken "+authoken
}
)
#getting pdf response - writing pdf encoding and making respective pdf invoice on the desktop
with open('/Users/office/Desktop/'+str(invoice_number_hellocash_zoho)+'.pdf', 'wb') as f:
f.write(response.content)
Here is the google app script.
I get the error - Conversion from text/plain to application/pdf failed.
var url = 'https://books.zoho.com/api/v3/invoices/'+invoice_data+'?organization_id=41285962&accept=pdf';
var data = {
"Content-Type" : "application/x-www-form-urlencoded;charset=UTF-8",
"Authorization" : "Zoho-oauthtoken "+refresh_token_correct
}
var options = { "method":"GET",
"headers" : data
};
var pdf_encoded_response = UrlFetchApp.fetch(url, options);
var pdf_encoded_response_content = pdf_encoded_response.getContentText();
var pdfContent = pdf_encoded_response_content;
var intermediate = DriveApp.createFile('tempFile',pdfContent,MimeType.PLAIN_TEXT);
var blob = intermediate.getAs(MimeType.PDF);
Logger.log(blob.getContentType());
var pdfFile = DriveApp.createFile(blob);
DriveApp.getFileById(intermediate.getId()).setTrashed(true);

Google Spreadsheet Script: UrlFetchApp upload string as file

I saw this SO thread to upload a file using UrlFetchApp.
Also I saw this SO thread to post a string as file in python requests (without having a file or creating a temp file).
I want to send a string as file in Google Spreadsheet Script, and based on the two threads above I think it should be possible to do it without creating a temp file in google drive.
My question is how in Google Spreadsheet Script I can pretend the string is coming from a file and pass it to UrlFetchApp?
Here is the base code I am working on:
var string = 'test';
var url = "https://api.telegram.org/.../sendDocument";
var chat_id = "12345";
var data = {'chat_id': chat_id,
'text':text} ;
var headers = { "Accept":"application/json",
"Content-Type":"application/json"
};
var options = { "method":"POST",
"headers": headers,
"payload" : payload
};
var response = UrlFetchApp.fetch(url, options);
Here is how I got it right to post a string as file:
var url = "https://api.telegram.org/.../sendDocument";
var blob = Utilities.newBlob('Test!', 'text/plain', 'report.txt');
var data = {
'chat_id' : '12345',
'document': blob
};
var options = {
'method' : 'POST',
'payload' : data,
};
UrlFetchApp.fetch(url, options);
Thanks to comment from #Jack Brown and google developer example for posting blobs (example titled: Make a POST request with form data.).

Google Script UrlFetchApp.fetch returns a 404 eventhough the page exist

I am sending automated report with Google spreadsheet and Google script.
So far it was working perfectly. But somehow when I try to create a new report to be emailed, the function "UrlFetchApp.fetch" return a 404. The same situation happened when I tried copying the old report.
The line with "UrlFetchApp.fetch" give me this error:
Request failed for https://docs.google.com/spreadsheets/d/1qm_bCKn4MbLKy7AIuIeu7bTZcTk8ObYBln0GAxwfsX8/pub?gid=195635557&single=true&output=pdf returned code 404. Truncated server response
It seems that I am not the only one having the issue but I cannot find any solution to it.
Here is the code:
function emailSpreadsheetAsCSV() {
var ss = SpreadsheetApp.openById("1qm_bCKn4MbLKy7AIuIeu7bTZcTk8ObYBln0GAxwfsX8");
var url = ss.getUrl();
url = url.replace(/edit$/,'');
var token = ScriptApp.getOAuthToken();
var sheets = ss.getSheets();
//make an empty array to hold your fetched blobs
var blobs = [];
for (var i=0; i<sheets.length; i++) {
var response = UrlFetchApp.fetch("https://docs.google.com/spreadsheets/d/1qm_bCKn4MbLKy7AIuIeu7bTZcTk8ObYBln0GAxwfsX8/pub?gid=195635557&single=true&output=pdf", {
headers: {
'Authorization': 'Bearer ' + token
},
'muteHttpExceptions': false
});
//convert the response to a blob and store in our array
blobs[i] = response.getBlob().setName(sheets[i].getName() + '.csv');
}
//create new blob that is a zip file containing our blob array
var zipBlob = Utilities.zip(blobs).setName(ss.getName() + '.zip');
return blobs[0];
}
Thanks a lot for your help.
Aymeric.
I've gotten this problem too and after some research, Spence Easton (question 34573295) solved my issue. I simply added this bogus call to drive so access is granted, and so the script can now get to your file.
Add this near the top before trying to grab the url:
var bogus = DriveApp.getRootFolder();
Now it runs fine with no 404 errors.
Remove the headers from the request:
var response = UrlFetchApp.fetch("https://docs.google.com/spreadsheets/d/1qm_bCKn4MbLKy7AIuIeu7bTZcTk8ObYBln0GAxwfsX8/pub?gid=195635557&single=true&output=pdf", {
'muteHttpExceptions': false
});
Check if it works for you.
You use the "pub" url so are you sure the spreadsheet is published on the web ? If you get a 404 it means the page is not published.
If file is published the bearer is not necessary as it is public now.
After I don't really understand your code because you iterate all the sheets of your file
for (var i=0; i<sheets.length; i++)
but the param "gid" (pub?gid=195635557&single=true&output=pdf) for the url in your urlfetch is fixed ?
Second point you get the file as pdf and after you create a csv ?
Why not get the file as csv directly : https://docs.google.com/spreadsheets/export?id=TheIdOfTheFile&exportFormat=csv
By adapting this code you can get the csv directly, see : https://stackoverflow.com/a/28503601/3556215
Take care you will get the first page and not others.
Stéphane
Try with:
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(res.getContentText());