I'm trying to pull data from Airtable using Apps Scripts but all of it doesn't transfer over due to size. What do I need to add/change in order for it work?
function importCA() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ca_sheet = ss.getSheetByName("CA")
var ca = getCA();
ca_sheet.getRange(1,1, ca.length, ca[00].length).setValues(ca)
}
function getCA() {
var ca = requestAirtable();
//console.log("ca: ", ca)
var ca_info = []
ca_info.push(["Name", "Emails", "Districts", "Job Title", "Course", "Completed", "Start Dates"])
for(i=0; i<ca.length; i++) {
var fields = ca[i].fields;
ca_info.push([
fields.Name,
fields.Emails,
fields.Districts,
fields.Title,
fields.Course,
fields.Completed,
fields.StartDates,
])
}
console.log("CA ", ca_info)
return ca_info;
}
function requestAirtable() {
var url = "[removed]"
var headers ={
"Authorization": "[removed]",
"Content-type" : "application/json"
}
var options = {
headers: headers,
method: "GET"
}
var response = UrlFetchApp.fetch(url, options).getContentText();
var result = JSON.parse(response);console.log("result: ", result)
return result.records
}
I tried to altering the line:
for(i=0; i<ca.length; i++) {
but didn't work.
If you must log it to console, you could always log it while you are pushing it to the array instead of trying to log the entire array later.
console.log(ca_info.push([
fields.Name,
fields.Emails,
fields.Districts,
fields.Title,
fields.Course,
fields.Completed,
fields.StartDates
])
Related
I have a Google script trigger for tracking the plugin's version from all my wp websites by fetching an API from each website, I also attach the "last update" time to see the last time the API was called.
but when my trigger runs, it keeps resulting in the same data since the first call, even when I add/delete new plugins. From the error catch, the function runs smoothly but the result doesn't there.
why is it? do google script store the data? or is there any limitation in fetching API data?
edit
here's the code of the function to fetch the API and the trigger function
function teste()
{
var all_data = getDataFromPluginList()
/*return
[ { first_cell: 'A2',
last_cell: 'I8',
first_row: 2,
last_row: 8,
total_row: 7,
url: 'https://example1.wpengine.com/' },
{ first_cell: 'A10',
last_cell: 'I15',
first_row: 9,
last_row: 14,
total_row: 6,
url: 'https://example2.wpengine.com/' } ]
*/
for (var i = 0; i < all_data.length; i++) {
trigger_(all_data[i].url, all_data[i].first_row, all_data[i].last_row, all_data[i].total_row);
}
}
function trigger_(url, first_row, last_row, total_row)
{
var new_trigger = ScriptApp.newTrigger("writePluginData").timeBased().everyMinutes(1).create();
var trigger_id = new_trigger.getUniqueId();
PropertiesService.getUserProperties().setProperty(trigger_id, url+","+first_row+","+last_row+","+ total_row);
}
function writePluginData(event)
{
var trig = ScriptApp.getProjectTriggers();
let sheet_name = 'trigger_result';
let lowest_row = lowestRow(sheet_name);
for(var i =0; i<trig.length; i++)
{
if(trig[i].getUniqueId()== event.triggerUid )
{
var urlParam = PropertiesService.getUserProperties().getProperty(event.triggerUid);
urlParam = urlParam.split(",");
var url = urlParam[0];
var first_row = urlParam[1];
var last_row = urlParam[2];
var total_row = urlParam[3];
var new_first_row = 0;
var ss = SpreadsheetApp.getActive().getSheetByName(sheet_name); // change accordingly
var data = ListPlugins(url);
for (var i = 1; i < data.length; i++) {
let empty = ''
data[i].push(empty);
}
if(total_row != data[0][7]){
ss.deleteRows(first_row, first_row);
ss.getRange(lowest_row + 1 , 1,data[0][7],9).setValues(data);
} else {
ss.getRange(first_row, 1,total_row,9).setValues(data);
}
}
}
}
function ListPlugins(url) {
let sheet_name = 'apps and plugins'
var options = {
"async": true,
"crossDomain": true,
"method" : "GET",
"headers" : {
"Token" : TOKEN_HERE,
"cache-control": "no-cache"
}
};
var urlEncoded = encodeURI(url)
let api_url = urlEncoded + "/wp-json/bd/v1/public/plugin-list/"
var jsondata = UrlFetchApp.fetch(api_url,options)
var object = JSON.parse(jsondata.getContentText())
if(object){
return object;
} else {
return "not found"
}
}
and the result data would be like this
I have been trying to get an api call to Amazon SES to work for sending bulk emails. After figuring out issues with dates I'm now getting an error about the signatures mismatching. My code is below
function sendEmails() {
var template = HtmlService.createHtmlOutputFromFile('EmailTemplate.html');
var output = template.getContent();
var subject = 'Message from Mr. Bunz';
var data = JSON.stringify(
{
"Content": {
"Simple": {
"Body": {
"Html": {
"Data": output
},
},
"Subject": {
"Data": subject
}
},
},
"Destination": {
"ToAddresses": [ "example#gmail.com" ]
},
"FromEmailAddress": "no-reply#mail.example.com",
"ReplyToAddresses": [ "josh#example.com" ]
}
);
var url = 'https://email.us-west-1.amazonaws.com/v2/email/outbound-emails';
var aws_key_id = 'AKIAWLG4NO6GFEXAMPLE';
var aws_key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY';
var today = new Date();
var amz_date_iso = Utilities.formatDate(today,"UTC","YYYYMMd'T'HHmmss'Z'");
var amz_date = Utilities.formatDate(today,"UTC",'YYYYMMd');
console.log(amz_date)
var signature = awsSignature(aws_key,amz_date_iso);
var headers = {
"contentType": "application/json",
'X-Amz-Date': amz_date_iso,
"Authorization": "AWS4-HMAC-SHA256 Credential="+aws_key_id+"/"+amz_date+"/us-west-1/ses/aws4_request, SignedHeaders=content-type;host;x-amz-date;, Signature="+signature
};
console.log(headers);
var options = {
"method": "POST",
"headers": headers,
"payload": data,
"muteHttpExceptions" : true,
};
apiresponse = UrlFetchApp.fetch(url,options);
console.log(apiresponse.getContentText());
}
function awsSignature(key,dateStamp) {
var regionName = 'us-west-1';
var serviceName = 'iam';
var kDate = Utilities.computeHmacSha256Signature(dateStamp, "AWS4" + key);
var kRegion = Utilities.computeHmacSha256Signature(
Utilities.newBlob(regionName).getBytes(),
kDate
);
var kService = Utilities.computeHmacSha256Signature(
Utilities.newBlob(serviceName).getBytes(),
kRegion
);
var kSigning = Utilities.computeHmacSha256Signature(
Utilities.newBlob("aws4_request").getBytes(),
kService
);
kSigning = kSigning
.map(function(e) {
return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2);
})
.join("");
Logger.log(kSigning);
return kSigning;
}
The exact error message is below
{"message":"The request signature we calculated does not match the
signature you provided. Check your AWS Secret Access Key and signing
method. Consult the service documentation for details."}
I've tried generating a new key/id pair with no luck. The two answers on this issue on stackoverflow I have found are here and here.
I was getting a byte array back and couldn't figure out how to convert it into the needed signature so my implementation of creating the signature is based on this post.
Would greatly appreciate any and all help.
Update
After checking my signature code with the example values provided here I noticed that at the bottom where it gives the example output it says that while those are hex representations the actual signature should be binary. Now I'm having trouble converting hex to binary in GAS
Currently the script works totally fine but has one issue, every time there is an error, it stops, then I have to delete that row with error and run the script again.
What I want is, if there is an error then it should return the results as null and then move to next line item, so that there is no manual interruption.
function getSearchAnalytics(){
var service = getService();
if (service.hasAccess()) {
for(var i=7;i<525;i++){
var site = s_searchAnalytics.getRange(i, 1).getValue();
if (!site){
continue;
return null
}
var apiURL = 'https://www.googleapis.com/webmasters/v3/sites/' + URLDecode(site) + '/searchAnalytics/query?fields=rows&alt=json';
var lastRow = s_searchAnalytics.getLastRow();
s_searchAnalytics.getRange(i,2,lastRow,5).clear();
var headers = {"Authorization": "Bearer " + getService().getAccessToken()};
var payload = {
"startDate" : startDate,
"endDate" : endDate,
"dimensions" : ["device"],
"rowLimit" : "25000"
};
var options = {
"headers": headers,
"contentType":'application/json',
"method" : "post",
"payload" : JSON.stringify(payload),
"muteHttpExceptions": true
};
try {
var response = UrlFetchApp.fetch(apiURL, options);
}
catch (e) {
Logger.log(e);
}
Logger.log(response)
if (!response){
continue;
return null
}
var result = JSON.parse(response.getContentText());
if (result.error){
Browser.msgBox(result.error.errors[0].message);
return null
}
var row = []
for (var k in result.rows){
row.push([
result.rows[k].keys[0],
result.rows[k].metric1,
result.rows[k].metric2,
result.rows[k].metric3,
result.rows[k].position
]);
}
s_searchAnalytics.getRange(i,2,row.length,5).setValues(row);
}} else {
var authorizationUrl = service.getAuthorizationUrl();
Logger.log('Open the following URL and re-run the script: %s', authorizationUrl);
}
}
I tried to replicate your code and found some issues:
Using return statement in your loop with terminate the whole function. Instead, use only continue. In line 9 and 47: the code will never reach the return null because you already use continue. Continue will leave the current iteration and move to the next one.
Instead of using if(!response), It would be easier to determine if the API call has an error by identifying the response code.
Informational responses (100–199)
Successful responses (200–299)
Redirects (300–399)
Client errors (400–499)
Server errors (500–599)
By using the response code, we can prevent writes if the response code is not 200(OK).
Here I modified your code:
function getSearchAnalytics() {
var service = getService();
if (service.hasAccess()) {
for (var i = 7; i < 525; i++) {
var site = s_searchAnalytics.getRange(i, 1).getValue();
if (!site) {
continue;
}else{
var apiURL = 'https://www.googleapis.com/webmasters/v3/sites/' + URLDecode(site) + '/searchAnalytics/query?fields=rows&alt=json';
var startDate = Utilities.formatDate(s_searchAnalytics.getRange(2, 2).getValue(), "GMT+7", "yyyy-MM-dd");
var endDate = Utilities.formatDate(s_searchAnalytics.getRange(3, 2).getValue(), "GMT+7", "yyyy-MM-dd");
var lastRow = s_searchAnalytics.getLastRow();
s_searchAnalytics.getRange(i, 2, lastRow, 5).clear();
var headers = {
"Authorization": "Bearer " + getService().getAccessToken()
};
var payload = {
"startDate": startDate,
"endDate": endDate,
"dimensions": ["device"],
"rowLimit": "25000"
};
var options = {
"headers": headers,
"contentType": 'application/json',
"method": "post",
"payload": JSON.stringify(payload),
"muteHttpExceptions": true
};
try {
var response = UrlFetchApp.fetch(apiURL, options);
} catch (e) {
Logger.log(e);
}
Logger.log(response)
if (response.getResponseCode() == 200) {
var result = JSON.parse(response.getContentText());
var row = []
for (var k in result.rows) {
row.push([
result.rows[k].keys[0],
result.rows[k].clicks,
result.rows[k].impressions,
result.rows[k].ctr,
result.rows[k].position
]);
}
s_searchAnalytics.getRange(i, 2, row.length, 5).setValues(row);
}
}
}
} else {
var authorizationUrl = service.getAuthorizationUrl();
Logger.log('Open the following URL and re-run the script: %s', authorizationUrl);
}
}
Reference:
HTTP response status code
I took ideas from both your codes and it worked. Here is the final version that's working.
function getSearchAnalytics(){
var service = getService();
if (service.hasAccess()) {
for(var i=7;i<525;i++){
var site = s_searchAnalytics.getRange(i, 1).getValue();
if (!site){
continue;
return null
}
var apiURL = 'https://www.googleapis.com/webmasters/v3/sites/' + URLDecode(site) + '/searchAnalytics/query?fields=rows&alt=json';
var startDate = Utilities.formatDate(s_searchAnalytics.getRange(2, 2).getValue(), "GMT+7", "yyyy-MM-dd");
var endDate = Utilities.formatDate(s_searchAnalytics.getRange(3, 2).getValue(), "GMT+7", "yyyy-MM-dd");
var lastRow = s_searchAnalytics.getLastRow();
s_searchAnalytics.getRange(i,2,lastRow,5).clear();
var headers = {"Authorization": "Bearer " + getService().getAccessToken()};
var payload = {
"startDate" : startDate,
"endDate" : endDate,
"dimensions" : ["device"],
"rowLimit" : "25000"
};
var options = {
"headers": headers,
"contentType":'application/json',
"method" : "post",
"payload" : JSON.stringify(payload),
"muteHttpExceptions": true
};
try {
var response = UrlFetchApp.fetch(apiURL, options);
}
catch (e) {
Logger.log(e);
}
Logger.log(response)
if (response.getResponseCode() == 200) {
}
var result = JSON.parse(response.getContentText());
if (result.error){
continue;
return null
}
var row = []
for (var k in result.rows){
row.push([
result.rows[k].keys[0],
result.rows[k].clicks,
result.rows[k].impressions,
result.rows[k].ctr,
result.rows[k].position
]);
}
s_searchAnalytics.getRange(i,2,row.length,5).setValues(row);
}} else {
var authorizationUrl = service.getAuthorizationUrl();
Logger.log('Open the following URL and re-run the script: %s', authorizationUrl);
}
}
I have a script that iterates through an array and does a POST call to my API to create new records.
When it runs I see new records are created for each value in the array but I am unable to pass through the tens/u_department value (the array value) I'm having to do a switch because the input value is not valid in that format in my API.
How can I get the following responses from the below requests.
Requests
{"caller_id":"caller","description":"description","u_department":"A B.C"}
{"caller_id":"caller","description":"description","u_department":"D E.F"}
{"caller_id":"caller","description":"description","u_department":"H I.J"}
Desired Responses
{"result":{"caller_id":"caller","description":"description","u_department":"A B.C"},"record":"1"}}
{"result":{"caller_id":"caller","description":"description","u_department":"D E.F"},"record":"2"}}
{"result":{"caller_id":"caller","description":"description","u_department":"G H.I"},"record":"3"}}
Script
//Input tenants "ABC, DEF, GHI....."
var tens = "ABC, DEF, GHI"
console.log(tens);
var realten = input.tenants;
var realten = realten.split(',');
console.log(realten);
var letters = tens.split(',').map(string=>string.trim());
console.log(letters);
//Send data
var data = {};
var caller_id = "caller";
data.caller_id = caller_id;
var description = "description";
data.description = description;
//Convert tens to proper format
var site = {};
switch (realten[0]) {
case 'ABC':
site = "A B.C";
break;
case 'DEF':
site = "D E.F";
break;
case 'GHI':
site = "G H.I";
break;
case 'JKL':
site = "J K.L";
break;
case 'MNO':
site = "M N.O";
break;
}
var u_department = site;
data.u_department = u_department;
console.log(data)
//POST options
var options = {
'endpoint': 'test',
'path':'/api/table/records',
'method': 'POST',
"headers": {
"Authorization": "Basic xxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json"
} };
//I create following function:
function sendData(data) {
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
});
req.write(JSON.stringify(data));
}
//end try send for each array item:
for (var i=0; i<letters.length;i++) {
sendData(data[i]);
}
According to OP, sendData(data); is the correct solution.
I'm trying to parse JSON I recieved from an API call, but I keep running into the error "TypeError: Cannot read property "id" from undefined. (line 42, file "")" I'm relatively new to Apps Script. Any ideas on what's going on? I can get the payload back in JSON, but can't seem to parse it.
function getInfo() {
var url = "https://subdomain.chargify.com/subscriptions.json";
var username = "xxx"
var password = "x"
var headers = {
"Authorization": "Basic " + Utilities.base64Encode(username + ':' + password)
};
var options = {
"method": "GET",
"contentType": "application/json",
"headers": headers
};
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
Logger.log(data);
var id = data.subscription; // kicks back an error
// var id = data; works and returns the whole JSON payload
var ss = SpreadsheetApp.getActiveSheet()
var targetCell = ss.setActiveSelection("A1");
targetCell.setValue(id);
}
According to the documentation here
https://docs.chargify.com/api-subscriptions#api-usage-json-subscriptions-list
it returns an array of subscriptions when you call the /subscriptions.json endpoint. So probably your data object should be handled like:
for (var i=0;i<data.length;i++) {
var item = data[i]; //subscription object, where item.subscription probably works
Logger.log(JSON.stringify(item));
}
function getInfo() {
var url = "https://subdomain.chargify.com/subscriptions.json";
var username = "xxx"
var password = "x"
var headers = {
"Authorization": "Basic " + Utilities.base64Encode(username + ':' + password)
};
var options = {
"method": "GET",
"contentType": "application/json",
"headers": headers
};
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
for (var i = 0; i < data.length; i++) {
var item = data[i]; //subscription object, where item.subscription probably works
Logger.log(JSON.stringify(item));
var subscriptionid = item.subscription.id;
}
var ss = SpreadsheetApp.getActiveSheet()
var targetCell = ss.setActiveSelection("A2");
targetCell.setValue(subscriptionid);
}