Google App Script UrlFetchApp error need ivs - json

I tried to login my account by using UrlFetchApp, when I ran script manually, everything worked well. But when I set trigger to run automatically, it returned "error_need_ivs". I have no idea what it is and how to fix. please help me. Below is my code
function login() {
var data = {
'username':'username',
'password_hash':'password',
}
var option = {
muteHttpExceptions: true,
"method" : "POST",
"payload" : data,
}
var url = 'my url'
var res = JSON.parse(UrlFetchApp.fetch(url,option).getContentText());
Logger.log(res) //returned error_need_ivs when I set trigger but worked well when I ran script manually
}
UPDATE : This picture show the result after scripting executed by trigger

From the new screenshot shared I can see no Exceptions were thrown, which means the error logged error_need_ivs certainly comes from the response of the HTTP request rather than an issue with Apps Scripts.
Regarding why it works when calling the affected function manually and why it doesn't worked when invoking it via timed-trigger, I believe what #Tanaike suggested to make sense, maybe the affected endpoint is not prepared to receive IPv6 requests or require more data when doing so.
I'd suggest checking the documentation for the endpoint you are making the request for to help identify what might be causing this behavior.
Alternatively, I'd also suggest to report it as an Issue on IssueTracker using this template. Make sure to include a full reproducible scenario when reporting it (including a working endpoint).

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

Postman Canary 8.0.0-canary01 not saving environment variables

Today I upgraded my Postman to the latest version, going from PostmanCanary 7.37.0-canary01 to 8.0.0-canary01.
I used to run a login request and save the returned access token to my environment variables with this script:
response = JSON.parse(responseBody);
access_token = response.access_token;
postman.setEnvironmentVariable("access_token",access_token);
to process this response :
{
"token_type": "Bearer",
"expires_in": "3599",
"ext_expires_in": "3599",
"expires_on": "1610147694",
"not_before": "1610143794",
"resource": "https://xxxxxxxxxxx.crm.dynamics.com/",
"access_token": "eyJ0eXAiOiJKV1QxxxxxxxxxxxxxxxI1NiIsIng1dCI6IjVPZjlQNUY5xxxxxxxxxxxxxxxxxxxxxx1EayIsxxxxZCI6IjxxxxxxxxxxxxNDd0NtxxxxxxxxxEREUS1Exxxx.xxxxxxxxxxxxxxxwczovL2RxxxxkZXZxxxxxxxxxxxxxxxxxxxxxcy5jb20vIiwiaXNxxxxxxxxxxxxxxxxzdHMud2luZG93cy5uZXQvNTBmOGZjYzxxxxxxxxxxxxxxxxxxxxxtMzZlZDU3YzdjOGEyLyIsImlhdCI6MTYxMDE0Mzc5NCwibmJmIjoxNjEwMTQzNzk0LCJleHAiOjE2MTAxNDc2OTQsImFpbyI6IkUySmdZQWc0bjN2L1o4VE5HT20zdnRQMStMZGFBZ0E9IiwiYXBwaWQiOiI4ZTc3ZDkzZi05MmY1LTRhMWYtOWY1OS1iZGY4ZGNkYTNkY2IiLCJhcHBpZGFjciI6IjEiLCJpZHAiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC81MGY4ZmNjNC05NGQ4LTRmMDctODRlYi0zNmVkNTdjN2M4YTIvIiwib2lkIjoiYmJmZjA5OTQtZGQyNi00Nzg5LThlMjktMTc5OTIwOWI0ZDMxIiwicmgiOiIwLkFBQUF4UHo0VU5pVUIwLUU2emJ0VjhmSW9qX1pkNDcxa2g5S24xbTktTnphUGNzTkFCdy4iLCJzdWIiOiJiYmZmMDk5NC1kZDI2LTQ3ODktOGUyOS0xNzk5MjA5YjRkMzEiLCJ0aWQiOiI1MGY4ZmNjNC05NGQ4LTRmMDctODRlYi0zNmVkNTdjN2M4YTIiLCJ1dGkiOiJjZXJzaGlldGxFeU15Q1c2MVFWTUFBIiwidmVyIjoiMS4wIn0.EXV9P_DZIdVbTUK4PY6VcyrUmUx752ZA9MGr5BJ7xxxxxxxxxxxx-xxxxxxxxxX5wgidfGfoNklllZuoJVTi91jtnKP2T9Q-XFShpXhexDdCgOvMe9ZOOd0vOb11of1YPl37GKILtHikT3oPvKfUjBhOjZkFJo6F7pKeuxa3XiD_3WM1eCurVzuaG9iME94mFXb3HNTgUrWw9mPEqDwVzfxxxxx-xxxx-xxxxy0lw-2EcqpEYk7fqHUOTPUfAj2426zVV7ITfFPLdN08c4OND336sXpKjEFa5c7Buyk1dc24nawqJwCoKve1DaZAwPwljZKhGIIW4rd-1nitik2xWg"
}
Even if the environment variables did not exist prior to the call, this script would create them and set values. If I opened the environment variables, it would be listed.
After the upgrade, this no longer works. My subsequent requests kept failing because an old access_token was still there as it was not getting updated. I deleted the old access_token and confirmed that the access_token is now no longer being created.
I read about the resulting parsed JSON causing issues for other people because it is not text. I don't truly believe this to be the issue, mine is a single value, not a structure nor an array, but decided to play it safe and stringify it. Following the current documentation, I changed my script to :
response = JSON.parse(responseBody);
access_token = response.access_token;
console.log (access_token); // I can see the token in the console - parsing executed correctly
pm.environment.set("access_token",JSON.stringify(access_token)); // setting the environment variable
console.log(pm.environment.get("access_token")); // getting the exact same environment variable I have just set - I can see this on the console as well
console.log("WTF?!?!?"); // Self explanatory - added at the end to ensure all instructions in the script are read and executed - I see this every time as well
This does not work either (with or without stringify) and gives me the same results. Everything seems fine on the console, but when I look at my environment variables, access_token is not present although I can access it during the execution of the test script. Afterward, it is gone.
At this point I'm frustrated and at a loss - have anyone else seen similar behavior or am I missing something stupidly simple?
Hi Please use stable postman version :
https://www.postman.com/downloads/
Canary builds usually for beta testing , the issue seems to be there and i have raised a bug:https://github.com/postmanlabs/postman-app-support/issues/9412
Update The issue is fixed now : https://github.com/postmanlabs/postman-app-support/issues/9412

Returning JSON through angular and bible.org api or esvapi.org

I've been researching this and cannot find or understand some of the solutions so i'm hoping to get some help here. I'm using Asp.net and building an application that needs to use a bible api. I like the two listed in the question. Every time I call esvapi it comes back successful, but I cannot view the data. I get an error in the console.
XMLHttpRequest cannot load http://www.esvapi.org/v2/rest`/passageQuery?key=8834092f0c58fcda&passage=James2. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:59324' is therefore not allowed access.`
I've seen other with this error and I have questions.
If I'm understanding this correct I get this because the server is preventing me from seeing the data for security purposes. Maybe even the browser( this is not just a chrome issue) problem. So if I need to add a info to the response header from Angularjs to stop this how is that done. Anyone with experience?
Would I need to contact anyone to be able to prevent the server from responding this way...I doubt this, but thought I would ask. I already have valid api key.
the bible.org website api key is confusing to apply to my code. on esvapi i just add a header with key: "keypass" and I only have the CORS issue. But with bible.org I can't figure out how to implement the api key and password. see below... Do I say token:key: username. If i put the api in the browser I get a popup to add username and password. the username is my key and the password is ignored. I tried putting in username as key, but that didn't cut it. Regardless I need to fix the CORS issue and add info to response headers to see response data.
$scope.search = function() {
return $http.get("http://www.esvapi.org/v2/rest/passageQuery?&passage=" + $scope.bo + $scope.chap, {
headers: {
"key?token?orusername?": "",
///thought i saw someone do this...don't know if this is right
"Access-Control-Expose-Headers": "Content-Disposition",
}
}).success(function (data, status, headers, config) {
$scope.book = data.Book;
$scope.chapter = data.Chapter;
$scope.output = data.Output;
}).error(function (data, status, headers, config) {
$scope.message = "Oops... something went wrong";
});
Any input would be helpful. Thanks!
I actually have a bible api working...just a version that I don't like and there is not another version on that webites api.
Change the get $http.get call to $http.jsonp and hope it works. You're using cross-site scripting. Sometimes you can get away with a JSONP call in these cases and sometimes you can't.

How to use REST API PATCH command with Google Apps Script UrlFetchApp

I am trying to PATCH (partially update) Firebase records (firebase.com). This works perfect outside of Google Apps Script using PATCH. GAS is not supporting PATCH and I tried X-HTTP-Method-Override without success. Using GAS with X-HTTP-Method-Override renders the same result as a standard GET. There is no security on my test database. No log-in is required.
var myPayload = "{\"WSD124\" : {\"auction\" : {\"stockno\" : \"ESD124\", \"highbid\" : \"240\"}}}";
var myURL = "https://mydatabase.firebaseio.com/auctions/.json";
var options = {
headers: {
"X-HTTP-Method-Override" : "PATCH"
},
method: "POST",
payload: myPayload
};
var oResponse = UrlFetchApp.fetch(myURL,options);
A quick update for those coming back to this old thread - we now support X-HTTP-Method-Override headers on all REST API calls, so this should now work
UPDATE
This is now supported. See Chris Raynor's answer.
OLD ANSWER
We don't currently support X-HTTP-Method-Override though we are considering it. For now you'll likely have to do a PUT with the whole record. Give us an email at support#firebase.com if this is significantly blocking you.

Trigger Google Apps Script by email

I'm looking for examples of a pattern where a demon script running within a GoogleAppsForBusiness domain can parse incoming email messages. Some messages will will contain a call to yet a different GAScript that could, for example, change the ACL setting of a specific document.
I'm assuming someone else has already implemented this pattern but not sure how I go about finding examples.
thx
You can find script examples in the Apps Script user guide and tutorials. You may also search for related discussions on the forum. But I don't think there's one that fits you exactly, all code is out there for sure, but not on a single script.
It's possible that someone wrote such script and never published it. Since it's somewhat straightforward to do and everyone's usage is different. For instance, how do you plan on marking your emails (the ones you've already read, executed, etc)? It may be nice to use a gmail filter to help you out, putting the "command" emails in a label right away, and the script just remove the label (and possibly set another one). Point is, see how it can differ a lot.
Also, I think it's easier if you can keep all functions in the same script project. Possibly just on different files. As calling different scripts is way more complicated.
Anyway, he's how I'd start it:
//set a time-driven trigger to run this function on the desired frequency
function monitorEmails() {
var label = GmailApp.getUserLabelByName('command');
var doneLabel = GmailApp.getUserLabelByName('executed');
var cmds = label.getThreads();
var max = Math.min(cmds.length,5);
for( var i = 0; i < max; ++i ) {
var email = cmds[i].getMessages()[0];
var functionName = email.getBody();
//you may need to do extra parsing here, depending on your usage
var ret = undefined;
try {
ret = this[functionName]();
} catch(err) {
ret = err;
}
//replying the function return value to the email
//this may make sense or not
if( ret !== undefined )
email.reply(ret);
cmds[i].removeLabel(label).addLabel(doneLabel);
}
}
ps: I have not tested this code
You can create a google app that will be triggered by an incoming email message sent to a special address for the app. The message is converted to an HTTP POST which your app receives.
More details here:
https://developers.google.com/appengine/docs/python/mail/receivingmail
I havn't tried this myself yet but will be doing so in the next few days.
There are two ways. First you can use Google pub/sub and handle incomming notifications in your AppScrit endpoint. The second is to use the googleapis npm package inside your AppScript code an example here. Hope it helps.
These are the steps:
made a project on https://console.cloud.google.com/cloudpubsub/topicList?project=testmabs thing?
made a pubsub topic
made a subscription to the webhook url
added that url to the sites i own, i guess? I think I had to do DNS things to confirm i own it, and the error was super vague to figure out that was what i had to do, when trying to add the subscription
added permission to the topic for "gmail-api-push#system.gserviceaccount.com" as publisher (I also added ....apps.googleusercontent.com and youtrackapiuser.caps#gmail.com but i dont think I needed them)
created oauth client info and downloaded it in the credentials section of the google console. (oauthtrash.json)