Send form data to Google Spreadsheet from client side - html

I have some form on my pure JS/HTML/CSS site (without server side). And have Google account. My purpose is send filled form from web client direct to Google Spreadsheet. Is it possible?

Yes, this is possible. I would do it by creating an Apps Script and deploying it as a web app. Here is a sample script: fill in the Id of the spreadsheet and the name of one of its sheets.
function doPost(event) {
var params = event.parameter;
var sheet = SpreadsheetApp.openById('..Id..').getSheetByName('..Name..');
if (params.data !== undefined) {
sheet.getRange(1, 1).setValue(params.data);
return ContentService.createTextOutput("Success");
}
else {
return ContentService.createTextOutput("Oops");
}
}
Publish the script as a web app, allowing access to everyone (unless you want to deal with authentification). This will give you a URL such as https://script.google.com/macros/s/..../exec
On the client side, you send POST request to that URL. The script expects data to be in parameter "data".
var url = 'https://script.google.com/macros/s/..../exec';
$.post(url, {data: 'hello world'});
(I'm using jQuery here just to have a shorter example; you can send a POST request in plain JavaScript.)
The cell A1 of the sheet you chose will have "hello world".

Related

Google app script runs in debug mode, not in run mode

Hello Google Script experts, I'm new to google script and trying something related to HTTP POST from google docs.
I've a google app script that sends a post request (API) on opening a google doc.
function onOpen() {
var ui = DocumentApp.getUi(); // Same variations.
var actDoc = DocumentApp.getActiveDocument();
var docID = actDoc.getId();
var repeater = 0;
var data = {
'bstask': text,
'docid': docID
};
console.log(data);
var options = {
'method' : 'post',
'contentType': 'application/json',
// Convert the JavaScript object to a JSON string.
'payload' : JSON.stringify(data)
};
ui.alert("Sending request with the payload" + data.bstask + " and " + data.docid);
var response = UrlFetchApp.fetch('https://test.com/path', options);
ui.alert("Response is: " + response.getResponseCode());
if (response.getResponseCode() == 200) {
Logger.log(response.getContentText() + response.getAllHeaders());
ui.alert('Yey!! Document refreshed.');
}
else{
ui.alert('Opps!! Document refresh failed.'+ response.getContent());
}
}
This script is used to provide an option to the user to update the document when it is opened or refreshed. This script runs fine and invoking the API when I test it in debug mode. But, when I want this script to be executed on opening the document, it is not invoking the API and the rest of the UI prompts are working fine. Am I missing something here or something wrong with the script? I really appreciate any help!!
Simple Triggers – Restrictions
Because simple triggers fire automatically, without asking the user for authorization, they are subject to several restrictions:
They cannot access services that require authorization. For example, a simple trigger cannot send an email because the Gmail service requires authorization, but a simple trigger can translate a phrase with the Language service, which is anonymous.
In other words, the UrlFetchApp.fetch() call will not execute when opening the document because it requires authorization. You should be able to see this failure in the execution logs as well.

Google forms approval workflow

I'm trying to set up a workflow using Google Forms, Sheets and Apps Script. For a simple example lets say I am setting up a leave form for a company. I have a form for the employee enters their leave details. On submit the details are populated into a sheet and an email is sent to an someone for approval.
This is where I am getting stuck. What is the best way to approve the leave requests? I can just edit the sheet and once the column has been changed from unapproved to approved and email could be sent but I was hoping to avoid having to edit the sheet at all.
Is there a better way to handle this workflow?
Assume that 3 people need to approve the request. The approvers that need to review the request are approvers X,Y,Z.
User X gets an Email requesting that they review the request
The email that user X gets will use HTML
The HTML will have a link in it
A link in HTML submits a GET request
Whenever you click a link, or enter a url into the browser address
bar, a GET request is made to the url
An Apps Script Web App is an Apps Script project that is published as
a Web App
A Web App has a url that can be used to make a request to it
When the url (link) is used, a GET request is made
A GET request made to an Apps Script Web App will run the doGet()
function
Once that doGet() function run, you can have your Apps Script code do
anything that you want
It can get information sent in to it from a search string
Then send out another email to user Y
So, when user X clicks the link, the url needs to have information
appended to the url in the form of a search string
httpz://the link?whichUser=X&approved=true
You can get the user and whether it was approved or not from the "event object" often designated by the letter "e"
function doGet(e) {
var whatUserJustReviewed,isItApproved;
//Get the values passed in from "e" which is the event object
eventParam = e.parameter;
whatUserJustReviewed = eventParam.whichUser;
Logger.log(' whatUserJustReviewed : ' + whatUserJustReviewed )
isItApproved = eventParam. approved;
switch (whatUserJustReviewed) {
case "X"
if (isItApproved === 'true') {
// //Send an email to the next user which is Y
}
break;
case "Y"
if (isItApproved === 'true') {
// //Send an email to the next user which is Z
}
break;
case "Z"
if (isItApproved === 'true') {
//Send an email to all involved who need to know that it was approved.
}
break;
default:
console.error('There was an error getting user or status');
};
}

Google Spreadsheets as JSON

I want to know if and how is it possible to get data from specific cells of a Google spreadsheet without publishing the sheet as public using HTTP GET request to fetch data in JSON format.
I am not totally sure if this is what you are looking for, but you could just create a doGet() that returns a JSON object and then publish your project as a Webapp. Then make get requests to that URL.
function doGet() {
var cell = SpreadsheetApp
.openById('SPREADSHEET ID HERE')
.getActiveSheet()
.getRange('A1')
.getValue();
var stringified = JSON.stringify({cellValue: cell});
return ContentService.createTextOutput(stringified);
}
EDIT: You could even put in some URL parameters and make it return specific cells. Read more here.

Use Google Script's Web App as Webhook to receive Push Notification directly

My Goal: Changes in Google Drive => Push Notification to https://script.google.com/a/macros/my-domain/... => App is pushed to take action.
I don't want to setup an middle Webhook agent for receiving notification. Instead, let the Web App (by Google Script) to receive it and be pushed directly.
Since the relevant function is quite undocumented (just here: https://developers.google.com/drive/web/push) , below is the code I tried but failure.
1. Is above idea feasible??
2. My code doPost(R) seems cannot receive notification (R parameter) properly. Anyway, no response after I change the Google Drive. Any problem? (I have tried to log the input parameter R so as to see its real structure and decide if the parameter Obj for OAuth is the same as normal Drive App, but error occur before log)
function SetWatchByOnce(){
var Channel = {
'address': 'https://script.google.com/a/macros/my-domain/.../exec',
'type': 'web_hook',
'id': 'my-UUID'
};
var Result = Drive.Changes.watch(Channel);
...
}
function doPost(R) {
var SysEmail = "My Email";
MailApp.sendEmail(SysEmail, 'Testing ', 'Successfully to received Push Notification');
var Response = JSON.parse(R.parameters);
if (Response.kind == "drive#add") {
var FileId = Response.fileId;
MyFile = DriveApp.getFolderById(FileId);
...
}
}
function doGet(e) {
var HTMLToOutput;
var SysEmail = "My Email";
if (e.parameters.kind) {
//I think this part is not needed, since Push Notification by Drive is via Post, not Get. I should use onPost() to receive it. Right?
} else if (e.parameters.code) {
getAndStoreAccessToken(e.parameters.code);
HTMLToOutput = '<html><h1>App is successfully installed.</h1></html>';
} else { //we are starting from scratch or resetting
HTMLToOutput = "<html><h1>Install this App now...!</h1><a href='" + getURLForAuthorization() + "'>click here to start</a></html>";
}
return HtmlService.createHtmlOutput(HTMLToOutput);
}
....
Cloud Functions HTTP trigger(s) might also be an option ...
(which not yet existed at time of this question). this just requires setting the trigger URL as the notification URL, in the Google Drive settings - and adding some NodeJS code for the trigger; whatever it shall do. one can eg. send emails and/or FCM push notifications alike that. that trigger could also be triggered from App Script, with UrlFetchApp and there is the App Script API. one can have several triggers, which are performing different tasks (App Script is only one possibilty).
Cicada,
We have done similar functions to receive webhooks/API calls many times. Notes:
to get R, you need: var Response = R.parameters and then you can do Response.kind, Response.id, etc.
Logger will not work with doGet() and doPost(). I set it up a write to spreadsheet -- before any serious code. That way I know if it is getting triggered.

Google Apps Script - Handling Result from UrlFetchApp.fetch()

I have a spreadsheet that I only want users to modify by running a script. The script is a UiApp that has a few pre-defined input fields and text boxes and the results are submitted onto the spreadsheet. Because I only want the document modified from this app, I have to set the permissions of the spreadsheet to "Can comment." However, in doing this, the users cannot run the script (because the script edits the page and they don't have editing rights to the page). So I assume that I need to create a web app.
The web app would be stand-alone and would run as me (the owner) so that calls to the app would allow the submitted data to be written to the spreadsheet. My web app looks something like this:
function doGet() {
var app = UiApp.createApplication();
// UiApp elements are added here
return app;
}
...and the works fine when the url is accessed directly from the browser. However, I would like for the app to open w/i the spreadsheet from a spreadsheet trigger. I was thinking something like this:
var app = UrlFetchApp.fetch(url);
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.show(app);
...but this is not working. The error I get is: "Invalid argument: userInterface (line 12, file "Web App")." Line 12 is "ss.show(app)." I was hoping that the app object would be returned from UrlFetch, but I now know that an HTTPResponse is returned.
How can I convert this response into a UiApp object? Thanks.
The solution I came up with was to have the UiApp open on the spreadsheet (from a trigger) and have the user choose the drop-downs and complete the text boxes. Upon clicking the submit button, the handler function would take all of the parameters and create a payload. Then this payload was passed to a doPost(e) stand-alone web app. Because I passed the ssid, the web app was able to locate the spreadsheet/sheet/range and write/format the data in a certain way. Here is my code:
var payload = {
"ssid" : ssid,
"sheetName" : sheetName,
"row" : row,
"col" : col,
"method" : method,
"strategy" : strategy,
"summary" : summary,
};
var options = {
"method" : "post",
"payload" : payload
};
UrlFetchApp.fetch(url, options);
This way the users can input the information in a certain format without having editing rights to the sheet.