Caching results of Maps API call to reduce volume in Sheets - google-apps-script

I have a public form which incudes a place name, which I'm using the Places API to get the Place ID, to then do another call to look up an address. I need to optimize the volume of API calls so I'm trying to add caching so that Sheets doesn't re-call the two APIs unnecessarily.
For some reason I can't get the caching to work, either it errors or I get "object object" as the response.
function locId(text) {
var text = cache.get(cacheLocId);
if (cacheLocId === null) {
var API_KEY = 'XYZXYZXYZ';
var baseUrl = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json';
var queryUrl = baseUrl + '?input=' + text + '&inputtype=textquery&key=' + API_KEY;
if (text == null) {
console. log("I QUIT!")
return;
}
var response = UrlFetchApp.fetch(queryUrl);
var json = response.getContentText();
var placeId = JSON.parse(json);
}
cache.put(cacheLocId, placeId)
console. log(text)
console. log(placeId)
return placeId.candidates[0].place_id;
}

It looks like you are overwriting the function argument and using cache keys and values the wrong way around. Try this pattern:
function locId(text) {
if (!text || typeof text !== 'string') {
return null;
}
const cache = CacheService.getDocumentCache();
const cached = cache.get(text);
if (cached) {
return cached;
}
const API_KEY = 'XYZXYZXYZ';
const baseUrl = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json';
const queryUrl = baseUrl + '?input=' + text + '&inputtype=textquery&key=' + API_KEY;
const response = UrlFetchApp.fetch(queryUrl);
const placeId = JSON.parse(response.getContentText()).candidates[0].place_id;
cache.put(text, placeId);
return placeId;
}

Related

Coinbase v2 with Google Sheets

I'm trying to use the Coinbase API v2 (NOT PRO) to simply pull the contents of my wallet in to my spreadsheet. I have the following:
var url = 'https://api.coinbase.com/v2';
var requestPath = '/accounts';
var api_key = '********';
var secret_key = '********';
// var timestamp = new Date().getTime().toString().slice(0, -3);
var timestamp = Math.floor(Date.now() / 1000).toString();
var method = 'GET';
var message = Utilities.base64Decode(Utilities.base64Encode(timestamp + method + requestPath));
var decoded_secret = Utilities.base64Decode(secret_key);
var signature = Utilities.base64Encode(Utilities.computeHmacSha256Signature(message, decoded_secret));
//previous attempt
/* var signature = Utilities.computeHmacSha256Signature(message, decoded_secret);
signature = signature.map(function(e) {
var v = (e < 0 ? e + 256 : e).toString(16);
return v.length == 1 ? "0" + v : v;
}).join("");*/
var params = {
'method': method,
'headers': {
'Content-Type': 'application/json',
'CB-ACCESS-SIGN': signature,
'CB-ACCESS-TIMESTAMP': timestamp,
'CB-ACCESS-KEY': api_key,
'CB-VERSION': '2021-02-03'
}
};
Logger.log(params);
var res = await UrlFetchApp.fetch(url + requestPath, params);
Unfortunately I am getting the invalid signature error. I feel like I'm close. It could be that I don't have the url/request path going in to the signature correctly.
Creating a Coinbase signature with Apps Script is a bit tricky
As you can see from the documentation for Coinbase API, in Python the signature is built with
signature = hmac.new(self.secret_key, message, hashlib.sha256).hexdigest().
In other words, the signature needs to be hex-encoded.
There is no 1:1 equivalent to hexdigest() in Apps Script, but you can build it manually.
This works for me:
var message = (timestamp + method + requestPath + body);
var byteSignature = Utilities.computeHmacSha256Signature(message, secret);
var signature = byteSignature.reduce(function(str,chr){
chr = (chr < 0 ? chr + 256 : chr).toString(16);
return str + (chr.length==1?'0':'') + chr;
},'');
Thereby secret is your credential provided by Coinbase - no need to decode it.

Connect telegram bot with google apps script

I have setup a bot on telegram bot and connected it with google spreadsheets via apps script by following this tutorial. Here is the code:
var token = ""; // FILL IN YOUR OWN TOKEN
var telegramUrl = "https://api.telegram.org/bot" + token;
var webAppUrl = ""; // FILL IN YOUR GOOGLE WEB APP ADDRESS
var ssId = ""; // FILL IN THE ID OF YOUR SPREADSHEET
function getMe() {
var url = telegramUrl + "/getMe";
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function setWebhook() {
var url = telegramUrl + "/setWebhook?url=" + webAppUrl;
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function sendText(id,text) {
var url = telegramUrl + "/sendMessage?chat_id=" + id + "&text=" + text;
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function doGet(e) {
return HtmlService.createHtmlOutput("Hi there");
}
function doPost(e) {
// this is where telegram works
var data = JSON.parse(e.postData.contents);
var text = data.message.text;
var id = data.message.chat.id;
var name = data.message.chat.first_name + " " + data.message.chat.last_name;
var answer = "Hi " + name + ", thank you for your comment " + text;
sendText(id,answer);
SpreadsheetApp.openById(ssId).getSheets()[0].appendRow([new Date(),id,name,text,answer]);
if(/^#/.test(text)) {
var sheetName = text.slice(1).split(" ")[0];
var sheet = SpreadsheetApp.openById(ssId).getSheetByName(sheetName) ? SpreadsheetApp.openById(ssId).getSheetByName(sheetName) : SpreadsheetApp.openById(ssId).insertSheet(sheetName);
var comment = text.split(" ").slice(1).join(" ");
sheet.appendRow([new Date(),id,name,comment,answer]);
}
}
Now I encountered the following issue; I use my bot to store messages from my home automation system. Therefore I send those messages from the system to telegram bot via HTTP GET request:
https://api.telegram.org/bot[BOT_API_KEY]/sendMessage?chat_id=[MY_CHANNEL_NAME]&text=[MY_MESSAGE_TEXT]
Currently these messages sent through http get request seem to be ignored by the script. Does anyoene know how I can solve this issue?
Judging from your question and comments, it seems you are struggling with sending info from your script to your bot on Telegram. Here are the steps to do that:
1.- Create a bot: on Telegram's search look for #BotFather. Click start, write /newbot, give it a name and a username. You should get a token to access the HTTP API. Save this token.
2.- Find your bot on Telegram with its username. Write something to it e.g. 'test'. This will come in handy later.
3.- Test access to the bot from your code
var token = "123456:kioASDdjicOljd_ijsdf"; // Fill this in with your token
var telegramUrl = "https://api.telegram.org/bot" + token;
function getMe() {
var url = telegramUrl + "/getMe";
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
You should get something resembling this:
{"ok":true,"result":{"id":<somenumber>,"is_bot":true,"first_name":"<name of your bot>","username":"<username of your bot>","can_join_groups":true,"can_read_all_group_messages":false,"supports_inline_queries":false}}
4.- Write the sendMessage function
function sendMessage(chat_id,text) {
var url = telegramUrl + "/sendMessage?chat_id=" + chat_id + "&text=" + text;
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
Known is the text you want to send e.g. 'testing bot', but chat_id is unknown. Where do we get this?
5.- Find the chat_id. Before running this function, make sure that you have at least written one message to your bot on Telegram (step 2)
function getChat_id(){
var res = UrlFetchApp.fetch(telegramUrl+"/getUpdates").getContentText();
var res = JSON.parse(res);
Logger.log(res.result[0].message.chat.id.toString());
}
6.- Run sendMessage with the chat_id you found in step 5 and the message you want to send.

how to communicate telegram bot with google sheet

i have problem for communication with telegram bot and google Spreadsheet , yesterday i work with that , and work very good, but today it can't work.
i create another google account and and another Bot, but not work.
this is my google script :
var token="123197063:AAH04kulz7tRqPz3vbDcgYdVje18WH2Pv-4";
var telegramUrl= "https://api.telegram.org/bot"+token;
var webAppUrl = "https://script.google.com/macros/s/AKfycbwqvJWsWcm_5_Y1vhYEkSN2G9dxiDBzQIvYvbte-3_HfGcGFN3a/exec";
function getMe(){
var url = telegramUrl+"/getMe";
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function setWebhook() {
var url = telegramUrl+"/setWebhook?url="+webAppUrl;
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function doGet(e){
return HtmlService.createHtmlOutput("hi this is my first project");
}
function dePost(e){
GmailApp.sendEmail(Session.getEffectiveUser().getEmail(), "message from bot", JSON.stringify(e, null, 4));
}
in this code when i write anything in telegram bot , google sheet must send an email to me, but it can't work today.
and this is my Bot address: #irmec_bot
do you have idea that it not work?
please help to me
thanks
You may follow the instructions in this video tutorial: How to connect your Telegram Bot to a Google Spreadsheet (Apps Script) Script in Description.
//
// FILL IN THE GLOBAL VARIABLES token, webAppUrl and ssId
//
var token = ""; // FILL IN YOUR OWN TOKEN
var telegramUrl = "https://api.telegram.org/bot" + token;
var webAppUrl = ""; // FILL IN YOUR GOOGLE WEB APP ADDRESS
var ssId = ""; // FILL IN THE ID OF YOUR SPREADSHEET
function getMe() {
var url = telegramUrl + "/getMe";
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function setWebhook() {
var url = telegramUrl + "/setWebhook?url=" + webAppUrl;
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function sendText(id,text) {
var url = telegramUrl + "/sendMessage?chat_id=" + id + "&text=" + text;
var response = UrlFetchApp.fetch(url);
Logger.log(response.getContentText());
}
function doGet(e) {
return HtmlService.createHtmlOutput("Hi there");
}
function doPost(e) {
// this is where telegram works
var data = JSON.parse(e.postData.contents);
var text = data.message.text;
var id = data.message.chat.id;
var name = data.message.chat.first_name + " " + data.message.chat.last_name;
var answer = "Hi " + name + ", thank you for your comment " + text;
sendText(id,answer);
SpreadsheetApp.openById(ssId).getSheets()[0].appendRow([new Date(),id,name,text,answer]);
if(/^#/.test(text)) {
var sheetName = text.slice(1).split(" ")[0];
var sheet = SpreadsheetApp.openById(ssId).getSheetByName(sheetName) ? SpreadsheetApp.openById(ssId).getSheetByName(sheetName) : SpreadsheetApp.openById(ssId).insertSheet(sheetName);
var comment = text.split(" ").slice(1).join(" ");
sheet.appendRow([new Date(),id,name,comment,answer]);
}
}
Here's an additional reference which might also help: Telegram Bot with Apps Script
If this is a new script for the same bot, you should set the web hook to the new link.
1) After you publish as app, copy the given a url (some thing like > https://script.google.com/macros/s/... )
2) Replace the url on line 3 var webAppUrl = INSERT_URL_HERE
3) Save the script
4) Run the setWebhook() function by clicking Run > Run Function > setWebhook()
Hope this helps!

Fetch API data from Bittrex

I'm trying to fetch the API data with Google Apps Script about my balance on Bittrex but it returns me nothing, no errors and only blank cells. This is the code I've written based on the documentation here: https://bittrex.com/Home/Api
function getBalance() {
var ss = SpreadsheetApp.openById("***");
var data = ss.getSheetByName("Data");
var key = ss.getSheetByName("Api").getRange('A2').getValue();
var secret = ss.getSheetByName("Api").getRange('B2').getValue();
var baseUrl = 'https://bittrex.com/api/v1.1/';
var nonce = Math.floor(new Date().getTime()/1000);
var command = "/account/getbalances";
var uri = baseUrl.concat(command + "?apikey=" + key + "&nonce=" + nonce);
var signature = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512,
uri,
secret);
signature = signature.map(function(byte) {
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
}).join('')
var headers = {
"apisign": signature
}
var params = {
"method": "get",
"headers": headers,
}
var response = UrlFetchApp.fetch(uri, params);
var json = JSON.parse(response.getContentText());
var blnc = [];
blnc.push(['Balance']);
for(var key in json.result)
{
blnc[0].push(json.result[key]);
}
askRange = data.getRange(2, 2, blnc.length, 1);
askRange.setValues(blnc);
}
The askrange last number is "1" because the script only pass the "Balance" value to the spreadsheet, but the values should be something around 210. Any help? Thank you
I solved it, the problem was in the "command" variable, there was a slash not needed that generated an url with a double slash

How to use an Service Account Oauth token to make REST call in appscript

I am using the GAS_Service_Account library.
I was able to do all the .p12 key decoding. But now I have:
myJwt.generateJWT().requestToken();
var token=myJwt.getToken();
Now I would like to know a simple way to use it to make an API call with
the service account to an api like drive to get a specific user's files.
Service accounts are powerful tools. The library GersonLobos mentions is: MJ5317VIFJyKpi9HCkXOfS0MLm9v2IJHf
Lets give some back ground. See the first half of this video on how to set up a service account in your domain:
https://www.youtube.com/watch?v=EDmEzZEGSts
With the library enabled in your project you can generate the token with the following:
// If userEmail is null the service account's token is returned
function tokenService(userEmail){
var userEmail = userEmail || ""
var jsonKey = JSON.parse(PropertiesService.getScriptProperties().getProperty("jsonKey"));
var privateKey = jsonKey.private_key;
var serviceAccountEmail = jsonKey.client_email;
if(!userEmail){userEmail = serviceAccountEmail};
var sa = GSApp.init(privateKey, ['https://www.googleapis.com/auth/drive'], serviceAccountEmail).addUser(userEmail);
var tokenObj = JSON.parse(PropertiesService.getScriptProperties().getProperty(userEmail)) || {};
return function(){
var nowTime = parseInt((Date.now()/1000).toString().substr(0,10));
if(!("token" in tokenObj) || tokenObj.expire < nowTime){
var newToken = sa.requestToken().getToken(userEmail);
PropertiesService.getScriptProperties().setProperty(userEmail, JSON.stringify(newToken));
tokenObj.token = newToken.token;
tokenObj.expire = newToken.expire;
}
return tokenObj.token;
}
}
Good now you have your token. I even show how to cache it as the requests take several seconds. Now you can make some calls. As requested by Gerson here are some drive calls:
function transferFileToUser(fileId, transferToEmail, token){
var url = "https://www.googleapis.com/drive/v2/files/"+fileId+"/permissions?sendNotificationEmails=false";
var payload = {"role":"owner","value":transferToEmail,"type":"user"};
var params ={method:"POST",
contentType:'application/json',
headers:{Authorization: "Bearer " + token},
payload:JSON.stringify(payload),
muteHttpExceptions:true
};
var results = UrlFetchApp.fetch(url, params);
return JSON.parse(results.getContentText());
}
function getAllFolders(token){
var query = "mimeType = 'application/vnd.google-apps.folder'";
return driveList(query, token);
}
function getFilesInFolder(folderId, token){
var query = "'"+folderId+"' in parents and mimeType != 'application/vnd.google-apps.folder'";
return driveList(query, token);
}
// genereic call to drive just pass the query
function driveList(query, token){
var filesArray = [];
var pageToken = "";
var query = encodeURIComponent(query);
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 files = JSON.parse(results.getContentText());
url = "https://www.googleapis.com/drive/v2/files?q="+query;
for(var i in files.items){
filesArray.push({"name":files.items[i].title, "id":files.items[i].id})
}
pageToken = files.nextPageToken;
url += "&pageToken="+encodeURIComponent(pageToken);
}while(pageToken != undefined)
var filesObj = {};
filesObj["fileObjs"] = filesArray;
return filesObj;
}