For work we would like to automated certain tasks. One of those tasks could be automated using an API. This is an external API and we would like to import it into Google Sheets to start working with it.
However, when creating the script I'm getting a 401 error. I have the url and key available, but with this I'm a little out of my debt on how to do this.
Can someone possibly point me in the right direction?
Thank you in advance.
function OnOpen() {
const API_KEY = 'XXX'
let url = 'XXX'
let request = url + API_KEY + '&q=' + location
let repsonse = UrlFetchApp.fetchapp(request);
let data = JSON.parse(reponse.getContentText());
}
Related
I am trying to scrape very small information from a webpage using Cheerio and Google Apps Script.
I want to get the performance number from this webpage:
Following is the code snippet that I am using to get it:
function LinkResult(){
var url ='https://pagespeed.web.dev/report?url=http%3A%2F%2Fwww.juicecoldpressed.com%2F';
var result = UrlFetchApp.fetch(url);
var content = Cheerio.load(result.getContentText())
var item = content(".lh-gauge__percentage").text()
Logger.log(item)
}
As I run, this code does not show any output in the variable item. Surely there is something which I am missing, can you please guide me? Thank you.
Issue and workaround:
In this case, I'm worried that your goal might not be able to be directly achieved using the URL of https://pagespeed.web.dev/report?url=http%3A%2F%2Fwww.juicecoldpressed.com%2F and Cheerio. Because the HTML data retrieved from UrlFetchApp.fetch(url) is different from that on the browser. And, it seems that the value is calculated using a script.
Fortunately, in your situation, I thought that your values can be retrieved using PageSpeed Insights API. In this answer, I would like to propose achieving your goal using PageSpeed Insights API.
Usage:
1. Get Started with the PageSpeed Insights API.
Please check the official document for using PageSpeed Insights API. In this case, it is required to use your API key. And, please enable PageSpeed Insights API at the API console.
2. Sample script.
function myFunction() {
const apiKey = "###"; // Please set your API key.
const url = "http://www.juicecoldpressed.com/"; // Please set URL.
const apiEndpoint = `https://www.googleapis.com/pagespeedonline/v5/runPagespeed?key=${apiKey}&url=${encodeURIComponent(url)}&category=performance`;
const strategy = ["desktop", "mobile"];
const res = UrlFetchApp.fetchAll(strategy.map(e => ({ url: `${apiEndpoint}&strategy=${e}`, muteHttpExceptions: true })));
const values = res.reduce((o, r, i) => {
if (r.getResponseCode() == 200) {
const obj = JSON.parse(r.getContentText());
o[strategy[i]] = obj.lighthouseResult.categories.performance.score * 100;
} else {
o[strategy[i]] = null;
}
return o;
}, {});
console.log(values);
}
3. Testing.
When this script is run, you can see the returned value of { desktop: ##, mobile: ## } at the log. The values (the unit is %.) of desktop and mobile are the values for the desktop and the mobile, respectively.
Reference:
Get Started with the PageSpeed Insights API
Can someone tell me how I can upload an image on Firebase Storage? I would apriciate if someone can give me an code sample how to that with Typescript and Node.js.
I have already created an Firebase project. How many giga Bytes you may upload for free?
this is my Client API endpoint written with Retrofit:
#Multipart
#POST("/uploadImage")
fun uploadFile(#Part("description") description: RequestBody, #Part file: MultipartBody.Part, #Query("idUser") idUser: String): Observable<ResponseBody>
At the moment I use something like that, but not working for me:
const storage = require('#google-cloud/storage')
const functions = require('firebase-functions')
exports.uploadImage = functions.https.onRequest(async (request:any,response:any) => {
// params
const file = request.query.file
const idUser = request.query.idUser
const description = request.query.description
console.log("idUser: " + idUser + ", description: " + description)
const storageRef = storage.bucket('gs://<project>')
const finalDestination = storageRef.child("/FCMImages");
// const metadata = {
// contentType: 'image/jpeg',
// };
storageRef.upload(file, {destination: finalDestination});
})
There are some tutorials and documentation that you can follow to perform upload of images to Firebase.
I would recommend you to take a look at the following links, to confirm if they might help you achieve it. In case they don't, let me know, so I can assist you further.
Firebase cloud function for file upload
Image processing using Google Cloud function
The first one is a post here, on the Community, with some codes and solution on how to do it and the second one is a post on Medium, about processing and working images with Cloud Functions.
Let me know if the information helped you!
How do you make an app script which attaches a spreadsheet as an excel file and emails it to a certain email address?
There are some older posts on Stackoverflow on how to do this however they seem to be outdated now and do not seem to work.
Thank you.
It looks like #Christiaan Westerbeek's answer is spot on but its been a year now since his post and I think there needs to be a bit of a modification in the script he has given above.
var url = file.exportLinks[MimeType.MICROSOFT_EXCEL];
There is something wrong with this line of code, maybe that exportLinks has now depreciated. When I executed his code it gave an error to the following effect:
TypeError: Cannot read property "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" from undefined.
The workaround is as follows:
The URL in the above line of code is basically the "download as xlsx" URL that can be used to directly download the spreadsheet as an xlsx file that you get from File> Download as > Microsoft Excel (.xlsx)
This is the format:
https://docs.google.com/spreadsheets/d/<<<ID>>>/export?format=xlsx&id=<<<ID>>>
where <<>> should be replaced by the ID of your file.
Check here to easily understand how to extract the ID from the URL of your google sheet.
Here's an up-to-date and working version. One prerequisite for this Google Apps script to work is that the Drive API v2 Advanced Google Service must be enabled. Enable it in your Google Apps script via Resources -> Advanced Google Services... -> Drive API v2 -> on. Then, that window will tell you that you must also enabled this service in the Google Developers Console. Follow the link and enable the service there too! When you're done, just use this script.
/**
* Thanks to a few answers that helped me build this script
* Explaining the Advanced Drive Service must be enabled: http://stackoverflow.com/a/27281729/1385429
* Explaining how to convert to a blob: http://ctrlq.org/code/20009-convert-google-documents
* Explaining how to convert to zip and to send the email: http://ctrlq.org/code/19869-email-google-spreadsheets-pdf
* New way to set the url to download from by #tera
*/
function emailAsExcel(config) {
if (!config || !config.to || !config.subject || !config.body) {
throw new Error('Configure "to", "subject" and "body" in an object as the first parameter');
}
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var spreadsheetId = spreadsheet.getId()
var file = Drive.Files.get(spreadsheetId);
var url = 'https://docs.google.com/spreadsheets/d/'+spreadsheetId+'/export?format=xlsx';
var token = ScriptApp.getOAuthToken();
var response = UrlFetchApp.fetch(url, {
headers: {
'Authorization': 'Bearer ' + token
}
});
var fileName = (config.fileName || spreadsheet.getName()) + '.xlsx';
var blobs = [response.getBlob().setName(fileName)];
if (config.zip) {
blobs = [Utilities.zip(blobs).setName(fileName + '.zip')];
}
GmailApp.sendEmail(
config.to,
config.subject,
config.body,
{
attachments: blobs
}
);
}
Update: I updated the way to set the url to download from. Doing it through the file.exportLinks collection is not working anymore. Thanks to #tera for pointing that out in his answer.
I need to execute a GAS service on behalf of a user that is logged to my system. So I have her/his access token. I would like somehow to transfer the token to the web app and without having to authorize again the user to use it for some activities. Can this be accomplished? Thank you.
EDIT: I think I didn't explain right what I try to accomplish. Here is the work flow I try to achieve:
We authorize a user visiting our website using OAuth2 and Google;
We get hold of her/his access token that Google returns;
There is a Google Apps Script web app that is executed as the user running the web app;
We want to call this app (3) by providing the access token (2) so Google not to ask again for authorization;
Actually, we want to call this app (3) not by redirecting the user to it but by calling it as a web service.
Thanks
Martin's answer worked for me in the end, but when I was making a prototype there was a major hurdle.
I needed to add the following scope manually, as the "automatic scope detection system" of google apps script did not ask for it: "https://www.googleapis.com/auth/drive.readonly". This resulted in UrlFetchApp.fetch always giving 401 with additional information I did not understand. Logging this additional information would show html, including the following string
Sorry, unable to open the file at this time.</p><p> Please check the address and try again.
I still don't really understand why "https://www.googleapis.com/auth/drive.readonly" would be necessary. It may have to do with the fact that we can use the /dev url, but who may use the /dev url is managed is checked using the drive permissions of the script file.
That said, the following setup then works for me (it also works with doGet etc, but I chose doPost). I chose to list the minimally needed scopes explicitly in the manifest file, but you can also make sure the calling script will ask for permissions to access drive in different ways. We have two google apps script projects, Caller and WebApp.
In the manifest file of Caller, i.e. appsscript.json
{
...
"oauthScopes":
[
"https://www.googleapis.com/auth/drive.readonly",
"https://www.googleapis.com/auth/script.external_request"]
}
In Code.gs of Caller
function controlCallSimpleService(){
var webAppUrl ='https://script.google.com/a/DOMAIN/macros/s/id123123123/exec';
// var webAppUrl =
// 'https://script.google.com/a/DOMAIN/macros/s/id1212121212/dev'
var token = ScriptApp.getOAuthToken();
var options = {
'method' : 'post'
, 'headers': {'Authorization': 'Bearer '+ token}
, muteHttpExceptions: true
};
var response = UrlFetchApp.fetch(webAppUrl, options);
Logger.log(response.getContentText());
}
In Code.gs of WebApp (the web app being called)
function doPost(event){
return ContentService.createTextOutput("Hello World");
}
The hard answer is NO you can't use the built-in services of Apps Script with a service token. But if you already have the token for a user generated by a service account, access to the users data is pretty similar to any other language. All calls would be to the REST interface of the service your token is scoped for.
Take this small script for example. It will build a list of all the user's folders and return them as JSON:
function doGet(e){
var token = e.parameter.token;
var folderArray = [];
var pageToken = "";
var query = encodeURIComponent("mimeType = 'application/vnd.google-apps.folder'");
var params = {method:"GET",
contentType:'application/json',
headers:{Authorization:"Bearer "+token},
muteHttpExceptions:true
};
var url = "https://www.googleapis.com/drive/v2/files?q="+query;
do{
var results = UrlFetchApp.fetch(url,params);
if(results.getResponseCode() != 200){
Logger.log(results);
break;
}
var folders = JSON.parse(results.getContentText());
url = "https://www.googleapis.com/drive/v2/files?q="+query;
for(var i in folders.items){
folderArray.push({"name":folders.items[i].title, "id":folders.items[i].id})
}
pageToken = folders.nextPageToken;
url += "&pageToken="+encodeURIComponent(pageToken);
}while(pageToken != undefined)
var folderObj = {};
folderObj["folders"] = folderArray;
return ContentService.createTextOutput(JSON.stringify(folderObj)).setMimeType(ContentService.MimeType.JSON);
}
You do miss out on a lot of the convenience that makes Apps Script so powerful, mainly the built in services, but all functionality is available through the Google REST APIs.
I found a way! Just include the following header in the request:
Authorization: Bearer <user's_access_token>
I have a Google Docs Spreadsheet that I'd like to use to update referenced cards in Trello. I've had some success with oauth and pulling data via their HTTP API, but am stuck with the following:
1) it seems Trello's code.js requires a window object, which the Google Doc script doesn't provide. So, I am stuck using their HTTP API.
2) authenticating via OAuth works, but only gives me read access. I cannot update cards with the token I am able to get.
function test() {
var oauthConfig = UrlFetchApp.addOAuthService("trello");
oauthConfig.setAccessTokenUrl("https://trello.com/1/OAuthGetAccessToken");
oauthConfig.setRequestTokenUrl("https://trello.com/1/OAuthGetRequestToken");
oauthConfig.setAuthorizationUrl("https://trello.com/1/authorize?key=" + consumerKey + "&name=trello&expiration=never&response_type=token&scope=read,write");
//oauthConfig.setAuthorizationUrl("https://trello.com/1/OAuthAuthorizeToken"); <-- this only gives read access. Cannot POST
oauthConfig.setConsumerKey(consumerKey);
oauthConfig.setConsumerSecret(consumerSecret);
var url = 'https://trello.com/1/cards/yOqEgvzb/actions/comments&text=Testing...';
var postOptions = {"method" : "post",
"oAuthServiceName": "trello",
"oAuthUseToken": "always"};
var response = UrlFetchApp.fetch(url, postOptions); // "Request failed for returned code 404. Truncated server response: Cannot POST"
Logger.log(response.getContentText());
}
I've found a number of related questions but no direct answers:
How to get a permanent user token for writes using the Trello API?
Trello API: vote on a card
Trello API: How to POST a Card from Google Apps Script (GAS)
Google apps script oauth connect doesn't work with trello
Many thanks ahead of time for any advice.
In order to get write access, you need to change the authorization url.
This example works for me
var oauthConfig = UrlFetchApp.addOAuthService("trello");
oauthConfig.setAccessTokenUrl("https://trello.com/1/OAuthGetAccessToken");
oauthConfig.setRequestTokenUrl("https://trello.com/1/OAuthGetRequestToken");
oauthConfig.setAuthorizationUrl("https://trello.com/1/OAuthAuthorizeToken?scope=read,write");
on 1) yes you cant use the library from server gas, its meant to be run from a browser.
on 2), Ive done it from GAS with write access without problems. You need to use the format:
https://api.trello.com/1/.../xxxx?key=yyyyyy&token=zzzzzzz&...
and when you get the token, you need to request permanent access (no expiration) and write access, as in:
https://trello.com/1/authorize?key="+key+"&name=xxxxxxx&expiration=never&response_type=token&scope=read,write"
As in:
function postNewCardCommentWorker(cardId, comment, key, token) {
var commentEncoded=encodeURIComponent(comment);
var url = "https://api.trello.com/1/cards/"+cardId+"/actions/comments?text="+commentEncoded+"&key="+key+"&token="+token;
var options =
{
"method" : "POST"
};
UrlFetchApp.fetch(url, options);
}