how can I access HTTP GET variables in Google Apps Script? - google-apps-script

I am trying to access the HTTP GET variables in a Google Apps Script (Like PHPs $_GET).
I tried several techniques:
Plain java script (window.location), which obviously is not supported
Googles own Service through SitesApp.getActivePage().getUrl(). Gives
me the URL, but without the variable string. On second thought this
might make sense.
e.parameter.[key] This gives me the following error: TypeError: Cannot read property "parameter" from undefined.
I'd really appreciate some pointers or a working example, thanks.
As per the comment from Srik I tried the following:
function doGet(e) {
UserProperties.setProperty("bottleid", e.parameter.id);
return HtmlService.createTemplateFromFile('showbottledata').evaluate();
}
Which gives me the mentioned
TypeError: Cannot read property "parameter" from undefined. (line 2)
error.

First, you need to define your doGet in such a way that it accepts URL parameters
function doGet(e) {
....
}
When you call your URL using URL parameters, say parm1=val1, use
var parm1 = e.parameter.parm1 ;

Related

Why is doGet() failing without posting logs?

I suppose my question is twofold: doGet() in the following context will just fail after 0.1~0.2 seconds without posting logs, so I have no idea how to troubleshoot it by myself. Additionally, if I'm having the script execute on my behalf, do I have to push a request with my authorization token to a more "pertinent" area than just the sheet name, such as within the iteration itself? Read further for more details:
I have a source spreadsheet where I am cross-referencing user inputted data to validate the information we have "on file". Most of our clients are over the age of 55, so I am trying to reduce end-user complexity by having the script run on my behalf whenever they need to use it (to bypass the Authorization screen, with the big scary "This application could be unsafe!" message). The way I've read to accomplish this seems to be with doGet(), so I set up a low-level HTTP Get request that just pushes a doGet() with my OAuth token, returning the sheet name. I also set up a masking function specifically to do this, and linked it to the button originally used for the iteration logic. The doGet() looks like this:
const doGet = e => {
Logger.log(`Recieved HTTP request.`);
const content = ContentService.createTextOutput(iterator(e));
Logger.log(content);
return content;
}
and the button that uses UrlFetchApp looks like:
const runMask = () => {
const active = SpreadsheetApp.getActiveSheet().getSheetName();
const v4 = 'https://script.google.com/macros/s/<scriptid>/dev' // ScriptApp.getService().getUrl() posts 404
UrlFetchApp.fetch(`${v4}?sheetName='${active}'`, {
headers: { Authorization: `Bearer ${ScriptApp.getOAuthToken()}` },
});
I have some logs set up within the real runMask() that proceed all the way to the end of the program, giving me real URLs and OAuth tokens, so I know it's making it through runMask() without an issue. However, the doGet() log doesn't post anything, even at the top of the function. I can see that it's executing the trigger in my execution log, but the log itself remains empty.
I've tried:
using ScriptApp.getService().getUrl() in place of v4: posts 404 in the log w/ truncated server response
replacing ${active} with the name of the sheet: same issue; logging ${active} also returns the correct name of the sheet.
Beyond this, I'm not even sure what to do. I have everything scoped correctly (auth/spreadsheets.currentonly, auth/script.external_request, and auth/userinfo.email), and I have no issues about operational security (as both the spreadsheet and script are written by me, the clients have no need to grant access to their entire drive). Before trying to implement doGet() and bypass the authorization screen, the iterator itself worked just fine. As such, I have chosen not to include it here, as it's hardly relevant (the function that executes the iteration function never makes it to that point).
I understand this has been quite the deluge of information; I'd be happy to provide more information or context as needed.
Getting ReferenceError: iterator is not defined (line 12, file "ag2")
With this:
const doGet = e => {
Logger.log(`Recieved HTTP request.`);
const content = ContentService.createTextOutput(iterator(e));
Logger.log(content);
return content;
}
Issued with url/exec?option=A
It runs with
const doGet = e => {
Logger.log(`Recieved HTTP request.`);
const content = ContentService.createTextOutput(JSON.stringify(e));
Logger.log(content);
return content;
}
and returns the appropriate stringified object
Only use the test URL (/dev) for testing the web app from a web browser.
Before doGet from a web browser using a versioned deployment (/exec) remember to publish a new version.
Assign a Google Cloud Project to your Google Apps Script project. For details see https://developers.google.com/apps-script/guides/cloud-platform-projects.
To make it easier to debug your avoid calling functions from a Google Apps Script method like createTextOutput, instead, assign the function result to a variable and use it as the method parameter, i.e. replace
const content = ContentService.createTextOutput(iterator(e));
by
const something = iterator(e);
const content = ContentService.createTextOutput(something);
For debugging purposes, create a function to call your doGet function, and check that it hasn't any problem to run, i.e.
function __test__doGet(){
const e = {
parameter: {}
}
doGet(e);
}
Related
Exception handling in google apps script web apps
Issue:
When I saw your question, I'm worried about I have everything scoped correctly (auth/spreadsheets.currentonly, auth/script.external_request, and auth/userinfo.email).
If you are using only the following scopes at oauthScopes of appsscript.json,
https://www.googleapis.com/auth/spreadsheets.currentonly
https://www.googleapis.com/auth/script.external_request
https://www.googleapis.com/auth/userinfo.email
Unfortunately, these scopes cannot be used for access to Web Apps. Although I'm not sure about the method for running your function of runMask, I thought that this might be the reason for your issue.
Solution:
If you want to access Web Apps of https://script.google.com/macros/s/<scriptid>/dev using the access token retrieved by ScriptApp.getOAuthToken(), please include the following scope.
https://www.googleapis.com/auth/drive.readonly
or
https://www.googleapis.com/auth/drive
After you include the above scope, please reauthorize the scopes, and test it again. When your function of iterator has already been declared and the script worked, by running runMask, you can see the log of Logger.log(Recieved HTTP request.) and Logger.log(content) at the log.
Reference:
Taking advantage of Web Apps with Google Apps Script

TypeError: this[e.parameter.run] is not a function

This is related to this thread. I don't know what the problem is since I'm just new with this coding thing. But I found the error when I clicked the latest code below the URL.
This is the error TypeError: this[e.parameter.run] is not a function (line 2, file "Code").
And, this is the code:
function doGet(e) {
this[e.parameter.run](e.parameter.sheetName || null); //this is line 2
return ContentService.createTextOutput();
}
Honestly, I don't know what that function does since I just copy it on this solution. But as far as I understand, it helps for the script to be accessible to other users. What seems to be the problem here?
Explanation
You function doGet(e) expects a parameter run to which the name of an (existing) function is assigned.
This paramter has to be appended to the WebApp URL
If you call the WebApp without assigning it any paramater (by pressing on latest code) the function will error
Instead, you need to copy the Current web app URL and append to it ?run=NameOfFunction
For example:
https://script.google.com/macros/s/XXXXXXXX/exec?run=myFunction
If your script contains a function called myFunction() - this function will be executed on pasting the full Web App URL including parameter run into the browser address bar.
Recomendation
Modify
return ContentService.createTextOutput();
to return ContentService.createTextOutput("It worked");
This will give you some feedback about the fact that the Web App has been executed correctly.

Cannot name get parameter 'pid' in google scripts get request

I want to pass a parameter to my google spreadsheet with a get request. The get parameter name is 'pid', which seems to make Google Sheets crash.
My example script just returns the get parameters to the client:
function doGet(e){
try {
return ContentService
.createTextOutput(JSON.stringify({"result":"your parameters", "parameters": e.parameter}))
.setMimeType(ContentService.MimeType.JSON);
} catch(ee){
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error message": ee}))
.setMimeType(ContentService.MimeType.JSON);
}
}
The following request works:
https://script.google.com/macros/s/<sheet-id-here>/exec?a=1
returns:
{"result":"your parameters","parameters":{"a":"1"}}
But simply changing the get parameter name returns an error:
https://script.google.com/macros/s/<sheet-id-here>/exec?pid=1
returns:
We're sorry, a server error occurred. Please wait a bit and try again.
Any idea what's going on here and how to fix this? Is this a bug? Is there a way to handle this on the server side (can't really change my client code)?
It seems Google has changed reserved parameters. As written in the documentation,
Warning: The following parameter names are reserved by the system and shouldn't be used in URL parameters or POST bodies:
c
sid
Using these parameters may result in an HTTP 405 response with the error message "Sorry, the file you have requested does not exist." If possible, update your script to use different parameter names.
It seems both c and sid parameters are valid now and pid parameter is reserved and throws
Sorry, unable to open the file at this time.
There doesn't seem to be anything that you can do server side.

How to use 'getBody()' on a Google document with a standalone script?

I want to do some text/paragraphs replacement in Google Docs that are automatically created by an add-on (autoCrat). I tried this successfully on a bound script but now that I want to try it on a standalone script, I get this error:
TypeError: Function getBody not found in the DOCUMENT-NAME object.
I don't understand.
Do I need to call a bound script from the standalone script or something like that?
(I hope not.)
The GAS documentation is not helping at all with this, at least with my understanding of what a standalone script is. Maybe it's a trivial error, but all the examples I found here are for bound scripts, which are not what I'm doing (I've already done a bound script and it's working fine).
This very simple code won't work for a standalone script and I don't understand why :
function Myfunction() {
var file = DriveApp.getFileById('doc-id');
var body = file.getBody();
Logger.log(body);
}
You are getting that error because the class returned by getfilebyID is of type File, not Document.
Try something like this:
let LogFile = DriveApp.getFileById('doc-id');
let LogDoc = DocumentApp.openById(LogFile.getId());
LogDoc.getBody()

TypeError: Cannot call method "setSchema" of undefined

I am trying to connect a Google Spreadsheet with Google BigQuery for that I created a Google Apps Script but when I try to run it I get the following error:
Cannot call method "setSchema" of undefined.
The code calling setSchema is the following
var loadJob = BigQuery.newJob()
.setConfiguration(
BigQuery.newJobConfiguration()
.setLoad(
BigQuery.newJobConfigurationLoad()
.setSourceFormat("NEWLINE_DELIMITED_JSON")
.setSchema(sshema)
.setDestinationTable(json_table.getTableReference())
)
);
When I view the log for sshema I get a correct JSON like
{fields=[{name=first, type=STRING}, {name=last, type=STRING}]}
I am not sure how to solve the error, when I comment out the SetSchema line the error goes away...but obviously the script does not do what its suppose to.
Any tip in the right direction will be appreciated. Thanks!
UPDATE: I tried debugging the script and the line that is suppose to create the newJob() simply inserts the {} value into the loadJob variable. I am not sure why this is not working but at least it seems to be the problem.
This is a temporary bug, should be fixed in a week. You can track it at:
https://code.google.com/p/google-apps-script-issues/issues/detail?id=2906
In the meantime, you can bypass it by not chaining the sets(): https://stackoverflow.com/a/17420247/132438