Getting Error Daily Limit for Unauthenticated Use Exceeded in Google Sheets for URL Shortener API - google-apps-script

I am getting "Error Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup" in google sheets with using URL Shortener API (image as below)
Below is my code in Script Editor
function shortenURL(urlField) {
var toShorten = UrlShortener.newUrl().setLongUrl(urlField);
var shortened = UrlShortener.Url.insert(toShorten);
return shortened.getId();
}
I have bonded to the API through Google Sheets build-in setting from "Cloud Platform Project", enabled URL Shortener API in "Advanced Google Services", enabled it in Google API Console, and created both API and OAuth (image as below). Besides, I was just using it for less than 20 cells in the Google Sheets, and so I am sure it is way less than the quote given by Google.
Cloud Platform Project
Advanced Google Services
Enable in Google API Console
If I use the below code (mentioned here), it works fine.
However, I want the script to run automatically as the function instead of by clicking the button. Therefore, I still want to solve the error.
function onOpen() {
SpreadsheetApp.getUi()
.createMenu("Shorten")
.addItem("Go !!","rangeShort")
.addToUi()
}
function rangeShort() {
var range = SpreadsheetApp.getActiveRange(), data = range.getValues();
var output = [];
for(var i = 0, iLen = data.length; i < iLen; i++) {
var url = UrlShortener.Url.insert({longUrl: data[i][0]});
output.push([url.id]);
}
range.offset(0,1).setValues(output);
}
I found some post mentioned the solution to this error is to apply authentication to the requests to Google. However, I have already created API key and OAuth and bond them to Google Sheets through those Google Sheets build-in setting.
Is there any solution to the error?
If the error occurs due to authentication issue, how I can apply the authentication in addition to those setting I have already done?

Try sending a POST request to UrlShortener API endpoint instead of using the UrlShortener service in Apps Script. With UrlShortener.Url.insert(), I quickly hit the usage quota.
Append the API url with the 'key' parameter and set it equal to the API key you obtained from Developer console.
In the body of your POST request, set 'muteHttpExceptions' to 'true' to log all error messages as beautified JSON.
var API_KEY = "YOUR_API_KEY";
function shortenUrl(longUrl) {
var apiEndpoint = "https://www.googleapis.com/urlshortener/v1/url?key=" + API_KEY;
var data = {
"longUrl": longUrl
}
var options = {
"method": "post",
"contentType": "application/json",
"muteHttpExceptions": true,
"payload": JSON.stringify(data)
};
var response = UrlFetchApp.fetch(apiEndpoint, options).getContentText();
var data = JSON.parse(response);
return data.id;
}

Related

ScriptApp.getOAuthToken not getting the right permissions for drive through url fetch app?

Trying to explore this with a very simple script but I'm getting an insufficient permissions error:
function mini(){
var gdriveId = "1hp8ncIG4Ww7FH8wi7HjJzzzzzzz";
var options = {
method: "GET",
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()
},
}
var url = "https://www.googleapis.com/drive/v2/files/"+gdriveId+"/children";
var response = JSON.parse(UrlFetchApp.fetch( url, options).getContentText());
}
I tried enabling the v2 drive api in the advanced google services dropdown but that didn't work.
I believe your situation and goal as follows.
From gdriveId in your script, I thought that you want to retrieve the folder list in the root folder of gdriveId using the method of "Children: list" in Drive API v2.
You have already enabled Drive API at Advanced Google Services.
For this, how about this answer?
Modification points:
When your script is put to new GAS project and Drive API is enabled at Advanced Google Services, the scopes of the project is only https://www.googleapis.com/auth/script.external_request. The required scope can be automatically detected by the script editor. But, even when Drive API is only enabled, it seems that no scopes are added. I think that the reason of your issue is this.
Under above situation, if you want to retrieve the access token including the required scopes, in order to make the script editor automatically detect the scope of https://www.googleapis.com/auth/drive.readonly, for example, please put // DriveApp.getFiles() to the script as a comment line.
In this case, when you use the methods for other scopes in your script, those scopes can be automatically detected and added by the script editor.
Modified script 1:
When your script is modified, it becomes as follows.
function mini(){
var gdriveId = "1hp8ncIG4Ww7FH8wi7HjJzzzzzzz";
var options = {
method: "GET",
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()
},
}
var url = "https://www.googleapis.com/drive/v2/files/"+gdriveId+"/children";
var response = JSON.parse(UrlFetchApp.fetch( url, options).getContentText());
}
// DriveApp.getFiles() // <--- Added this comment line. By this, the scope of https://www.googleapis.com/auth/drive.readonly is added.
Modified script 2:
When the method of Advanced Google service is used, the scope of https://www.googleapis.com/auth/drive is automatically added. By this, the following script works.
function test() {
var gdriveId = "1hp8ncIG4Ww7FH8wi7HjJzzzzzzz";
var res = Drive.Children.list(gdriveId);
console.log(res)
}
Other pattern:
From June 1, 2020, the files and folders in the shared Drive can be retrieved by Drive service. So you can also use the following script.
function myFunction() {
const getFolderList = (id, folders = []) => {
const f = DriveApp.getFolderById(id);
const fols = f.getFolders();
let temp = [];
while (fols.hasNext()) {
const fol = fols.next();
temp.push({name: fol.getName(), id: fol.getId(), parent: f.getName()});
}
if (temp.length > 0) {
folders.push(temp);
temp.forEach((e) => getFolderList(e.id, folders));
}
return folders.flat();
};
var gdriveId = "###"; // Please set the Drive ID.
const res = getFolderList(gdriveId);
console.log(res);
}
References:
Advanced Google services
Children: list of Drive API v2
Authorization Scopes
If you want to give permission to write with ScriptApp.getOAuthToken(), just add the following code in a commented out form and authorize it at runtime. If you don't do this, you'll only be able to download and browse.
//DriveApp.addFile("test");
Reference URL:https://00m.in/UeeOB

Google script replaceAllShapesWithImage with image from drive doesn"t work any more

Since yesterday one of my google script doesn't work anymore.
The script
take an image on the drive
copie a slide
replace a shape with an image
But I got this error:
"The provided image is in an unsupported format."
-> I give all access to the image: it doesn't change anything
-> The script work if I take an url outside the drive
Any idea
function test_image(){
var imageUrls = DriveApp.getFilesByName("DSC_3632.png");
var file = "undefined";
while ( imageUrls.hasNext()) {
var file = imageUrls.next();
}
var imageUrl = file.getDownloadUrl() + "&access_token=" + ScriptApp.getOAuthToken();
var model_file = DriveApp.getFileById("your-id");
var presentation = model_file.makeCopy("totot");
var presentation =Slides.Presentations.get(presentation.getId())
var requests = [{
"replaceAllShapesWithImage":
{
"imageUrl": imageUrl,
"imageReplaceMethod": "CENTER_INSIDE",
"containsText": {
"text": "toto",
"matchCase": false,
}
}
}];
var presentationId = presentation.presentationId
var createSlideResponse = Slides.Presentations.batchUpdate({
requests: requests
}, presentationId);
}
How about this answer? Please think of this as just one of several possible answers.
Issue and workaround:
I think that the reason of your issue is due to the following modification of official document.
First, we’re making changes to authorization for the Google Drive API. If you authorize download requests to the Drive API using the access token in a query parameter, you will need to migrate your requests to authenticate using an HTTP header instead. Starting January 1, 2020, download calls to files.get, revisions.get and files.export endpoints which authenticate using the access token in the query parameter will no longer be supported, which means you’ll need to update your authentication method.
By above situation, the URL of var imageUrl = file.getDownloadUrl() + "&access_token=" + ScriptApp.getOAuthToken(); cannot be used. For example, when it accesses to the URL, the login screen is displayed even when the access token is used.
In order to avoid this issue, how about the following modification?
Modification points:
The file is shared publicly and put to Google Slides. Then, the sharing file is closed.
In this case, even when the share of file is closed, the put image on Slides is not removed.
The webContentLink is used as the URL.
It's like https://drive.google.com/uc?export=download&id=###.
Modified script:
When your script is modified, it becomes as follows.
function test_image(){
var imageUrls = DriveApp.getFilesByName("DSC_3632.png");
var file; // Modified
while (imageUrls.hasNext()) {
file = imageUrls.next();
}
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW); // Added
var imageUrl = "https://drive.google.com/uc?export=download&id=" + file.getId(); // Modified
var model_file = DriveApp.getFileById("your-id");
var presentation = model_file.makeCopy("totot");
var presentation =Slides.Presentations.get(presentation.getId())
var requests = [{
"replaceAllShapesWithImage": {
"imageUrl": imageUrl,
"imageReplaceMethod": "CENTER_INSIDE",
"containsText": {
"text": "toto",
"matchCase": false,
}
}
}];
var presentationId = presentation.presentationId
var createSlideResponse = Slides.Presentations.batchUpdate({requests: requests}, presentationId);
file.setSharing(DriveApp.Access.PRIVATE, DriveApp.Permission.NONE); // Added
}
References:
Upcoming changes to the Google Drive API and Google Picker API
setSharing()
If I misunderstood your question and this was not the direction you want, I apologize.

Can Google Sites API still be authorized?

I tested it in the Google OAuth 2.0 Playground and it looked like I could return info from the site, but when I set up the OAuth2 code from Github, I can't seem to do a UrlFetchApp request as I get
the error returned code 403. Truncated server response: Not authorized to access this feed
I am not sure if this is because it is not enabled in the API console, but I can't find it there or under Advanced Google Services.
This is the section of code I am falling down at:
var service = getService();
if (service.hasAccess()) {
Logger.log("initial xml has access "service.hasAccess());
var headers = {
"Authorization": "Bearer " + service.getAccessToken()
};
var MyAttachmentsURL = 'https://sites.google.com/feeds/content/[DOMAIN]/[SITE NAME]?kind=attachment';
var response = UrlFetchApp.fetch(MyAttachmentsURL, headers);
};
The script from Github worked for me and I authorized when the message came up. This is what is in my scope tab:
7 OAuth Scopes required by the script:
https://sites.google.com/feeds
https://www.googleapis.com/auth/drive
https://www.googleapis.com/auth/script.container.ui
https://www.googleapis.com/auth/script.external_request
https://www.googleapis.com/auth/script.scriptapp
https://www.googleapis.com/auth/spreadsheets
https://www.googleapis.com/auth/userinfo.email
According to the Protocol Guide's "Authorizing requests with OAuth 2.0" You must activate the Google Sites API in the API Console if you can see that option (Step 2).
The only other issue I can see is the requiring to specify a version as GData-Version: 1.4.
So your code would change to something like this:
var service = getService();
if (service.hasAccess()) {
Logger.log("initial xml has access "service.hasAccess());
var headers = {
"GData-Version": "1.4",
"Authorization": "Bearer " + service.getAccessToken()
};
var MyAttachmentsURL = 'https://sites.google.com/feeds/content/[DOMAIN]/[SITE NAME]?kind=attachment';
var response = UrlFetchApp.fetch(MyAttachmentsURL, headers);
};
As long as the scope is mentioned in the code, it doesn't need to be passed, so that wasn't the issue. This was one of many variations I had been trying and I blame missing the post method on it being the wee hours. This code works (for now).
var service = getService();
if (service.hasAccess()) {
Logger.log("initial xml has access "+service.hasAccess());
var headers = {
// "GData-Version" : "1.4",
"Authorization" : "Bearer "+service.token_.access_token
};
var params = {"headers": headers, 'method':'get', 'muteHttpExceptions':true};
var MyAttachmentsURL = 'https://sites.google.com/feeds/content/[DOMAIN]/[SITE NAME]?kind=attachment';
var response = UrlFetchApp.fetch(MyAttachmentsURL, params);
};
It appears that "GData-Version" : "1.4" is returned in the response header so is not needed in the request. What is needed is the access token and although all the other API's seem to be able to make use of .getAccessToken, I had to amend this to .token_.access_token - this may be just for Google Sites.
I appreciate those who had a look at this and thank you Chris for responding.

How to download a file using a url in Google Apps Script

I am fairly new to Google Apps Script. I am using Google's functionality to access the DFA/DCM Trafficking and Reporting API through App Scripts without having to use OAuth.
When I run the DCM Report to then convert into google sheets, I am not able to figure out how to use either urls i'm supplied with to download the CSV.
Here is the code i'm using.
var file = DCM.Reports.run(profile.profileId,30792432);
var file2 = DCM.Files.get(30792432, file.id);
//wait till running of the report is complete.
file2 = DCM.Files.get(30792432, file.id);
var response = UrlFetchApp.fetch(file2.urls.browserUrl);
I also try using:
file2.urls.apiUrl();
for the UrlFetchApp service, but that didn't work either.
Any help on how to execute the url to download the file as an object where I can paste into google sheets would be greatly appreciated.
Add the ScriptApp authorization bearer as a header in the parameters while using the apiurl call. Something like:
var token = ScriptApp.getOAuthToken();
var headersOptions = {
Authorization : 'Bearer ' + token
};
var options = {
headers : headersOptions
};
var csvDoc = UrlFetchApp.fetch(file2.url.apiurl, options);

Apps Script & Oauth2 & Youtube API v3

I have This script that lists my favorite videos of youtube using Oauth and the YTB API v2.
Now I would like to do the same with the YTB DATA API V3 and who knows an easy step ahaed is the YTB ANALYTICS API V1.
So I was looking for the URL that would get me to the favorites in V3.
var URL = "https://www.googleapis.com/youtube/v3/"
instead of
//var URL = "http://gdata.youtube.com/feeds/api/users/default/favorites?v=2";
Is that there a way to do it like this with the DATA API v3?
Or is it only possible to reach to the simple data with the long URL request with the API KEY as in the github example of #Arun Nagarajan
var url = 'https://www.googleapis.com/youtube/v3/activities?'
+'part=snippet&channelId=UC_x5XG1OV2P6uZZ5FSM9Ttw&maxResults=20&publishedBefore=2013-02-25T00:00:00.0Z'
+'&key='+API_KEY;
Here is the part of the code that I would like to use with the YTB API v3.
//var URL = "http://gdata.youtube.com/feeds/api/users/default/favorites?v=2"; works
var URL = "https://www.googleapis.com/youtube/v3/" // cant find it
function getFavoriteVideos()
{
var data = UrlFetchApp.fetch(URL, googleOAuth_()).getContentText();
var xmlOutput = Xml.parse(data, false);
var favorites = xmlOutput.getElement().getElements('entry');
Logger.log("a" + favorites.length.toString())
var a = favorites.length.toString()
for(var i = 0; i < favorites.length; i++)
{
favorites[i].getElement('title').getText()
Logger.log(favorites[i].getElement('title').getText())
}
}
The authentication
var NAME = 'youtube';
var SCOPE = 'http://gdata.youtube.com';
function googleOAuth_() {
var oAuthConfig = UrlFetchApp.addOAuthService(NAME);
oAuthConfig.setRequestTokenUrl('https://www.google.com/accounts/OAuthGetRequestToken?scope='+SCOPE);
oAuthConfig.setAuthorizationUrl('https://www.google.com/accounts/OAuthAuthorizeToken');
oAuthConfig.setAccessTokenUrl('https://www.google.com/accounts/OAuthGetAccessToken');
oAuthConfig.setConsumerKey('anonymous');
oAuthConfig.setConsumerSecret('anonymous');
return {oAuthServiceName:NAME, oAuthUseToken:'always'};
}
The problem with utilizing the oAuthConfig class is that it's based on oAuth1 not oAuth2.
There is a request in at Google-Apps-Scirpt-Issues to upgrade to oAuth2:
https://code.google.com/p/google-apps-script-issues/issues/detail?id=2580
I initially forgot to mention there is a posting in SO on using oAuth2 with GAS, Arun, in his response, posted a reference to an example he provides in GitHub: How to authorize with oauth 2.0 from appscript to Google APIs?