├── api_013_paypal ├── .clasp.json ├── appsscript.json ├── Oauth.js └── Code.js ├── api_001_swapi ├── api_001_numbers.gs ├── api_001_swapi_v2.gs └── api_001_swapi_v1.gs ├── for_website ├── 001_numbers.gs ├── 002_itunes.gs └── 003_swapi.gs ├── README.md ├── api_011_stripe └── api_011_stripe.gs ├── api_005_slides └── api_005_slides_v1.gs ├── api_012_spotify ├── api_012_spotify_code.gs └── api_012_spotify_oauth.gs ├── api_006_github_oauth ├── Oauth.gs ├── helpers.gs └── Code.gs ├── api_010_ejunkie └── code.gs ├── api_002_mailchimp ├── measureSchool1.gs ├── api_002_mailchimp_listGrowth.gs ├── measureSchool2.gs ├── measureSchool3.gs └── api_002_mailchimp_v1.gs ├── api_009_gmail_service └── api_009_gmail.gs ├── api_004_itunes └── api_004_itunes_v1.gs ├── api_006_github └── api_006_github.gs ├── api_008_crunchbase └── api_008_crunchbase.gs ├── api_003_google_analytics └── api_003_google_analytics_v1.gs └── api_007_blogger_oauth2 └── api_007_blogger.gs /api_013_paypal/.clasp.json: -------------------------------------------------------------------------------- 1 | {"scriptId":"1ukfoz_HCNxo1N7mwsEcOpfWMudz0gK9KTK_lsGU5Q9MHe-fysz00maDL"} 2 | -------------------------------------------------------------------------------- /api_013_paypal/appsscript.json: -------------------------------------------------------------------------------- 1 | { 2 | "timeZone": "America/New_York", 3 | "dependencies": { 4 | }, 5 | "exceptionLogging": "STACKDRIVER" 6 | } -------------------------------------------------------------------------------- /api_001_swapi/api_001_numbers.gs: -------------------------------------------------------------------------------- 1 | function callNumbers() { 2 | 3 | // Call the Numbers API for random year 4 | var response = UrlFetchApp.fetch("http://numbersapi.com/random/year"); 5 | Logger.log(response.getContentText()); 6 | 7 | // Call a random number 8 | var number = Math.round(Math.random() * 1000); 9 | var response = UrlFetchApp.fetch("http://numbersapi.com/" + number); 10 | Logger.log("\n Random number fact:"); 11 | Logger.log(response.getContentText()); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /for_website/001_numbers.gs: -------------------------------------------------------------------------------- 1 | function onOpen() { 2 | var ui = SpreadsheetApp.getUi(); 3 | ui.createMenu('Custom Numbers API Menu') 4 | .addItem('Display random number fact','callNumbers') 5 | .addToUi(); 6 | } 7 | 8 | function callNumbers() { 9 | 10 | // Call the Numbers API for random math fact 11 | var response = UrlFetchApp.fetch("http://numbersapi.com/random/math"); 12 | Logger.log(response.getContentText()); 13 | 14 | var fact = response.getContentText(); 15 | var sheet = SpreadsheetApp.getActiveSheet(); 16 | sheet.getRange(sheet.getLastRow() + 1,1).setValue([fact]); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apps Script and APIs 2 | 3 | Collection of apps scripts for connecting to apis. Originally a 2017 project but something I'll be adding more to. 4 | 5 | To get started with Apps Script and APIs, [check out this tutorial I created](https://www.benlcollins.com/apps-script/beginner-apis/) 6 | 7 | New to Apps Script? Get started and learn just enough Apps Script to automate your Google Sheets workflows with my new course: [Apps Script Blastoff!](https://courses.benlcollins.com/p/apps-script-blastoff/) 8 | 9 | For a full list of Apps Script tutorials, [check out this list](https://www.benlcollins.com/articles/#AppsScript) 10 | -------------------------------------------------------------------------------- /api_011_stripe/api_011_stripe.gs: -------------------------------------------------------------------------------- 1 | var SECRET_API_KEY = 'Your secret key in here'; 2 | 3 | function callStripe() { 4 | 5 | // api URL 6 | var apiURL = 'https://api.stripe.com/'; 7 | 8 | // example endpoint 9 | var endpoint = "v1/charges" 10 | 11 | // request url 12 | var stripeURL = apiURL + endpoint; 13 | 14 | var headers = { 15 | "Authorization": "Bearer " + SECRET_API_KEY 16 | }; 17 | 18 | var options = { 19 | "headers": headers, 20 | "method" : "GET", 21 | "muteHttpExceptions": true 22 | }; 23 | 24 | var response = UrlFetchApp.fetch(stripeURL,options); 25 | 26 | Logger.log(response); 27 | } -------------------------------------------------------------------------------- /api_005_slides/api_005_slides_v1.gs: -------------------------------------------------------------------------------- 1 | function exportSheetToSlides() { 2 | 3 | /* Setup: 4 | * Resources > Libraires and add library id 1-8n9YfGU1IBDmagna_1xZRHdB3c2jOuFdUrBmUDy64ITRfyhQoXH5lHc 5 | * H/T Spencer Easton https://plus.google.com/u/0/+SpencerEastonCCS/posts/gK1jmbFH5kT 6 | * Go to Developers Console and enable Drive API and Slides API 7 | */ 8 | 9 | // name of our slide template 10 | var TEMPLATEFILE = 'sheets_to_slides_template'; 11 | 12 | // get authorization 13 | SlidesAPI.setTokenService(function(){ 14 | return ScriptApp.getOAuthToken() 15 | }); 16 | 17 | // make copy of slide template and get the ID 18 | var DECK_ID = DriveApp.getFilesByName(TEMPLATEFILE).next().makeCopy().getId(); 19 | 20 | // log the ID 21 | Logger.log(DECK_ID); 22 | } 23 | 24 | -------------------------------------------------------------------------------- /api_013_paypal/Oauth.js: -------------------------------------------------------------------------------- 1 | /** 2 | * access client ID and client secret from user properties 3 | */ 4 | // first time running script, need to add the client id and secret to user properties 5 | // var CLIENT_ID = '...'; 6 | // var CLIENT_SECRET = '...'; 7 | // thereafter, access them from user properties 8 | var CLIENT_ID = getUserProperty('CLIENT_ID'); 9 | var CLIENT_SECRET = getUserProperty('CLIENT_SECRET'); 10 | 11 | /** 12 | * Adds client ID and client secret to user properties 13 | */ 14 | function addToUserProps() { 15 | var userProperties = PropertiesService.getUserProperties(); 16 | var clientProperties = { 17 | CLIENT_ID: CLIENT_ID, 18 | CLIENT_SECRET: CLIENT_SECRET 19 | } 20 | userProperties.setProperties(clientProperties,true); // true argument deletes all other properties in the store 21 | } 22 | 23 | function getUserProperty(key) { 24 | var userProperties = PropertiesService.getUserProperties(); 25 | return userProperties.getProperty(key); 26 | } 27 | 28 | function viewUserProperties() { 29 | Logger.log(CLIENT_ID); 30 | Logger.log(CLIENT_SECRET); 31 | } -------------------------------------------------------------------------------- /api_012_spotify/api_012_spotify_code.gs: -------------------------------------------------------------------------------- 1 | // Get Rate limit 2 | function getSpotifyData() { 3 | // set up the service 4 | var service = getSpotifyService_(); 5 | 6 | if (service.hasAccess()) { 7 | Logger.log("App has access."); 8 | 9 | var base = "https://api.spotify.com"; 10 | //var endpoint = "/v1/me"; 11 | var endpoint = "/v1/me/tracks"; 12 | 13 | var headers = { 14 | "Authorization": "Bearer " + getSpotifyService_().getAccessToken() 15 | }; 16 | 17 | var options = { 18 | "headers": headers, 19 | "method" : "GET", 20 | "muteHttpExceptions": true 21 | }; 22 | 23 | var response = JSON.parse(UrlFetchApp.fetch(base + endpoint, options)); 24 | 25 | Logger.log(response); 26 | // {error={message=Insufficient client scope, status=403}} 27 | 28 | } 29 | else { 30 | Logger.log("App has no access yet."); 31 | 32 | // open this url to gain authorization from github 33 | var authorizationUrl = service.getAuthorizationUrl(); 34 | Logger.log("Open the following URL and re-run the script: %s", 35 | authorizationUrl); 36 | } 37 | } -------------------------------------------------------------------------------- /api_006_github_oauth/Oauth.gs: -------------------------------------------------------------------------------- 1 | var CLIENT_ID = 'Insert your client ID'; 2 | var CLIENT_SECRET = 'Insert your client secret'; 3 | 4 | // configure the service 5 | function getGithubService_() { 6 | return OAuth2.createService('GitHub') 7 | .setAuthorizationBaseUrl('https://github.com/login/oauth/authorize') 8 | .setTokenUrl('https://github.com/login/oauth/access_token') 9 | .setClientId(CLIENT_ID) 10 | .setClientSecret(CLIENT_SECRET) 11 | .setCallbackFunction('authCallback') 12 | .setPropertyStore(PropertiesService.getUserProperties()) 13 | .setScope('user'); 14 | } 15 | 16 | // Logs the redict URI to register 17 | // can also get this from File > Project Properties 18 | function logRedirectUri() { 19 | var service = getGithubService_(); 20 | Logger.log(service.getRedirectUri()); 21 | } 22 | 23 | 24 | // handle the callback 25 | function authCallback(request) { 26 | var githubService = getGithubService_(); 27 | var isAuthorized = githubService.handleCallback(request); 28 | if (isAuthorized) { 29 | return HtmlService.createHtmlOutput('Success! You can close this tab.'); 30 | } else { 31 | return HtmlService.createHtmlOutput('Denied. You can close this tab'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /api_006_github_oauth/helpers.gs: -------------------------------------------------------------------------------- 1 | // Gets date from ISO 8601 format into local format 2 | // code from: http://stackoverflow.com/questions/11810441/how-do-i-format-this-date-string-so-that-google-scripts-recognizes-it 3 | // Created by M Hawksey 4 | function getDateFromIso(string) { 5 | try{ 6 | var aDate = new Date(); 7 | var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" + 8 | "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\\.([0-9]+))?)?" + 9 | "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"; 10 | var d = string.match(new RegExp(regexp)); 11 | 12 | var offset = 0; 13 | var date = new Date(d[1], 0, 1); 14 | 15 | if (d[3]) { date.setMonth(d[3] - 1); } 16 | if (d[5]) { date.setDate(d[5]); } 17 | if (d[7]) { date.setHours(d[7]); } 18 | if (d[8]) { date.setMinutes(d[8]); } 19 | if (d[10]) { date.setSeconds(d[10]); } 20 | if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); } 21 | if (d[14]) { 22 | offset = (Number(d[16]) * 60) + Number(d[17]); 23 | offset *= ((d[15] == '-') ? 1 : -1); 24 | } 25 | 26 | offset -= date.getTimezoneOffset(); 27 | time = (Number(date) + (offset * 60 * 1000)); 28 | return aDate.setTime(Number(time)); 29 | } catch(e){ 30 | return; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /api_010_ejunkie/code.gs: -------------------------------------------------------------------------------- 1 | // Ejunkie can send an HTTP POST data to a common notification url 2 | // Apps Script can receive the POST request and output data to sheet 3 | // Read more here: http://www.e-junkie.com/ej/help.integration.htm 4 | 5 | function doPost(e) { 6 | 7 | var ss= SpreadsheetApp.openById(""); 8 | var sheet = ss.getSheetByName("Sheet1"); 9 | 10 | var outputArray = []; 11 | 12 | if(typeof e !== 'undefined') { 13 | var data = e.parameter; 14 | 15 | outputArray.push( 16 | data.ej_txn_id, 17 | data.invoice, 18 | data.payment_date, 19 | data.item_name, 20 | data.from_email, 21 | data.receiver_email, 22 | data.discount_codes, 23 | data.mc_gross, 24 | data.payment_type, 25 | data.payer_id, 26 | data.payer_email, 27 | data.first_name, 28 | data.last_name, 29 | data.residence_country, 30 | data.payer_status, 31 | data.payment_status, 32 | data.payment_gross, 33 | data.buyer_ip, 34 | data.affiliate_id, 35 | data.item_affiliate_fee_total, 36 | data.receiver_id, 37 | data.mc_currency, 38 | data.payer_business_name, 39 | data.payment_fee 40 | ); 41 | 42 | sheet.appendRow(outputArray); 43 | } 44 | 45 | return; 46 | } -------------------------------------------------------------------------------- /api_002_mailchimp/measureSchool1.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Mailchimp API - Get Campaign Data into Google Sheets 4 | * By Ben Collins 2017 5 | * http://www.benlcollins.com/ 6 | * 7 | */ 8 | 9 | var API_KEY = ''; 10 | var LIST_ID = ''; 11 | 12 | // call the Mailchimip API to get campaign data 13 | // This gets all campaigns in an account 14 | function mailchimpCampaign() { 15 | 16 | // URL and params for the Mailchimp API 17 | var root = 'https://us11.api.mailchimp.com/3.0/'; 18 | var endpoint = 'campaigns?count=100'; 19 | 20 | // parameters for url fetch 21 | var params = { 22 | 'method': 'GET', 23 | 'muteHttpExceptions': true, 24 | 'headers': { 25 | 'Authorization': 'apikey ' + API_KEY 26 | } 27 | }; 28 | 29 | // call the Mailchimp API 30 | var response = UrlFetchApp.fetch(root+endpoint, params); 31 | var data = response.getContentText(); 32 | var json = JSON.parse(data); 33 | 34 | Logger.log(json); 35 | 36 | // get just campaign data 37 | var campaigns = json['campaigns']; 38 | 39 | // Log the campaign stats 40 | Logger.log("Number of campaigns: " + campaigns.length); 41 | 42 | // print out all the campaign headings 43 | campaigns.forEach(function(campaign) { 44 | Logger.log(campaign["settings"]["subject_line"]); 45 | }); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /api_012_spotify/api_012_spotify_oauth.gs: -------------------------------------------------------------------------------- 1 | var CLIENT_ID = ''; 2 | var CLIENT_SECRET = ''; 3 | 4 | // configure the service 5 | function getSpotifyService_() { 6 | return OAuth2.createService('Spotify') 7 | .setAuthorizationBaseUrl('https://accounts.spotify.com/authorize') 8 | .setTokenUrl('https://accounts.spotify.com/api/token') 9 | .setClientId(CLIENT_ID) 10 | .setClientSecret(CLIENT_SECRET) 11 | .setCallbackFunction('authCallback') 12 | .setPropertyStore(PropertiesService.getUserProperties()) 13 | .setScope('user-library-read'); 14 | } 15 | 16 | // Logs the redict URI to register 17 | // can also get this from File > Project Properties 18 | function logRedirectUri() { 19 | var service = getSpotifyService_(); 20 | Logger.log(service.getRedirectUri()); 21 | } 22 | 23 | 24 | // handle the callback 25 | function authCallback(request) { 26 | var spotifyService = getSpotifyService_(); 27 | var isAuthorized = spotifyService.handleCallback(request); 28 | if (isAuthorized) { 29 | return HtmlService.createHtmlOutput('Success! You can close this tab.'); 30 | } else { 31 | return HtmlService.createHtmlOutput('Denied. You can close this tab'); 32 | } 33 | } 34 | 35 | // {images=[], followers={total=2, href=null}, href=https://api.spotify.com/v1/users/benlcollins, 36 | // id=benlcollins, display_name=null, type=user, external_urls={spotify=https://open.spotify.com/user/benlcollins}, 37 | // uri=spotify:user:benlcollins} -------------------------------------------------------------------------------- /api_002_mailchimp/api_002_mailchimp_listGrowth.gs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * 3 | * API experiments 2017 #002 4 | * Exploring the MailChimp API 5 | * Retrives MailChimp list growth data and populates a Google Sheet 6 | * 7 | */ 8 | 9 | 10 | function listGrowth() { 11 | 12 | // get mailchimp api key from properties service 13 | var apikey = getApiKey(); 14 | 15 | var listID = getListID(); 16 | 17 | var endpointListGrowth = 'lists/' + listID + '/growth-history'; 18 | 19 | var listGrowth = mailchimpEndpoint(endpointListGrowth)['history']; 20 | 21 | //Logger.log(listGrowth); 22 | 23 | // [{existing=3070, optins=77, imports=0, list_id=77e612d207, month=2017-03, _links=[{...}]}, 24 | 25 | var monthlyGrowth = []; 26 | 27 | listGrowth.forEach(function(el) { 28 | monthlyGrowth.push([el.month, el.existing, el.optins, el.imports]); 29 | }); 30 | 31 | return monthlyGrowth; 32 | } 33 | 34 | 35 | // add the campaign data to our sheet 36 | function getListGrowth() { 37 | 38 | var data = listGrowth().reverse(); 39 | Logger.log(data); 40 | 41 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 42 | var sheet = ss.getSheetByName('List Growth'); 43 | 44 | var numRows = data.length; 45 | var numCols = data[0].length; 46 | 47 | sheet.getRange(4,1,numRows,numCols).setValues(data); 48 | 49 | for (var i = 0; i < numRows; i++) { 50 | sheet.getRange(4+i,5).setFormulaR1C1('=iferror(R[0]C[-3] - R[-1]C[-3],0)'); // absolute monthly change in list 51 | sheet.getRange(4+i,6).setFormulaR1C1('=iferror((R[0]C[-4] - R[-1]C[-4])/R[-1]C[-4],0)').setNumberFormat("0.00%"); // rate of change in list 52 | } 53 | 54 | } 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /api_009_gmail_service/api_009_gmail.gs: -------------------------------------------------------------------------------- 1 | /* 2 | * Script to extract names email and addresses for a specific label in Gmail 3 | * Created by Ben Collins, March 2017 4 | * Read more: 5 | * http://www.benlcollins.com/apps-script/extract-email-from-gmail/ 6 | * 7 | */ 8 | 9 | // add menu to Sheet 10 | function onOpen() { 11 | var ui = SpreadsheetApp.getUi(); 12 | ui.createMenu('Extract Emails') 13 | .addItem('Extract Emails...', 'extractEmails') 14 | .addToUi(); 15 | } 16 | 17 | 18 | // extract emails from label in Gmail 19 | function extractEmails() { 20 | 21 | // get the spreadsheet 22 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 23 | var sheet = ss.getActiveSheet(); 24 | var label = sheet.getRange(1,2).getValue(); 25 | 26 | // get all email threads that match label from Sheet 27 | var threads = GmailApp.search ("label:" + label); 28 | 29 | // get all the messages for the current batch of threads 30 | var messages = GmailApp.getMessagesForThreads (threads); 31 | 32 | var emailArray = []; 33 | 34 | // get array of email addresses 35 | messages.forEach(function(message) { 36 | message.forEach(function(d) { 37 | emailArray.push(d.getFrom(),d.getTo()); 38 | }); 39 | }); 40 | 41 | // de-duplicate the array 42 | var uniqueEmailArray = emailArray.filter(function(item, pos) { 43 | return emailArray.indexOf(item) == pos; 44 | }); 45 | 46 | var cleanedEmailArray = uniqueEmailArray.map(function(el) { 47 | var name = ""; 48 | var email = ""; 49 | 50 | var matches = el.match(/\s*"?([^"]*)"?\s+<(.+)>/); 51 | 52 | if (matches) { 53 | name = matches[1]; 54 | email = matches[2]; 55 | } 56 | else { 57 | name = "N/k"; 58 | email = el; 59 | } 60 | 61 | return [name,email]; 62 | }).filter(function(d) { 63 | if ( 64 | d[1] !== "benlcollins@gmail.com" && 65 | d[1] !== "drive-shares-noreply@google.com" && 66 | d[1] !== "wordpress@www.benlcollins.com" 67 | ) { 68 | return d; 69 | } 70 | }); 71 | 72 | // clear any old data 73 | sheet.getRange(4,1,sheet.getLastRow(),2).clearContent(); 74 | 75 | // paste in new names and emails and sort by email address A - Z 76 | sheet.getRange(4,1,cleanedEmailArray.length,2).setValues(cleanedEmailArray).sort(2); 77 | 78 | } -------------------------------------------------------------------------------- /for_website/002_itunes.gs: -------------------------------------------------------------------------------- 1 | // -------------------------------------------------------------------------------------------------- 2 | // 3 | // iTunes Music Discovery Application in Google Sheets 4 | // 5 | // -------------------------------------------------------------------------------------------------- 6 | 7 | // custom menu 8 | function onOpen() { 9 | var ui = SpreadsheetApp.getUi(); 10 | ui.createMenu('Custom iTunes Menu') 11 | .addItem('Get Artist Data','displayArtistData') 12 | .addToUi(); 13 | } 14 | 15 | // function to call iTunes API 16 | function calliTunesAPI(artist) { 17 | 18 | // Call the iTunes API 19 | var response = UrlFetchApp.fetch("https://itunes.apple.com/search?term=" + artist + "&limit=200"); 20 | 21 | // Parse the JSON reply 22 | var json = response.getContentText(); 23 | return JSON.parse(json); 24 | 25 | } 26 | 27 | 28 | function displayArtistData() { 29 | 30 | // pick up the search term from the Google Sheet 31 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 32 | var sheet = ss.getActiveSheet(); 33 | 34 | var artist = sheet.getRange(11,2).getValue(); 35 | 36 | var tracks = calliTunesAPI(artist); 37 | 38 | var results = tracks["results"]; 39 | 40 | var output = [] 41 | 42 | results.forEach(function(elem,i) { 43 | var image = '=image("' + elem["artworkUrl60"] + '",4,60,60)'; 44 | var hyperlink = '=hyperlink("' + elem["previewUrl"] + '","Listen to preview")'; 45 | output.push([elem["artistName"],elem["collectionName"],elem["trackName"],image,hyperlink]); 46 | sheet.setRowHeight(i+15,65); 47 | }); 48 | 49 | // sort by album 50 | var sortedOutput = output.sort( function(a,b) { 51 | 52 | var albumA = (a[1]) ? a[1] : 'Not known'; 53 | var albumB = (b[1]) ? b[1] : 'Not known'; 54 | 55 | if (albumA < albumB) { 56 | return -1; 57 | } 58 | else if (albumA > albumB) { 59 | return 1; 60 | } 61 | // names are equal 62 | return 0; 63 | }); 64 | 65 | // adds an index number to the array 66 | sortedOutput.forEach(function(elem,i) { 67 | elem.unshift(i + 1); 68 | }); 69 | 70 | var len = sortedOutput.length; 71 | 72 | // clear any previous content 73 | sheet.getRange(15,1,500,6).clearContent(); 74 | 75 | // paste in the values 76 | sheet.getRange(15,1,len,6).setValues(sortedOutput); 77 | 78 | // formatting 79 | sheet.getRange(15,1,500,6).setVerticalAlignment("middle"); 80 | sheet.getRange(15,5,500,1).setHorizontalAlignment("center"); 81 | sheet.getRange(15,2,len,3).setWrap(true); 82 | 83 | } -------------------------------------------------------------------------------- /api_002_mailchimp/measureSchool2.gs: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * Mailchimp API - Get Campaign Data into Google Sheets 4 | * By Ben Collins 2017 5 | * http://www.benlcollins.com/ 6 | * 7 | */ 8 | 9 | var API_KEY = ''; 10 | var LIST_ID = ''; 11 | 12 | // setup menu to run print Mailchimp function from Sheet 13 | function onOpen() { 14 | var ui = SpreadsheetApp.getUi(); 15 | 16 | ui.createMenu('MailChimp Menu') 17 | .addItem('Get campaign data', 'mailchimpCampaign') 18 | .addToUi(); 19 | } 20 | 21 | /** 22 | * call the Mailchimip API to get campaign data 23 | * This gets all campaigns in an account 24 | */ 25 | function mailchimpCampaign() { 26 | 27 | // URL and params for the Mailchimp API 28 | var root = 'https://us11.api.mailchimp.com/3.0/'; 29 | var endpoint = 'campaigns?count=100'; 30 | 31 | // parameters for url fetch 32 | var params = { 33 | 'method': 'GET', 34 | 'muteHttpExceptions': true, 35 | 'headers': { 36 | 'Authorization': 'apikey ' + API_KEY 37 | } 38 | }; 39 | 40 | try { 41 | // call the Mailchimp API 42 | var response = UrlFetchApp.fetch(root+endpoint, params); 43 | var data = response.getContentText(); 44 | var json = JSON.parse(data); 45 | 46 | // get just campaign data 47 | var campaigns = json['campaigns']; 48 | 49 | // blank array to hold the campaign data for Sheet 50 | var campaignData = []; 51 | 52 | // Add the campaign data to the array 53 | for (var i = 0; i < campaigns.length; i++) { 54 | 55 | // put the campaign data into a double array for Google Sheets 56 | if (campaigns[i]["emails_sent"] != 0) { 57 | campaignData.push([ 58 | i, 59 | campaigns[i]["send_time"].substr(0,10), 60 | campaigns[i]["settings"]["title"], 61 | campaigns[i]["settings"]["subject_line"], 62 | campaigns[i]["recipients"]["recipient_count"], 63 | campaigns[i]["emails_sent"], 64 | (campaigns[i]["report_summary"]) ? campaigns[i]["report_summary"]["unique_opens"] : 0, 65 | (campaigns[i]["report_summary"]) ? campaigns[i]["report_summary"]["subscriber_clicks"] : 0 66 | ]); 67 | } 68 | else { 69 | campaignData.push([ 70 | i, 71 | "Not sent", 72 | campaigns[i]["settings"]["title"], 73 | campaigns[i]["settings"]["subject_line"], 74 | campaigns[i]["recipients"]["recipient_count"], 75 | campaigns[i]["emails_sent"], 76 | "N/a", 77 | "N/a" 78 | ]); 79 | } 80 | } 81 | 82 | // Log the campaignData array 83 | Logger.log(campaignData); 84 | 85 | // select the campaign output sheet 86 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 87 | var sheet = ss.getSheetByName('Campaign Analysis'); 88 | 89 | // calculate the number of rows and columns needed 90 | var numRows = campaignData.length; 91 | var numCols = campaignData[0].length; 92 | 93 | // output the numbers to the sheet 94 | sheet.getRange(4,1,numRows,numCols).setValues(campaignData); 95 | 96 | // adds formulas to calculate open rate and click rate 97 | for (var i = 0; i < numRows; i++) { 98 | sheet.getRange(4+i,9).setFormulaR1C1('=iferror(R[0]C[-2]/R[0]C[-3]*100,"N/a")'); 99 | sheet.getRange(4+i,10).setFormulaR1C1('=iferror(R[0]C[-2]/R[0]C[-4]*100,"N/a")'); 100 | } 101 | 102 | } 103 | catch (error) { 104 | // deal with any errors 105 | Logger.log(error); 106 | }; 107 | 108 | 109 | } -------------------------------------------------------------------------------- /api_013_paypal/Code.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Add custom menu 3 | */ 4 | function onOpen() { 5 | SpreadsheetApp.getUi() 6 | .createMenu('PayPal App') 7 | .addItem('Import Transactions', 'postTransactionsToSheet') 8 | .addToUi(); 9 | } 10 | 11 | /** 12 | * paste transaction data into Google Sheet 13 | */ 14 | function postTransactionsToSheet() { 15 | 16 | // empty array to hold data for Sheet 17 | var allData = []; 18 | 19 | // get transactions 20 | var transactionData = getTransactions().transaction_details; 21 | //Logger.log(transactionData); 22 | 23 | transactionData.forEach(function(transaction) { 24 | Logger.log(transaction); 25 | 26 | var row = []; 27 | var info = transaction.transaction_info; 28 | var transaction_id = info.transaction_id; 29 | var transaction_value = info.transaction_amount.value; 30 | var transaction_currency = info.transaction_amount.currency_code; 31 | var transaction_note = info.transaction_note ? info.transaction_note : 'N/a'; 32 | var transaction_subject = info.transaction_subject ? info.transaction_subject : 'N/a'; 33 | var ending_balance_value = info.ending_balance.value; 34 | var transaction_date = info.transaction_initiation_date; 35 | 36 | row.push( 37 | transaction_id, 38 | transaction_date, 39 | transaction_value, 40 | transaction_currency, 41 | transaction_note, 42 | transaction_subject, 43 | ending_balance_value 44 | ); 45 | 46 | allData.push(row); 47 | 48 | }); 49 | 50 | Logger.log(allData); 51 | 52 | // get spreadsheet 53 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 54 | var sheet = ss.getSheetByName('Sheet1'); 55 | 56 | // range to paste data 57 | var range = sheet.getRange(sheet.getLastRow() + 1,1,allData.length,7); 58 | 59 | range.setValues(allData); 60 | 61 | } 62 | 63 | 64 | /** 65 | * get paypal transactions from api 66 | */ 67 | function getTransactions() { 68 | 69 | var access_token = getAccessToken(); 70 | 71 | var transactionBase = 'https://api.paypal.com/v1/reporting/transactions'; 72 | var startDate = '2019-01-01T00:00:00-0700'; 73 | var endDate = '2019-01-31T23:59:59-0700'; 74 | var transactionEndpoint = transactionBase + '?start_date=' + startDate + '&end_date=' + endDate; 75 | 76 | var head = { 77 | 'Authorization':'Bearer ' + access_token, 78 | 'Content-Type': 'application/json' 79 | } 80 | 81 | var params = { 82 | headers: head, 83 | method: 'get', 84 | muteHttpExceptions: true 85 | } 86 | 87 | try { 88 | var response = UrlFetchApp.fetch(transactionEndpoint, params); 89 | var responseCode = response.getResponseCode(); 90 | Logger.log(responseCode); 91 | 92 | var responseBody = response.getContentText(); 93 | //Logger.log(responseBody); 94 | return JSON.parse(responseBody); 95 | } 96 | catch(e){ 97 | Logger.log(e); 98 | } 99 | } 100 | 101 | 102 | /** 103 | * get access token request 104 | */ 105 | function getAccessToken() { 106 | 107 | var tokenEndpoint = 'https://api.paypal.com/v1/oauth2/token'; 108 | 109 | var head = { 110 | 'Authorization':'Basic ' + Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET), 111 | 'Accept': 'application/json', 112 | 'Content-Type': 'application/x-www-form-urlencoded' 113 | } 114 | 115 | var postPayload = { 116 | 'grant_type' : 'client_credentials' 117 | } 118 | 119 | var params = { 120 | headers: head, 121 | contentType: 'application/x-www-form-urlencoded', 122 | method : 'post', 123 | payload : postPayload, 124 | muteHttpExceptions: true 125 | } 126 | 127 | var response = UrlFetchApp.fetch(tokenEndpoint, params); 128 | var result = response.getContentText(); 129 | var resultObject = JSON.parse(result); 130 | //Logger.log(resultObject); 131 | 132 | return resultObject.access_token; 133 | 134 | } 135 | -------------------------------------------------------------------------------- /api_004_itunes/api_004_itunes_v1.gs: -------------------------------------------------------------------------------- 1 | function onOpen() { 2 | var ui = SpreadsheetApp.getUi(); 3 | ui.createMenu('Custom iTunes Menu') 4 | .addItem('Get Artist Data','displayArtistData') 5 | .addToUi(); 6 | } 7 | 8 | 9 | // -------------------------------------------------------------------------------------------------- 10 | // 11 | // Step 1: Most basic call to the API 12 | // 13 | // -------------------------------------------------------------------------------------------------- 14 | 15 | function calliTunes() { 16 | 17 | // Call the iTunes API 18 | var response = UrlFetchApp.fetch("https://itunes.apple.com/search?term=coldplay&limit=5"); 19 | Logger.log(response.getContentText()); 20 | } 21 | 22 | 23 | // -------------------------------------------------------------------------------------------------- 24 | // 25 | // Step 2: Parse the response 26 | // 27 | // -------------------------------------------------------------------------------------------------- 28 | 29 | function calliTunes2() { 30 | 31 | // Call the iTunes API 32 | var response = UrlFetchApp.fetch("https://itunes.apple.com/search?term=metallica&limit=200"); 33 | 34 | // Parse the JSON reply 35 | var json = response.getContentText(); 36 | var data = JSON.parse(json); 37 | 38 | Logger.log(data); 39 | //Logger.log(data["results"][0]); 40 | Logger.log(data["results"][0]["artistName"]); 41 | Logger.log(data["results"][0]["collectionName"]); 42 | Logger.log(data["results"][0]["artworkUrl60"]); 43 | Logger.log(data["results"][0]["previewUrl"]); 44 | 45 | Logger.log(data["results"][3]); 46 | Logger.log("New"); 47 | Logger.log(data["results"][7]); 48 | 49 | } 50 | 51 | 52 | // -------------------------------------------------------------------------------------------------- 53 | // 54 | // Step 3: Output the results 55 | // 56 | // -------------------------------------------------------------------------------------------------- 57 | 58 | function calliTunesAPI(artist) { 59 | 60 | // Call the iTunes API 61 | var response = UrlFetchApp.fetch("https://itunes.apple.com/search?term=" + artist + "&limit=200"); 62 | 63 | // Parse the JSON reply 64 | var json = response.getContentText(); 65 | return JSON.parse(json); 66 | 67 | } 68 | 69 | 70 | function displayArtistData() { 71 | 72 | // pick up the search term from the Google Sheet 73 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 74 | var sheet = ss.getActiveSheet(); 75 | 76 | var artist = sheet.getRange(11,2).getValue(); 77 | 78 | var tracks = calliTunesAPI(artist); 79 | 80 | var results = tracks["results"]; 81 | 82 | var output = [] 83 | 84 | results.forEach(function(elem,i) { 85 | var image = '=image("' + elem["artworkUrl60"] + '",4,60,60)'; 86 | var hyperlink = '=hyperlink("' + elem["previewUrl"] + '","Listen to preview")'; 87 | output.push([elem["artistName"],elem["collectionName"],elem["trackName"],image,hyperlink]); 88 | sheet.setRowHeight(i+15,65); 89 | }); 90 | 91 | // sort by album 92 | var sortedOutput = output.sort( function(a,b) { 93 | 94 | var albumA = (a[1]) ? a[1] : 'Not known'; 95 | var albumB = (b[1]) ? b[1] : 'Not known'; 96 | 97 | if (albumA < albumB) { 98 | return -1; 99 | } 100 | else if (albumA > albumB) { 101 | return 1; 102 | } 103 | // names are equal 104 | return 0; 105 | }); 106 | 107 | 108 | // return > 50 results 109 | 110 | //Logger.log(sortedOutput); 111 | 112 | sortedOutput.forEach(function(elem,i) { 113 | elem.unshift(i + 1); 114 | Logger.log(elem); 115 | Logger.log(i); 116 | }); 117 | 118 | 119 | var len = sortedOutput.length; 120 | 121 | sheet.getRange(15,1,500,6).clearContent(); 122 | 123 | sheet.getRange(15,1,len,6).setValues(sortedOutput); 124 | 125 | // formatting 126 | sheet.getRange(15,1,500,6).setVerticalAlignment("middle"); 127 | sheet.getRange(15,5,500,1).setHorizontalAlignment("center"); 128 | sheet.getRange(15,2,len,3).setWrap(true); 129 | 130 | 131 | } 132 | 133 | 134 | -------------------------------------------------------------------------------- /api_006_github/api_006_github.gs: -------------------------------------------------------------------------------- 1 | // GitHub API <> Google Sheets 2 | // currently just a straight http call 3 | // need to build authenticated version of app to get better rate limits 4 | // 5 | // read more about api here: https://developer.github.com/v3/ 6 | 7 | function onOpen() { 8 | var ui = SpreadsheetApp.getUi(); 9 | ui.createMenu('Custom GitHub Menu') 10 | .addItem('Get User Repos','getUserRepos') 11 | .addItem('Get Repo languages','getRepoLanguages') 12 | .addItem('Get GitHub Rate Limit','getGitHubRateLimit') 13 | .addToUi(); 14 | } 15 | 16 | 17 | // get all the repos for username in google sheet 18 | // cycle through, print out the repo names in sheet 19 | // make into a drop down menu 20 | // create a chart of languages used in the repo 21 | 22 | function getUserRepos() { 23 | 24 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 25 | var sheet = ss.getSheetByName("Github dashboard"); 26 | var workings = ss.getSheetByName("workings"); 27 | 28 | var username = sheet.getRange(3,2).getValue(); 29 | sheet.getRange(5,2).clearContent(); 30 | //Logger.log(username); 31 | 32 | var baseURL = "https://api.github.com/"; 33 | 34 | var response = UrlFetchApp.fetch(baseURL + "users/" + username + "/repos"); 35 | 36 | // Parse the JSON reply 37 | var json = response.getContentText(); 38 | var data = JSON.parse(json); 39 | 40 | var repoNames = []; 41 | 42 | data.forEach(function(elem) { 43 | repoNames.push([elem["name"]]); 44 | }); 45 | 46 | Logger.log(repoNames); 47 | 48 | workings.getRange(1,1,repoNames.length,1).setValues(repoNames); 49 | 50 | } 51 | 52 | 53 | function getRepoLanguages() { 54 | 55 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 56 | var sheet = ss.getSheetByName("Github dashboard"); 57 | 58 | var username = sheet.getRange(3,2).getValue(); 59 | var repoName = sheet.getRange(4,2).getValue(); 60 | 61 | var baseURL = "https://api.github.com/repos/"; 62 | 63 | var response = UrlFetchApp.fetch(baseURL + username + "/" + repoName + "/languages"); 64 | 65 | // Parse the JSON reply 66 | var json = response.getContentText(); // string 67 | var data = JSON.parse(json); // object 68 | 69 | Logger.log(typeof json); // string 70 | Logger.log(json); // {"Ruby":53927,"HTML":47401,"CSS":25427,"JavaScript":667} 71 | Logger.log(json["Ruby"]); // undefined 72 | 73 | Logger.log(typeof data); // object 74 | Logger.log(data); // {CSS=25427, JavaScript=667, HTML=47401, Ruby=53927} 75 | 76 | // create an array of index and key/value pairs 77 | var langs = Object.keys(data).map(function(key,index) { 78 | return [index + 1,key,data[key]]; 79 | }); 80 | 81 | Logger.log(langs); // [[0, Ruby, 53927], [1, HTML, 47401], [2, CSS, 25427], [3, JavaScript, 667]] <-- array of rows 82 | 83 | // clear any old repo language info 84 | sheet.getRange(9,1,500,3).clear(); 85 | 86 | // paste in the new repo language info 87 | sheet.getRange(9,1,langs.length,3).setValues(langs); 88 | 89 | // format the index column to be centre aligned 90 | sheet.getRange(9,1,langs.length,1).setHorizontalAlignment('center'); 91 | 92 | } 93 | 94 | 95 | function getGitHubRateLimit() { 96 | 97 | var response = UrlFetchApp.fetch("https://api.github.com/rate_limit"); 98 | var json = response.getContentText(); 99 | var data = JSON.parse(json); 100 | 101 | Logger.log(json); 102 | Logger.log(data["resources"]["core"]["reset"]); 103 | 104 | //{"resources":{"core":{"limit":60,"remaining":0,"reset":1486061428},"search":{"limit":10,"remaining":10,"reset":1486061134}},"rate":{"limit":60,"remaining":0,"reset":1486061428}} 105 | 106 | var callsRemaining = data["resources"]["core"]["remaining"]; 107 | var resetTime = data["resources"]["core"]["reset"]; 108 | 109 | Logger.log(time(resetTime)); 110 | 111 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 112 | var sheet = ss.getSheetByName("Github dashboard"); 113 | 114 | var remainingCell = sheet.getRange(5,2).clear(); 115 | remainingCell.setValue(callsRemaining).setHorizontalAlignment('center'); 116 | 117 | } 118 | 119 | function time(ms) { 120 | return new Date(ms).toLocaleString(); 121 | } 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /api_008_crunchbase/api_008_crunchbase.gs: -------------------------------------------------------------------------------- 1 | /* 2 | * Crunchbase API integration 3 | * 4 | * http://www.benlcollins.com/apps-script/crunchbase/ 5 | * 6 | * First step is to register for basic account (Free) 7 | * https://about.crunchbase.com/forms/apply-basic-access/ 8 | * 9 | * Email support for user key if you don't get one 10 | * 11 | */ 12 | 13 | var USER_KEY = 'Put your API user key in here'; 14 | 15 | function onOpen() { 16 | SpreadsheetApp.getUi() 17 | .createMenu('Crunchbase Data') 18 | .addItem('Retrieve organization data...', 'getCrunchbaseOrgs') 19 | .addItem('Retrieve people data...', 'getCrunchbasePeople') 20 | .addToUi(); 21 | } 22 | 23 | 24 | // function to retrive people data 25 | function getCrunchbasePeople() { 26 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 27 | var sheet = ss.getSheetByName('People'); 28 | var query = sheet.getRange(3,2).getValue(); 29 | 30 | // URL and params for the Crunchbase API 31 | var url = 'https://api.crunchbase.com/v/3/odm-people?query=' + encodeURI(query) + '&user_key=' + USER_KEY; 32 | 33 | var json = getCrunchbaseData(url,query); 34 | 35 | if (json[0] === "Error:") { 36 | // deal with error with fetch operation 37 | sheet.getRange(5,1,sheet.getLastRow(),2).clearContent(); 38 | sheet.getRange(6,1,1,2).setValues([json]); 39 | } 40 | else { 41 | if (json[0] !== 200) { 42 | // deal with error from api 43 | sheet.getRange(5,1,sheet.getLastRow(),2).clearContent(); 44 | sheet.getRange(6,1,1,2).setValues([["Error, server returned code:",json[0]]]); 45 | } 46 | else { 47 | var data = json[1].data.items[0].properties; 48 | 49 | // correct data comes back, parse into array for Google Sheet 50 | var outputData = [ 51 | ["Name",data.first_name + ' ' + data.last_name], 52 | ["Gender",data.gender], 53 | ["Type",data.organization_name], 54 | ["Short description",data.title], 55 | ["Country",data.country_code], 56 | ["Region",data.region_name], 57 | ["Website url",data.homepage_url], 58 | ["Facebook",data.facebook_url], 59 | ["Linkedin",data.linkedin_url], 60 | ["Twitter",data.twitter_url], 61 | ["Crunchbase URL","https://www.crunchbase.com/" + data.web_path], 62 | ["Crunchbase Organization URL","https://www.crunchbase.com/" + data.organization_web_path] 63 | ]; 64 | 65 | // clear any old data 66 | sheet.getRange(5,1,sheet.getLastRow(),2).clearContent(); 67 | 68 | // insert new data 69 | sheet.getRange(6,1,12,2).setValues(outputData); 70 | 71 | // add image with formula and format that row 72 | sheet.getRange(5,2).setFormula('=image("' + data.profile_image_url + '",4,50,50)').setHorizontalAlignment("center"); 73 | sheet.setRowHeight(5,60); 74 | } 75 | } 76 | } 77 | 78 | 79 | // function to retrive organizations data 80 | function getCrunchbaseOrgs() { 81 | 82 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 83 | var sheet = ss.getSheetByName('Organizations'); 84 | var query = sheet.getRange(3,2).getValue(); 85 | 86 | // URL and params for the Crunchbase API 87 | var url = 'https://api.crunchbase.com/v/3/odm-organizations?query=' + encodeURI(query) + '&user_key=' + USER_KEY; 88 | 89 | var json = getCrunchbaseData(url,query); 90 | 91 | if (json[0] === "Error:") { 92 | // deal with error with fetch operation 93 | sheet.getRange(5,1,sheet.getLastRow(),2).clearContent(); 94 | sheet.getRange(6,1,1,2).setValues([json]); 95 | } 96 | else { 97 | if (json[0] !== 200) { 98 | // deal with error from api 99 | sheet.getRange(5,1,sheet.getLastRow(),2).clearContent(); 100 | sheet.getRange(6,1,1,2).setValues([["Error, server returned code:",json[0]]]); 101 | } 102 | else { 103 | // correct data comes back, filter down to match the name of the entity 104 | var data = json[1].data.items.filter(function(item) { 105 | return item.properties.name == query; 106 | })[0].properties; 107 | 108 | // parse into array for Google Sheet 109 | var outputData = [ 110 | ["Name",data.name], 111 | ["Homepage",data.homepage_url], 112 | ["Type",data.primary_role], 113 | ["Short description",data.short_description], 114 | ["Country",data.country_code], 115 | ["Region",data.region_name], 116 | ["City name",data.city_name], 117 | ["Blog url",data.blog_url], 118 | ["Facebook",data.facebook_url], 119 | ["Linkedin",data.linkedin_url], 120 | ["Twitter",data.twitter_url], 121 | ["Crunchbase URL","https://www.crunchbase.com/" + data.web_path] 122 | ]; 123 | 124 | // clear any old data 125 | sheet.getRange(5,1,sheet.getLastRow(),2).clearContent(); 126 | 127 | // insert new data 128 | sheet.getRange(6,1,12,2).setValues(outputData); 129 | 130 | // add image with formula and format that row 131 | sheet.getRange(5,2).setFormula('=image("' + data.profile_image_url + '",4,50,50)').setHorizontalAlignment("center"); 132 | sheet.setRowHeight(5,60); 133 | } 134 | } 135 | } 136 | 137 | 138 | // general query to call Crunchbase API 139 | function getCrunchbaseData(url,query) { 140 | 141 | try { 142 | var response = UrlFetchApp.fetch(url); // POST emails to mailchimp 143 | var responseData = response.getContentText(); 144 | var responseCode = response.getResponseCode(); 145 | var json = JSON.parse(responseData); 146 | return [responseCode,json]; 147 | } 148 | catch (e) { 149 | Logger.log(e); 150 | return ["Error:", e]; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /api_002_mailchimp/measureSchool3.gs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * 3 | * Mailchimp API - Get Campaign Data into Google Sheets 4 | * By Ben Collins 2017 5 | * http://www.benlcollins.com/ 6 | * 7 | */ 8 | 9 | var API_KEY = ''; 10 | var LIST_ID = ''; 11 | 12 | 13 | /******************************************************************************** 14 | * call the Mailchimip API to get campaign data 15 | * This gets all campaigns in an account 16 | */ 17 | function mailchimpCampaign() { 18 | 19 | // URL and params for the Mailchimp API 20 | var root = 'https://us11.api.mailchimp.com/3.0/'; 21 | var endpoint = 'campaigns?count=100'; 22 | 23 | // parameters for url fetch 24 | var params = { 25 | 'method': 'GET', 26 | 'muteHttpExceptions': true, 27 | 'headers': { 28 | 'Authorization': 'apikey ' + API_KEY 29 | } 30 | }; 31 | 32 | try { 33 | // call the Mailchimp API 34 | var response = UrlFetchApp.fetch(root+endpoint, params); 35 | var data = response.getContentText(); 36 | var json = JSON.parse(data); 37 | 38 | // get just campaign data 39 | var campaigns = json['campaigns']; 40 | 41 | // blank array to hold the campaign data for Sheet 42 | var campaignData = []; 43 | 44 | // Add the campaign data to the array 45 | for (var i = 0; i < campaigns.length; i++) { 46 | 47 | // put the campaign data into a double array for Google Sheets 48 | if (campaigns[i]["emails_sent"] != 0) { 49 | campaignData.push([ 50 | i, 51 | campaigns[i]["send_time"].substr(0,10), 52 | campaigns[i]["settings"]["title"], 53 | campaigns[i]["settings"]["subject_line"], 54 | campaigns[i]["recipients"]["recipient_count"], 55 | campaigns[i]["emails_sent"], 56 | (campaigns[i]["report_summary"]) ? campaigns[i]["report_summary"]["unique_opens"] : 0, 57 | (campaigns[i]["report_summary"]) ? campaigns[i]["report_summary"]["subscriber_clicks"] : 0 58 | ]); 59 | } 60 | else { 61 | campaignData.push([ 62 | i, 63 | "Not sent", 64 | campaigns[i]["settings"]["title"], 65 | campaigns[i]["settings"]["subject_line"], 66 | campaigns[i]["recipients"]["recipient_count"], 67 | campaigns[i]["emails_sent"], 68 | "N/a", 69 | "N/a" 70 | ]); 71 | } 72 | } 73 | 74 | // Log the campaignData array 75 | Logger.log(campaignData); 76 | 77 | // select the campaign output sheet 78 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 79 | var sheet = ss.getSheetByName('Campaign Analysis'); 80 | 81 | // calculate the number of rows and columns needed 82 | var numRows = campaignData.length; 83 | var numCols = campaignData[0].length; 84 | 85 | // output the numbers to the sheet 86 | sheet.getRange(4,1,numRows,numCols).setValues(campaignData); 87 | 88 | // adds formulas to calculate open rate and click rate 89 | for (var i = 0; i < numRows; i++) { 90 | sheet.getRange(4+i,9).setFormulaR1C1('=iferror(R[0]C[-2]/R[0]C[-3]*100,"N/a")'); 91 | sheet.getRange(4+i,10).setFormulaR1C1('=iferror(R[0]C[-2]/R[0]C[-4]*100,"N/a")'); 92 | } 93 | 94 | } 95 | catch (error) { 96 | // deal with any errors 97 | Logger.log(error); 98 | }; 99 | 100 | } 101 | 102 | 103 | /******************************************************************************** 104 | * 105 | * Retrives MailChimp list growth data and populates a Google Sheet 106 | * 107 | */ 108 | function mailchimpListGrowth() { 109 | 110 | // URL and params for the Mailchimp API 111 | var root = 'https://us11.api.mailchimp.com/3.0/'; 112 | var endpoint = 'lists/' + LIST_ID + '/growth-history?count=100'; 113 | 114 | var params = { 115 | 'method': 'GET', 116 | 'muteHttpExceptions': true, 117 | 'headers': { 118 | 'Authorization': 'apikey ' + API_KEY 119 | } 120 | }; 121 | 122 | try { 123 | // call the Mailchimp API 124 | var response = UrlFetchApp.fetch(root+endpoint, params); 125 | var data = response.getContentText(); 126 | var json = JSON.parse(data); 127 | 128 | // get just list history data 129 | var listGrowth = json['history']; 130 | 131 | // blank array to hold the list growth data for Sheet 132 | var monthlyGrowth = []; 133 | 134 | // Add the list growth data to the array 135 | listGrowth.forEach(function(el) { 136 | monthlyGrowth.push([el.month, el.existing, el.optins, el.imports]); 137 | }); 138 | 139 | // Log the monthlyGrowth array 140 | Logger.log(monthlyGrowth); 141 | 142 | // select the list growth output sheet 143 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 144 | var sheet = ss.getSheetByName('List Growth'); 145 | 146 | // calculate the number of rows and columns needed 147 | var numRows = monthlyGrowth.length; 148 | var numCols = monthlyGrowth[0].length; 149 | 150 | // output the numbers to the sheet 151 | sheet.getRange(4,1,numRows,numCols).setValues(monthlyGrowth.reverse()); 152 | 153 | // adds formulas for absolute and relative growth 154 | for (var i = 0; i < numRows; i++) { 155 | sheet.getRange(4+i,5).setFormulaR1C1('=iferror(R[0]C[-3] - R[-1]C[-3],0)'); // absolute monthly change in list 156 | sheet.getRange(4+i,6).setFormulaR1C1('=iferror((R[0]C[-4] - R[-1]C[-4])/R[-1]C[-4],0)').setNumberFormat("0.00%"); // rate of change in list 157 | } 158 | 159 | } 160 | catch (error) { 161 | // deal with any errors 162 | Logger.log(error); 163 | }; 164 | 165 | } 166 | -------------------------------------------------------------------------------- /api_003_google_analytics/api_003_google_analytics_v1.gs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * 3 | * API experiments 2017 #003 4 | * Exploring the Google Analytics API 5 | * Retrives GA data and populates a Google Sheet 6 | * Apps Script Advanced Service 7 | * 8 | */ 9 | 10 | 11 | // setup menu to run print Mailchimp function from Sheet 12 | function onOpen() { 13 | var ui = SpreadsheetApp.getUi(); 14 | 15 | ui.createMenu('Google Analytics Menu') 16 | .addItem('Get Analytics data', 'gaReport') 17 | .addToUi(); 18 | 19 | } 20 | 21 | 22 | // script properties service 23 | // retrive copy of ga profile id 24 | function getProfileId() { 25 | var properties = PropertiesService.getScriptProperties(); 26 | return properties.getProperty('gaProfileId'); 27 | } 28 | 29 | // get the dates from the Sheet 30 | function getDates() { 31 | 32 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 33 | var sheet = ss.getSheetByName("workings"); 34 | 35 | var chosenPeriod = sheet.getRange(7,2).getValue(); 36 | var today = new Date(); 37 | 38 | // use Object literal approach instead of switch or if/else for this lookup 39 | var startDateCalculator = function(n) { 40 | return new Date(today.getTime() - n * 24 * 60 * 60 * 1000); 41 | } 42 | 43 | var periods = { 44 | 'Last 7 days': function() { 45 | return [chosenPeriod, startDateCalculator(7), today]; 46 | }, 47 | 'Last 14 days': function() { 48 | return [chosenPeriod, startDateCalculator(14), today]; 49 | }, 50 | 'Last 30 days': function() { 51 | return [chosenPeriod, startDateCalculator(30), today]; 52 | }, 53 | 'Last Quarter': function() { 54 | var newArr = getPreviousQuarter(today) 55 | newArr.unshift(chosenPeriod); 56 | return newArr; 57 | }, 58 | 'Year To Date': function() { 59 | return [chosenPeriod, new Date(today.getFullYear(),0,1), today]; 60 | }, 61 | 'Last Year': function() { 62 | return [chosenPeriod, new Date(today.getFullYear()-1,0,1), new Date(today.getFullYear()-1,11,31)]; 63 | }, 64 | 'Custom Range': function() { 65 | var startDateChosen = sheet.getRange(9,2).getValue(); 66 | var endDateChosen = sheet.getRange(10,2).getValue(); 67 | if (endDateChosen < startDateChosen) { 68 | 69 | // To Do: refactor this part of the application 70 | // still getting this error: 71 | // TypeError: Cannot read property "0" from undefined. 72 | Browser.msgBox("End date cannot precede Start date", Browser.Buttons.OK); 73 | return [chosenPeriod, startDateChosen, startDateChosen] 74 | } 75 | else { 76 | return [chosenPeriod, startDateChosen,endDateChosen]; 77 | } 78 | } 79 | }; 80 | 81 | return periods[chosenPeriod](); 82 | 83 | } 84 | 85 | 86 | // find out which quarter the date is in 87 | // return the two dates of the previous full quarter 88 | function getPreviousQuarter(date) { 89 | 90 | var startQuarter, endQuarter; 91 | var quarter = Math.ceil((date.getMonth() + 1)/ 3); 92 | 93 | //Logger.log(quarter); 94 | 95 | switch (quarter) { 96 | case 1.0: 97 | startQuarter = new Date(date.getFullYear() - 1,9,1); 98 | endQuarter = new Date(date.getFullYear() - 1,11,31); 99 | break; 100 | case 2.0: 101 | startQuarter = new Date(date.getFullYear(),0,1); 102 | endQuarter = new Date(date.getFullYear(),2,31); 103 | break; 104 | case 3.0: 105 | startQuarter = new Date(date.getFullYear(),3,1); 106 | endQuarter = new Date(date.getFullYear(),5,30); 107 | break; 108 | case 4.0: 109 | startQuarter = new Date(date.getFullYear(),6,1); 110 | endQuarter = new Date(date.getFullYear(),8,30); 111 | } 112 | 113 | //Logger.log([startQuarter,endQuarter]); 114 | return [startQuarter,endQuarter]; 115 | } 116 | 117 | 118 | // run Google Analytics report 119 | function gaReport() { 120 | 121 | var profileId = getProfileId(); 122 | var chosenDateRange = getDates()[0]; 123 | var startDate = Utilities.formatDate(getDates()[1], Session.getScriptTimeZone(),'yyyy-MM-dd'); 124 | var endDate = Utilities.formatDate(getDates()[2], Session.getScriptTimeZone(),'yyyy-MM-dd'); 125 | 126 | var tableId = 'ga:' + profileId; 127 | var metric = 'ga:visits'; 128 | var options = { 129 | 'dimensions': 'ga:deviceCategory', 130 | 'sort': '-ga:visits', 131 | 'filters': 'ga:medium==organic', 132 | 'max-results': 25 // actually redundant in this example with deviceCategory 133 | }; 134 | 135 | var report = Analytics.Data.Ga.get(tableId, startDate, endDate, metric, 136 | options); 137 | 138 | //Logger.log(report["query"]); 139 | // [[desktop, 4215], [mobile, 224], [tablet, 57]] 140 | // {end-date=2017-01-15, max-results=25, start-index=1, ids=ga:93306374, 141 | // start-date=2017-01-08, sort=[-ga:visits], filters=ga:medium==organic, 142 | // metrics=[ga:visits], dimensions=ga:deviceCategory} 143 | 144 | displayGAData(chosenDateRange,report); 145 | 146 | 147 | } 148 | 149 | 150 | // display output in Google Sheet 151 | function displayGAData(dateRange,data) { 152 | 153 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 154 | var sheet = ss.getSheetByName("Output"); 155 | 156 | var timestamp = new Date(); 157 | 158 | var output = [ 159 | timestamp, 160 | data["query"]["dimensions"], 161 | data["query"]["metrics"][0], 162 | data["query"]["filters"], 163 | dateRange, 164 | data["query"]["start-date"], 165 | data["query"]["end-date"], 166 | data["rows"][0][1], 167 | data["rows"][1][1], 168 | data["rows"][2][1] 169 | ]; 170 | 171 | Logger.log(output); 172 | 173 | sheet.appendRow(output); 174 | 175 | } 176 | -------------------------------------------------------------------------------- /api_006_github_oauth/Code.gs: -------------------------------------------------------------------------------- 1 | // add custom menu 2 | function onOpen() { 3 | var ui = SpreadsheetApp.getUi(); 4 | ui.createMenu('Custom GitHub Menu') 5 | .addItem('Get User Repos','getUserRepos') 6 | .addItem('Get repo commit statistics...','getGitHubStatistics') 7 | .addItem('Get rate quota','getGitHubRateLimit') 8 | .addToUi(); 9 | } 10 | 11 | 12 | // https://developer.github.com/v3/repos/commits/#list-commits-on-a-repository 13 | // https://developer.github.com/v3/repos/statistics/#get-the-last-year-of-commit-activity-data 14 | 15 | // TO DO: 16 | // DRY - make a general function for calling the api 17 | 18 | 19 | /***************************************/ 20 | // Get Rate limit 21 | function getGitHubRateLimit() { 22 | // set up the service 23 | var service = getGithubService_(); 24 | 25 | if (service.hasAccess()) { 26 | Logger.log("App has access."); 27 | 28 | var api = "https://api.github.com/rate_limit"; 29 | 30 | var headers = { 31 | "Authorization": "Bearer " + getGithubService_().getAccessToken(), 32 | "Accept": "application/vnd.github.v3+json" 33 | }; 34 | 35 | var options = { 36 | "headers": headers, 37 | "method" : "GET", 38 | "muteHttpExceptions": true 39 | }; 40 | 41 | var response = UrlFetchApp.fetch(api, options); 42 | 43 | var json = JSON.parse(response.getContentText()); 44 | var responseCode = response.getResponseCode(); 45 | 46 | Logger.log(responseCode); 47 | 48 | Logger.log("You have " + json.rate.remaining + " requests left this hour."); 49 | 50 | } 51 | else { 52 | Logger.log("App has no access yet."); 53 | 54 | // open this url to gain authorization from github 55 | var authorizationUrl = service.getAuthorizationUrl(); 56 | Logger.log("Open the following URL and re-run the script: %s", 57 | authorizationUrl); 58 | } 59 | } 60 | 61 | 62 | 63 | /***************************************/ 64 | // Get Repo Stats Data 65 | // first time you run this you may get a 202 message back 66 | // this means your data hasn't been cached by github 67 | // but they will kick off a background worker to compile your stats 68 | // run script again a few minutes later and you should get stats back 69 | // read more at the top of this page in the docs: 70 | // https://developer.github.com/v3/repos/statistics/#get-the-last-year-of-commit-activity-data 71 | function getGitHubStatistics() { 72 | 73 | // set up the service 74 | var service = getGithubService_(); 75 | 76 | if (service.hasAccess()) { 77 | Logger.log("App has access."); 78 | 79 | var api = "https://api.github.com/repos/benlcollins/apps_script/stats/commit_activity"; 80 | 81 | var headers = { 82 | "Authorization": "Bearer " + getGithubService_().getAccessToken(), 83 | "Accept": "application/vnd.github.v3+json" 84 | }; 85 | 86 | var options = { 87 | "headers": headers, 88 | "method" : "GET", 89 | "muteHttpExceptions": true 90 | }; 91 | 92 | var response = UrlFetchApp.fetch(api, options); 93 | 94 | var json = JSON.parse(response.getContentText()); 95 | var responseCode = response.getResponseCode(); 96 | 97 | Logger.log(responseCode); 98 | 99 | Logger.log(json); 100 | 101 | outputWeeklyCommitStats(json); 102 | 103 | } 104 | else { 105 | Logger.log("App has no access yet."); 106 | 107 | // open this url to gain authorization from github 108 | var authorizationUrl = service.getAuthorizationUrl(); 109 | Logger.log("Open the following URL and re-run the script: %s", 110 | authorizationUrl); 111 | } 112 | } 113 | 114 | 115 | function outputWeeklyCommitStats (data) { 116 | 117 | var outputArray = []; 118 | 119 | data.forEach(function(item,i) { 120 | var tempDaysArray = []; 121 | item.days.forEach(function(day) { 122 | tempDaysArray.push(day); 123 | }) 124 | outputArray.push(tempDaysArray); 125 | }); 126 | 127 | var newOutputArray = outputArray[0].map(function(col, i) { 128 | return outputArray.map(function(row) { 129 | return row[i]; 130 | }); 131 | }); 132 | 133 | Logger.log(newOutputArray); 134 | 135 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 136 | var sheet = ss.getSheetByName('Data'); 137 | /* 138 | var testArray = [[0, 0, 0, 4, 3, 0, 0], 139 | [0, 8, 0, 0, 3, 0, 0], 140 | [1, 0, 0, 4, 3, 2, 0]]; 141 | 142 | Logger.log(testArray[0]); 143 | 144 | var newTestArray = testArray[0].map(function(col, i) { 145 | return testArray.map(function(row) { 146 | return row[i]; 147 | }); 148 | }); 149 | 150 | Logger.log(newTestArray); 151 | 152 | var testArray2 = [[0,0,1], 153 | [0,8,9], 154 | [0,0,0], 155 | [4,0,4], 156 | [3,3,3], 157 | [0,0,2], 158 | [0,0,0]]; 159 | */ 160 | sheet.getRange(4,2,7,52).setValues(newOutputArray); 161 | 162 | } 163 | 164 | 165 | 166 | 167 | /***************************************/ 168 | // Get Event Data 169 | function getGitHubData() { 170 | 171 | // set up the service 172 | var service = getGithubService_(); 173 | 174 | if (service.hasAccess()) { 175 | Logger.log("App has access."); 176 | 177 | // https://developer.github.com/v3/activity/events/#list-events-performed-by-a-user 178 | var api = "https://api.github.com/users/benlcollins/events"; 179 | 180 | 181 | 182 | var headers = { 183 | "Authorization": "Bearer " + getGithubService_().getAccessToken(), 184 | "Accept": "application/vnd.github.v3+json" 185 | }; 186 | 187 | var options = { 188 | "headers": headers, 189 | "method" : "GET", 190 | "muteHttpExceptions": true 191 | }; 192 | 193 | var response = UrlFetchApp.fetch(api, options); 194 | 195 | var json = JSON.parse(response.getContentText()); 196 | var responseCode = response.getResponseCode(); 197 | 198 | Logger.log(responseCode); 199 | 200 | json.forEach(function(item) { 201 | Logger.log("Repo update: " + item.repo.name + " at " + new Date(getDateFromIso(item.created_at)) + " of type " + item.type); 202 | }); 203 | } 204 | else { 205 | Logger.log("App has no access yet."); 206 | 207 | // open this url to gain authorization from github 208 | var authorizationUrl = service.getAuthorizationUrl(); 209 | Logger.log("Open the following URL and re-run the script: %s", 210 | authorizationUrl); 211 | } 212 | } 213 | 214 | -------------------------------------------------------------------------------- /api_007_blogger_oauth2/api_007_blogger.gs: -------------------------------------------------------------------------------- 1 | var CLIENT_ID = '...'; 2 | var CLIENT_SECRET = '...'; 3 | var BLOG_ID = '...'; 4 | 5 | /* 6 | * Based on the following work by others; 7 | * https://mashe.hawksey.info/2015/10/setting-up-oauth2-access-with-google-apps-script-blogger-api-example/ 8 | * https://github.com/googlesamples/apps-script-oauth2 9 | * https://developers.google.com/blogger/docs/3.0/getting_started 10 | * 11 | **/ 12 | 13 | // add custom menu 14 | function onOpen() { 15 | var ui = SpreadsheetApp.getUi(); 16 | ui.createMenu('Custom Blogger Menu') 17 | .addItem('Get Blogger Posts','getBloggerPosts') 18 | .addItem('Publish post on Blogger','postToBlogger') 19 | .addToUi(); 20 | } 21 | 22 | 23 | 24 | // configure the service 25 | function getBloggerService_() { 26 | return OAuth2.createService('Blogger') 27 | .setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth') 28 | .setTokenUrl('https://accounts.google.com/o/oauth2/token') 29 | .setClientId(CLIENT_ID) 30 | .setClientSecret(CLIENT_SECRET) 31 | .setCallbackFunction('authCallback') 32 | .setPropertyStore(PropertiesService.getUserProperties()) 33 | .setScope('https://www.googleapis.com/auth/blogger'); // this is blogger scope 34 | } 35 | 36 | // Logs the redict URI to register 37 | function logRedirectUri() { 38 | var service = getBloggerService_(); 39 | Logger.log(service.getRedirectUri()); 40 | } 41 | 42 | 43 | // handle the callback 44 | function authCallback(request) { 45 | var bloggerService = getBloggerService_(); 46 | var isAuthorized = bloggerService.handleCallback(request); 47 | if (isAuthorized) { 48 | return HtmlService.createHtmlOutput('Success! You can close this tab.'); 49 | } else { 50 | return HtmlService.createHtmlOutput('Denied. You can close this tab'); 51 | } 52 | } 53 | 54 | // Step 1: call the blogger API and get list of blogger sites associated with this google account 55 | function getBloggerSites() { 56 | var service = getBloggerService_(); 57 | 58 | if (service.hasAccess()) { 59 | Logger.log("App has access."); 60 | var api = "https://www.googleapis.com/blogger/v3/users/self/blogs"; 61 | 62 | var headers = { 63 | "Authorization": "Bearer " + getBloggerService_().getAccessToken() 64 | }; 65 | 66 | var options = { 67 | "headers": headers, 68 | "method" : "GET", 69 | "muteHttpExceptions": true 70 | }; 71 | 72 | var response = UrlFetchApp.fetch(api, options); 73 | 74 | var json = JSON.parse(response.getContentText()); 75 | 76 | var bloggerIds = []; 77 | 78 | for (var i in json.items) { 79 | Logger.log("%s %s", json.items[i].name, json.items[i].url); 80 | bloggerIds.push(json.items[i].id); 81 | } 82 | Logger.log(bloggerIds); 83 | //return bloggerIds; 84 | } 85 | else { 86 | Logger.log("App has no access yet."); 87 | 88 | // this was the step I was missing originally 89 | // open this url to gain authorization from blogger 90 | var authorizationUrl = service.getAuthorizationUrl(); 91 | Logger.log('Open the following URL and re-run the script: %s', 92 | authorizationUrl); 93 | } 94 | } 95 | 96 | 97 | // Step 2: get list of all posts for specific blogger site 98 | function getBloggerPosts() { 99 | var service = getBloggerService_(); 100 | var blogId = BLOG_ID; // the id for my blogger site Data Chops 101 | 102 | var api = 'https://www.googleapis.com/blogger/v3/blogs/' + blogId + '/posts'; 103 | 104 | var headers = { 105 | "Authorization": "Bearer " + getBloggerService_().getAccessToken() 106 | }; 107 | 108 | var options = { 109 | "headers": headers, 110 | "method" : "GET", 111 | "muteHttpExceptions": true 112 | }; 113 | 114 | var response = UrlFetchApp.fetch(api, options); 115 | 116 | var json = JSON.parse(response.getContentText()); 117 | var posts = json["items"]; 118 | 119 | Logger.log(posts.length); // result is 8, which matches the number of blog posts at http://datachops.blogspot.com/ 120 | //Logger.log(posts[0]); 121 | 122 | var postsArray = []; 123 | 124 | for (var i = 0; i < posts.length; i++) { 125 | var authorName = posts[i]["author"]["displayName"]; 126 | //var authorImage = '=image("https:' + posts[i]["author"]["image"]["url"] + '",4,60,60)'; 127 | var publishedDate = posts[i]["published"]; 128 | var publishedUrl = posts[i]["url"]; 129 | var title = posts[i]["title"]; 130 | //var content = posts[i]["content"]; 131 | 132 | postsArray.push([publishedDate,title,publishedUrl,authorName/*,authorImage,content*/]); 133 | } 134 | 135 | Logger.log(postsArray); 136 | 137 | outputToSheet(postsArray); 138 | 139 | } 140 | 141 | 142 | // print out results to sheet 143 | function outputToSheet(post) { 144 | 145 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 146 | var publishedPosts = ss.getSheetByName('Published Posts'); 147 | 148 | publishedPosts.getRange(4,1,publishedPosts.getLastRow(),4).clearContent(); 149 | 150 | var outputRange = publishedPosts.getRange(4,1,post.length,4).setValues(post); 151 | 152 | /* 153 | // only need this snippet of code when i'm including thumbnail author images 154 | for (var i = 0; i < post.length; i++) { 155 | publishedPosts.setRowHeight(i + 4,65); 156 | } 157 | */ 158 | } 159 | 160 | 161 | // posting blog post from google sheet to blogger 162 | // need to get the content from the sheet into suitable json format 163 | // then post to blogger 164 | function postToBlogger() { 165 | 166 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 167 | var toPublish = ss.getSheetByName('To Publish'); 168 | 169 | var kind = toPublish.getRange(4,1).getValue(); 170 | var blogId = toPublish.getRange(4,2).getValue(); 171 | var title = toPublish.getRange(4,3).getValue(); 172 | var content = toPublish.getRange(4,4).getValue(); 173 | 174 | var body = JSON.stringify({ 175 | 'kind': kind, 176 | 'blog': { 177 | 'id': blogId 178 | }, 179 | 'title': title, 180 | 'content': content 181 | }); 182 | 183 | Logger.log(body); 184 | 185 | var service = getBloggerService_(); 186 | 187 | if (service.hasAccess()) { 188 | var api = 'https://www.googleapis.com/blogger/v3/blogs/' + blogId + '/posts/'; 189 | 190 | var headers = { 191 | 'Authorization': 'Bearer ' + getBloggerService_().getAccessToken() 192 | }; 193 | 194 | var options = { 195 | 'headers': headers, 196 | 'method' : 'post', 197 | 'contentType': 'application/json', 198 | 'payload': body, 199 | 'muteHttpExceptions': true 200 | }; 201 | 202 | try { 203 | var response = UrlFetchApp.fetch(api, options); 204 | 205 | var responseCode = response.getResponseCode(); 206 | Logger.log(responseCode); 207 | var json = JSON.parse(response.getContentText()); 208 | Logger.log(json); 209 | } 210 | catch(err) { 211 | Logger.log(err); // error with url fetch call 212 | } 213 | } 214 | else { 215 | var authorizationUrl = service.getAuthorizationUrl(); 216 | Logger.log('Open the following URL and re-run the script: %s', 217 | authorizationUrl); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /for_website/003_swapi.gs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * 3 | * API experiments 2017 4 | * Exploring the Star Wars API: http://swapi.co/api/ 5 | * Retrives Star Wars data and populates a Google Sheet 6 | * Drop-down menu controls for user to choose categories/items 7 | * 8 | */ 9 | 10 | function swapiCategories() { 11 | 12 | // get the categories from the api 13 | var categories = function () { 14 | 15 | try { 16 | var response = UrlFetchApp.fetch("http://swapi.co/api/"); 17 | var data = response.getContentText(); 18 | var json = JSON.parse(data); 19 | var keys = Object.keys(json); 20 | return keys; 21 | } 22 | catch(e) { 23 | Logger.log("Error: " + e.message); // log error message 24 | } 25 | 26 | }; 27 | 28 | Logger.log(categories()); // [people, planets, films, species, vehicles, starships] 29 | 30 | // set up spreadsheet variables 31 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 32 | var apiSheet = ss.getSheetByName("api tool"); 33 | var workingsSheet = ss.getSheetByName("workings"); 34 | 35 | // get the value from the spreadsheet corresponding to user's choice 36 | var category = apiSheet.getRange(4,3).getValue().toLowerCase(); 37 | 38 | // get the corresponding item names in this category 39 | var catData = categoryData(category); 40 | var catNames = getCategoryNames(category,catData); 41 | 42 | Logger.log(catData); 43 | Logger.log(catNames); 44 | // [[Luke Skywalker], [C-3PO], [R2-D2], [Darth Vader], [Leia Organa], [Owen Lars], 45 | // [Beru Whitesun lars], [R5-D4], [Biggs Darklighter], [Obi-Wan Kenobi]] 46 | 47 | // paste into our sheet as a drop down menu 48 | workingsSheet.getRange(13,2,workingsSheet.getLastRow()).clearContent(); 49 | workingsSheet.getRange(13, 2, catNames.length).setValues(catNames); 50 | 51 | // change the cell in the drop down menu to be the first name of the new category list 52 | var firstName = workingsSheet.getRange(13,2).getValue(); 53 | apiSheet.getRange(6,3).setValue(firstName); 54 | swapiDetail(); // run swapiDetail so that data displayed matches the first name 55 | } 56 | 57 | // get the items for a given category 58 | function categoryData(category) { 59 | 60 | try { 61 | // Call the Star Wars API for each class 62 | var response = UrlFetchApp.fetch("http://swapi.co/api/" + category + "/"); 63 | var json = response.getContentText(); 64 | var data = JSON.parse(json)["results"]; 65 | 66 | return data; 67 | } 68 | catch(e) { 69 | Logger.log("Error: " + e.message); // log error message 70 | } 71 | }; 72 | 73 | 74 | 75 | function swapiDetail() { 76 | 77 | // get the category name chosen 78 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 79 | var apiSheet = ss.getSheetByName("api tool"); 80 | var category = apiSheet.getRange(4,3).getValue().toLowerCase(); 81 | 82 | // call the api to get back all the data for that category 83 | var catData = categoryData(category); 84 | // Logger.log(catData[1]); 85 | var catNames = getCategoryNames(category,catData); // [[Alderaan], [Yavin IV], [Hoth], [Dagobah], [Bespin], [Endor], [Naboo], [Coruscant], [Kamino], [Geonosis]] 86 | 87 | // get the specific item chosen within this category 88 | var item = apiSheet.getRange(6,3).getValue(); 89 | 90 | var itemData; 91 | 92 | // loop through category data until have match with the chosen item 93 | catNames.forEach(function(elem,i) { 94 | if (elem[0] === item) { 95 | itemData = catData[i]; 96 | } 97 | }); 98 | 99 | // call function to parse itemData and return selected data for that category item 100 | // data required will be depedent on category of item e.g. people v planets 101 | var itemDataForSheet = returnItemDetails(itemData,category); 102 | 103 | // paste into sheet, clear old details first 104 | apiSheet.getRange(10,2,apiSheet.getLastRow(),2).clearContent(); 105 | apiSheet.getRange(10, 2, itemDataForSheet.length, 2).setValues(itemDataForSheet); 106 | apiSheet.getRange(10, 2, itemDataForSheet.length, 2).setBackground("black").setFontColor("#FFD966").setHorizontalAlignment("left"); 107 | 108 | } 109 | 110 | 111 | function returnItemDetails(itemData,category) { 112 | 113 | var data = []; 114 | 115 | if (category === 'films') { 116 | // do something 117 | data.push(["Title:",itemData["title"]]); 118 | data.push(["Url:",itemData["url"]]); 119 | data.push(["Director:",itemData["director"]]); 120 | data.push(["Opening Crawl:",itemData["opening_crawl"]]); 121 | } 122 | else if (category === 'people') { 123 | // put the people details into the data array 124 | data.push(["Name:",itemData["name"]]); 125 | data.push(["Url:",itemData["url"]]); 126 | data.push(["Height:",itemData["height"]]); 127 | data.push(["Mass:",itemData["mass"]]); 128 | data.push(["Hair Color:",itemData["hair_color"]]); 129 | data.push(["Skin Color:",itemData["skin_color"]]); 130 | data.push(["Eye Color:",itemData["eye_color"]]); 131 | data.push(["Birth Year:",itemData["birth_year"]]); 132 | data.push(["Gender:",itemData["gender"]]); 133 | } 134 | else if (category === 'planets') { 135 | // put the planets details into the data array 136 | data.push(["Name:",itemData["name"]]); 137 | data.push(["Url:",itemData["url"]]); 138 | data.push(["Climate:",itemData["climate"]]); 139 | data.push(["Rotation Period:",itemData["rotation_period"]]); 140 | data.push(["Population:",itemData["population"]]); 141 | data.push(["Orbital Period:",itemData["orbital_period"]]); 142 | data.push(["Surface Water:",itemData["surface_water"]]); 143 | data.push(["Diameter:",itemData["diameter"]]); 144 | data.push(["Gravity:",itemData["gravity"]]); 145 | data.push(["Terrain:",itemData["terrain"]]); 146 | } 147 | else if (category === 'species') { 148 | // put the species details into the data array 149 | data.push(["Name:",itemData["name"]]); 150 | data.push(["Url:",itemData["url"]]); 151 | data.push(["Skin color:",itemData["skin_colors"]]); 152 | data.push(["Homeworld:",itemData["homeworld"]]); 153 | data.push(["Eye color:",itemData["eye_colors"]]); 154 | data.push(["Language:",itemData["language"]]); 155 | data.push(["Classification:",itemData["classification"]]); 156 | data.push(["Hair color:",itemData["hair_colors"]]); 157 | data.push(["Average height:",itemData["average_height"]]); 158 | data.push(["Designation:",itemData["designation"]]); 159 | data.push(["Average lifespan:",itemData["average_lifespan"]]); 160 | } 161 | else if (category === 'starships') { 162 | // put the starship details into the data array 163 | data.push(["Name:",itemData["name"]]); 164 | data.push(["Url:",itemData["url"]]); 165 | data.push(["Max atmosphering speed:",itemData["max_atmosphering_speed"]]); 166 | data.push(["Cargo capacity:",itemData["cargo_capacity"]]); 167 | data.push(["Passengers:",itemData["passengers"]]); 168 | data.push(["Pilots:",itemData["pilots"]]); 169 | data.push(["Consumables:",itemData["consumables"]]); 170 | data.push(["MGLT:",itemData["MGLT"]]); 171 | data.push(["Length:",itemData["length"]]); 172 | data.push(["Starship class:",itemData["starship_class"]]); 173 | data.push(["Manufacturer:",itemData["manufacturer"]]); 174 | data.push(["Crew:",itemData["crew"]]); 175 | data.push(["Hyperdrive rating:",itemData["hyperdrive_rating"]]); 176 | data.push(["Cost in credits:",itemData["cost_in_credits"]]); 177 | data.push(["Model:",itemData["model"]]); 178 | } 179 | else if (category === 'vehicles') { 180 | // put the vehicle details into the data array 181 | data.push(["Name:",itemData["name"]]); 182 | data.push(["Url:",itemData["url"]]); 183 | data.push(["Max atmosphering speed:",itemData["max_atmosphering_speed"]]); 184 | data.push(["Cargo capacity:",itemData["cargo_capacity"]]); 185 | data.push(["Passengers:",itemData["passengers"]]); 186 | data.push(["Pilots:",itemData["pilots"]]); 187 | data.push(["Consumables:",itemData["consumables"]]); 188 | data.push(["Length:",itemData["length"]]); 189 | data.push(["Manufacturer:",itemData["manufacturer"]]); 190 | data.push(["Crew:",itemData["crew"]]); 191 | data.push(["Vehicle class:",itemData["vehicle_class=repulsorcraft"]]); 192 | data.push(["Cost in credits:",itemData["cost_in_credits"]]); 193 | data.push(["Model:",itemData["model"]]); 194 | } 195 | else { 196 | data.push(["Error!"],["There has been a great disturbance in the force"]); 197 | } 198 | 199 | return data; 200 | } 201 | 202 | // function to create array of names within category based on data retrieved from the api 203 | function getCategoryNames(category,data) { 204 | // create names array 205 | var names = []; 206 | 207 | data.forEach(function(item) { 208 | var itemName = (category == "films") ? item.title : item.name; 209 | names.push([itemName]); 210 | }); 211 | 212 | return names; 213 | } 214 | -------------------------------------------------------------------------------- /api_001_swapi/api_001_swapi_v2.gs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * 3 | * API experiments 2017 #001 4 | * Exploring the Star Wars API: http://swapi.co/api/ 5 | * Retrives Star Wars data and populates a Google Sheet 6 | * Drop-down menu controls for user to choose categories/items 7 | * 8 | */ 9 | 10 | function swapiCategories() { 11 | 12 | // get the categories from the api 13 | var categories = function () { 14 | 15 | try { 16 | var response = UrlFetchApp.fetch("http://swapi.co/api/"); 17 | var data = response.getContentText(); 18 | var json = JSON.parse(data); 19 | var keys = Object.keys(json); 20 | return keys; 21 | } 22 | catch(e) { 23 | Logger.log("Error: " + e.message); // log error message 24 | } 25 | 26 | }; 27 | 28 | Logger.log(categories()); // [people, planets, films, species, vehicles, starships] 29 | 30 | // set up spreadsheet variables 31 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 32 | var apiSheet = ss.getSheetByName("api tool"); 33 | var workingsSheet = ss.getSheetByName("workings"); 34 | 35 | // get the value from the spreadsheet corresponding to user's choice 36 | var category = apiSheet.getRange(4,3).getValue().toLowerCase(); 37 | 38 | // get the corresponding item names in this category 39 | var catData = categoryData(category); 40 | var catNames = getCategoryNames(category,catData); 41 | 42 | Logger.log(catData); 43 | Logger.log(catNames); 44 | // [[Luke Skywalker], [C-3PO], [R2-D2], [Darth Vader], [Leia Organa], [Owen Lars], 45 | // [Beru Whitesun lars], [R5-D4], [Biggs Darklighter], [Obi-Wan Kenobi]] 46 | 47 | // paste into our sheet as a drop down menu 48 | workingsSheet.getRange(13,2,workingsSheet.getLastRow()).clearContent(); 49 | workingsSheet.getRange(13, 2, catNames.length).setValues(catNames); 50 | 51 | // change the cell in the drop down menu to be the first name of the new category list 52 | var firstName = workingsSheet.getRange(13,2).getValue(); 53 | apiSheet.getRange(6,3).setValue(firstName); 54 | swapiDetail(); // run swapiDetail so that data displayed matches the first name 55 | } 56 | 57 | // get the items for a given category 58 | function categoryData(category) { 59 | 60 | try { 61 | // Call the Star Wars API for each class 62 | var response = UrlFetchApp.fetch("http://swapi.co/api/" + category + "/"); 63 | var json = response.getContentText(); 64 | var data = JSON.parse(json)["results"]; 65 | 66 | return data; 67 | } 68 | catch(e) { 69 | Logger.log("Error: " + e.message); // log error message 70 | } 71 | }; 72 | 73 | 74 | 75 | function swapiDetail() { 76 | 77 | // get the category name chosen 78 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 79 | var apiSheet = ss.getSheetByName("api tool"); 80 | var category = apiSheet.getRange(4,3).getValue().toLowerCase(); 81 | 82 | // call the api to get back all the data for that category 83 | var catData = categoryData(category); 84 | // Logger.log(catData[1]); 85 | var catNames = getCategoryNames(category,catData); // [[Alderaan], [Yavin IV], [Hoth], [Dagobah], [Bespin], [Endor], [Naboo], [Coruscant], [Kamino], [Geonosis]] 86 | 87 | // get the specific item chosen within this category 88 | var item = apiSheet.getRange(6,3).getValue(); 89 | 90 | var itemData; 91 | 92 | // loop through category data until have match with the chosen item 93 | catNames.forEach(function(elem,i) { 94 | if (elem[0] === item) { 95 | itemData = catData[i]; 96 | } 97 | }); 98 | 99 | // call function to parse itemData and return selected data for that category item 100 | // data required will be depedent on category of item e.g. people v planets 101 | var itemDataForSheet = returnItemDetails(itemData,category); 102 | 103 | // paste into sheet, clear old details first 104 | apiSheet.getRange(10,2,apiSheet.getLastRow(),2).clearContent(); 105 | apiSheet.getRange(10, 2, itemDataForSheet.length, 2).setValues(itemDataForSheet); 106 | apiSheet.getRange(10, 2, itemDataForSheet.length, 2).setBackground("black").setFontColor("#FFD966").setHorizontalAlignment("left"); 107 | 108 | } 109 | 110 | 111 | function returnItemDetails(itemData,category) { 112 | 113 | var data = []; 114 | 115 | if (category === 'films') { 116 | // do something 117 | data.push(["Title:",itemData["title"]]); 118 | data.push(["Url:",itemData["url"]]); 119 | data.push(["Director:",itemData["director"]]); 120 | data.push(["Opening Crawl:",itemData["opening_crawl"]]); 121 | } 122 | else if (category === 'people') { 123 | // put the people details into the data array 124 | data.push(["Name:",itemData["name"]]); 125 | data.push(["Url:",itemData["url"]]); 126 | data.push(["Height:",itemData["height"]]); 127 | data.push(["Mass:",itemData["mass"]]); 128 | data.push(["Hair Color:",itemData["hair_color"]]); 129 | data.push(["Skin Color:",itemData["skin_color"]]); 130 | data.push(["Eye Color:",itemData["eye_color"]]); 131 | data.push(["Birth Year:",itemData["birth_year"]]); 132 | data.push(["Gender:",itemData["gender"]]); 133 | } 134 | else if (category === 'planets') { 135 | // put the planets details into the data array 136 | data.push(["Name:",itemData["name"]]); 137 | data.push(["Url:",itemData["url"]]); 138 | data.push(["Climate:",itemData["climate"]]); 139 | data.push(["Rotation Period:",itemData["rotation_period"]]); 140 | data.push(["Population:",itemData["population"]]); 141 | data.push(["Orbital Period:",itemData["orbital_period"]]); 142 | data.push(["Surface Water:",itemData["surface_water"]]); 143 | data.push(["Diameter:",itemData["diameter"]]); 144 | data.push(["Gravity:",itemData["gravity"]]); 145 | data.push(["Terrain:",itemData["terrain"]]); 146 | } 147 | else if (category === 'species') { 148 | // put the species details into the data array 149 | data.push(["Name:",itemData["name"]]); 150 | data.push(["Url:",itemData["url"]]); 151 | data.push(["Skin color:",itemData["skin_colors"]]); 152 | data.push(["Homeworld:",itemData["homeworld"]]); 153 | data.push(["Eye color:",itemData["eye_colors"]]); 154 | data.push(["Language:",itemData["language"]]); 155 | data.push(["Classification:",itemData["classification"]]); 156 | data.push(["Hair color:",itemData["hair_colors"]]); 157 | data.push(["Average height:",itemData["average_height"]]); 158 | data.push(["Designation:",itemData["designation"]]); 159 | data.push(["Average lifespan:",itemData["average_lifespan"]]); 160 | } 161 | else if (category === 'starships') { 162 | // put the starship details into the data array 163 | data.push(["Name:",itemData["name"]]); 164 | data.push(["Url:",itemData["url"]]); 165 | data.push(["Max atmosphering speed:",itemData["max_atmosphering_speed"]]); 166 | data.push(["Cargo capacity:",itemData["cargo_capacity"]]); 167 | data.push(["Passengers:",itemData["passengers"]]); 168 | data.push(["Pilots:",itemData["pilots"]]); 169 | data.push(["Consumables:",itemData["consumables"]]); 170 | data.push(["MGLT:",itemData["MGLT"]]); 171 | data.push(["Length:",itemData["length"]]); 172 | data.push(["Starship class:",itemData["starship_class"]]); 173 | data.push(["Manufacturer:",itemData["manufacturer"]]); 174 | data.push(["Crew:",itemData["crew"]]); 175 | data.push(["Hyperdrive rating:",itemData["hyperdrive_rating"]]); 176 | data.push(["Cost in credits:",itemData["cost_in_credits"]]); 177 | data.push(["Model:",itemData["model"]]); 178 | } 179 | else if (category === 'vehicles') { 180 | // put the vehicle details into the data array 181 | data.push(["Name:",itemData["name"]]); 182 | data.push(["Url:",itemData["url"]]); 183 | data.push(["Max atmosphering speed:",itemData["max_atmosphering_speed"]]); 184 | data.push(["Cargo capacity:",itemData["cargo_capacity"]]); 185 | data.push(["Passengers:",itemData["passengers"]]); 186 | data.push(["Pilots:",itemData["pilots"]]); 187 | data.push(["Consumables:",itemData["consumables"]]); 188 | data.push(["Length:",itemData["length"]]); 189 | data.push(["Manufacturer:",itemData["manufacturer"]]); 190 | data.push(["Crew:",itemData["crew"]]); 191 | data.push(["Vehicle class:",itemData["vehicle_class=repulsorcraft"]]); 192 | data.push(["Cost in credits:",itemData["cost_in_credits"]]); 193 | data.push(["Model:",itemData["model"]]); 194 | } 195 | else { 196 | data.push(["Error!"],["There has been a great disturbance in the force"]); 197 | } 198 | 199 | return data; 200 | } 201 | 202 | // function to create array of names within category based on data retrieved from the api 203 | function getCategoryNames(category,data) { 204 | // create names array 205 | var names = []; 206 | 207 | for each (item in data) { 208 | var itemName = (category == "films") ? item.title : item.name; 209 | names.push([itemName]); 210 | } 211 | 212 | return names; 213 | } 214 | 215 | 216 | 217 | // change to onedit trigger: https://developers.google.com/apps-script/guides/triggers/#onedit 218 | -------------------------------------------------------------------------------- /api_001_swapi/api_001_swapi_v1.gs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * Step 1: 3 | * Most basic call to the API 4 | */ 5 | function swapi1() { 6 | 7 | // Call the Star Wars API 8 | var response = UrlFetchApp.fetch("http://swapi.co/api/planets/1/"); 9 | Logger.log(response.getContentText()); 10 | } 11 | 12 | /* 13 | * example data packet reply from api 14 | {films=[http://swapi.co/api/films/5/, http://swapi.co/api/films/4/, http://swapi.co/api/films/6/, 15 | http://swapi.co/api/films/3/, http://swapi.co/api/films/1/], edited=2014-12-21T20:48:04.175778Z, 16 | created=2014-12-09T13:50:49.641000Z, climate=arid, rotation_period=23, url=http://swapi.co/api/planets/1/, 17 | population=200000, orbital_period=304, surface_water=1, diameter=10465, gravity=1 standard, name=Tatooine, 18 | residents=[http://swapi.co/api/people/1/, http://swapi.co/api/people/2/, http://swapi.co/api/people/4/, 19 | http://swapi.co/api/people/6/, http://swapi.co/api/people/7/, http://swapi.co/api/people/8/, 20 | http://swapi.co/api/people/9/, http://swapi.co/api/people/11/, http://swapi.co/api/people/43/, 21 | http://swapi.co/api/people/62/], terrain=desert} 22 | */ 23 | 24 | 25 | /******************************************************************************** 26 | * Step 2: 27 | * Same basic call to the API 28 | * Parse the JSON reply 29 | */ 30 | function swapi2() { 31 | 32 | // Call the Star Wars API 33 | var response = UrlFetchApp.fetch("http://swapi.co/api/planets/1/"); 34 | 35 | // Parse the JSON reply 36 | var json = response.getContentText(); 37 | var data = JSON.parse(json); 38 | Logger.log(data); 39 | 40 | // output the planet name in our Google Sheet 41 | Browser.msgBox(data.name); 42 | } 43 | 44 | 45 | /******************************************************************************** 46 | * Step 3: 47 | * Same basic call to the API 48 | * Parse the JSON reply 49 | * Log error messages 50 | */ 51 | function swapi3() { 52 | 53 | try { 54 | 55 | // Call the Star Wars API 56 | // deliberately use the wrong URL 57 | var response = UrlFetchApp.fetch("http://ZZZswapi.co/api/planets/1/"); 58 | 59 | // Parse the JSON reply 60 | var json = response.getContentText(); 61 | var data = JSON.parse(json); 62 | 63 | // output the planet name in our Google Sheet 64 | Browser.msgBox(data.name); 65 | 66 | } catch (e) { 67 | 68 | // TO DO 69 | // log the error 70 | Logger.log(e); // full error message 71 | Logger.log(e.message); // content of error message 72 | // .. what else....? 73 | 74 | } 75 | 76 | } 77 | 78 | 79 | 80 | /******************************************************************************** 81 | * Step 4: 82 | * Same basic call to the API 83 | * Parse the JSON reply 84 | * Get response code and base decision off that 85 | * Log error messages 86 | */ 87 | function swapi4() { 88 | 89 | // Add the base URL for the Star Wars API to a variable 90 | var queryString = "http://swapi.co/api/" 91 | var endpoint = "bob" 92 | 93 | var params = { 94 | 'method': 'GET', 95 | 'muteHttpExceptions': true // allows program to continue despite error fetching the API with missing endpoint 96 | } 97 | 98 | // deliberately use the wrong URL 99 | var rc = UrlFetchApp.fetch(queryString + endpoint, params).getResponseCode(); 100 | 101 | if (rc == 200) { 102 | // output the planet name in our Google Sheet 103 | Logger.log(rc); 104 | } 105 | else { 106 | // do something... 107 | Logger.log("Uh-oh! I searched for '" + endpoint + "' but the server returned response code " + rc + ", which means I didn't find what you were looking for."); 108 | } 109 | 110 | } 111 | 112 | 113 | /******************************************************************************** 114 | * Step 5: 115 | * Same basic call to the API 116 | * Parse the JSON reply 117 | * Get headers 118 | */ 119 | function swapi5() { 120 | 121 | // Call the Star Wars API 122 | var response = UrlFetchApp.fetch("http://swapi.co/api/planets/1/"); 123 | 124 | // Get the reply headers 125 | var headers = response.getHeaders(); 126 | 127 | Logger.log(headers); 128 | Logger.log(headers.Date); 129 | Logger.log(headers.domain); // why was this "undefined"? 130 | 131 | } 132 | 133 | 134 | 135 | /******************************************************************************** 136 | * Step 6: 137 | * Same basic call to the API 138 | * Parse the JSON reply 139 | * display the different parts of the JSON 140 | */ 141 | function swapi6() { 142 | 143 | // Call the Star Wars API 144 | var response = UrlFetchApp.fetch("http://swapi.co/api/planets/1/"); 145 | 146 | // Parse the JSON reply 147 | var json = response.getContentText(); 148 | var data = JSON.parse(json); 149 | 150 | Logger.log("Record created: " + data.created); 151 | Logger.log("Record last edited: " + data.edited); 152 | Logger.log("URL of endopint: " + data.url); 153 | Logger.log("Name of planet: " + data.name); 154 | Logger.log("Climate of planet: " + data.climate); 155 | Logger.log("Terrain of planet: " + data.terrain); 156 | Logger.log("Population of planet: " + data.population); 157 | } 158 | 159 | 160 | /******************************************************************************** 161 | * Step 7: 162 | * Same basic call to the API 163 | * Parse the JSON reply 164 | * display the different parts of the JSON 165 | */ 166 | function swapi7() { 167 | 168 | // Call the Star Wars API 169 | var response = UrlFetchApp.fetch("http://swapi.co/api/planets/"); 170 | 171 | // Parse the JSON reply 172 | var json = response.getContentText(); 173 | var data = JSON.parse(json); 174 | 175 | // Log all planet names from the api 176 | for each (item in data["results"]) { 177 | 178 | Logger.log(item.name); 179 | } 180 | 181 | //Logger.log(data["results"][0]); 182 | //Logger.log(data["results"].length); 183 | } 184 | 185 | 186 | /******************************************************************************** 187 | * Step 8: 188 | * Initialize by creating list of all category items and pasting to sheet 189 | * Parse the JSON reply 190 | * display the different parts of the JSON 191 | */ 192 | function allData() { 193 | 194 | // Call the Star Wars API 195 | var response = UrlFetchApp.fetch("http://swapi.co/api/"); 196 | 197 | // Parse the JSON reply 198 | var json = response.getContentText(); 199 | var apiData = JSON.parse(json); 200 | 201 | return apiData; 202 | /* 203 | * {films=http://swapi.co/api/films/, planets=http://swapi.co/api/planets/, species=http://swapi.co/api/species/, 204 | * starships=http://swapi.co/api/starships/, vehicles=http://swapi.co/api/vehicles/, people=http://swapi.co/api/people/} 205 | */ 206 | } 207 | 208 | 209 | 210 | function returnCatNames(category) { 211 | 212 | var names = []; 213 | 214 | /* 215 | for each (item in category) { 216 | var obj = {}; 217 | names.push(item.name); 218 | //obj["name"] = item.name, 219 | //obj["url"] = item.url 220 | //); 221 | } 222 | */ 223 | 224 | category.forEach(function(elem) { 225 | var obj = {}; 226 | names.push(elem.name); 227 | }); 228 | 229 | 230 | Logger.log(names); 231 | 232 | return names; 233 | } 234 | 235 | 236 | function readToSheet() { 237 | 238 | var planetData = callAPI("planets"); 239 | var peopleData = callAPI("people"); 240 | 241 | // Create array of all planet names from the api 242 | var planetNames = returnCatNames(planetData); 243 | var peopleNames = returnCatNames(peopleData); 244 | 245 | 246 | Logger.log(planetNames); 247 | //Logger.log(planetData[0].url); 248 | Logger.log(peopleNames); 249 | 250 | } 251 | 252 | 253 | /******************************************************************************** 254 | * Step 9: 255 | * get all options for api and write to sheet 256 | * 257 | */ 258 | 259 | function getCategoryData() { 260 | 261 | // get the value from the spreadsheet corresponding to user's choice 262 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 263 | var apiSheet = ss.getSheetByName("api tool"); 264 | var category = apiSheet.getRange(4,3).getValue().toLowerCase(); 265 | Logger.log(category); 266 | 267 | // Call the Star Wars API for each class 268 | var response = UrlFetchApp.fetch("http://swapi.co/api/" + category + "/"); 269 | var json = response.getContentText(); 270 | var data = JSON.parse(json)["results"]; 271 | 272 | // create array of the names for this category 273 | var names = getCategoryNames(category,data); 274 | var categoryCount = names.length; 275 | Logger.log(names); 276 | Logger.log(categoryCount); 277 | 278 | // paste into our sheet as a drop down menu 279 | var workingsSheet = ss.getSheetByName("workings"); 280 | var maxRow = workingsSheet.getLastRow(); 281 | workingsSheet.getRange(13,2,maxRow).clearContent(); 282 | workingsSheet.getRange(13, 2, categoryCount).setValues(names); 283 | 284 | // change the cell in the drop down menu to be the first name of the new category list 285 | var firstName = workingsSheet.getRange(13,2).getValue(); 286 | apiSheet.getRange(6,3).setValue(firstName); 287 | 288 | Logger.log(data); 289 | return data; 290 | 291 | } 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | // turn into drop down menus so you can select from within the sheet 304 | // paste the API reply into the google sheet as the "answer" 305 | // explore different error handling and response codes 306 | // explore different bits of data returned and log and look at each one 307 | // https://developers.google.com/apps-script/reference/url-fetch/http-response 308 | -------------------------------------------------------------------------------- /api_002_mailchimp/api_002_mailchimp_v1.gs: -------------------------------------------------------------------------------- 1 | /******************************************************************************** 2 | * 3 | * API experiments 2017 #002 4 | * Exploring the MailChimp API 5 | * Retrives MailChimp data and populates a Google Sheet 6 | * 7 | */ 8 | 9 | 10 | // setup menu to run print Mailchimp function from Sheet 11 | function onOpen() { 12 | var ui = SpreadsheetApp.getUi(); 13 | 14 | ui.createMenu('MailChimp Menu') 15 | .addItem('Get campaign data', 'printMailChimpData') 16 | .addItem('Import emails', 'importEmailsMailChimp') 17 | .addItem('List Growth Details','listGrowth') 18 | .addToUi(); 19 | 20 | } 21 | 22 | 23 | 24 | // script properties service 25 | // retrive copy of mailchimp api key 26 | function getApiKey() { 27 | var properties = PropertiesService.getScriptProperties(); 28 | return properties.getProperty('apikey'); 29 | } 30 | 31 | function getListID() { 32 | var properties = PropertiesService.getScriptProperties(); 33 | return properties.getProperty('listID'); 34 | } 35 | 36 | 37 | /* 38 | * Step 1: 39 | * Basic MailChimp API GET request 40 | * 41 | * {list_id} the ID of your list in MailChimp 42 | * {apikey} your MailChimp API key 43 | * 44 | */ 45 | 46 | function mailchimp1() { 47 | 48 | // get mailchimp api key from properties service 49 | var apikey = getApiKey(); 50 | 51 | // URL and params for the Mailchimp API 52 | var root = 'https://us11.api.mailchimp.com/3.0/'; 53 | var listID = getListID(); 54 | var endpoint = 'lists/' + listID; 55 | 56 | var params = { 57 | 'method': 'GET', 58 | 'muteHttpExceptions': true, 59 | 'headers': { 60 | 'Authorization': 'apikey ' + apikey 61 | } 62 | }; 63 | 64 | // call the Mailchimp API 65 | var response = UrlFetchApp.fetch(root+endpoint, params); 66 | var data = response.getContentText(); 67 | var json = JSON.parse(data); 68 | 69 | // Log the list stats 70 | Logger.log(json["stats"]); 71 | 72 | // Log the total number of people on the list 73 | Logger.log("Total members on list: " + json["stats"]["member_count"]); 74 | } 75 | 76 | 77 | /**************************************************************************************** 78 | * 79 | * Step 2: 80 | * 81 | */ 82 | function mailchimp2() { 83 | 84 | // get mailchimp api key from properties service 85 | var apikey = getApiKey(); 86 | 87 | // URL and params for the Mailchimp API 88 | var root = 'https://us11.api.mailchimp.com/3.0/'; 89 | var endpoint = 'lists/'; 90 | 91 | var params = { 92 | 'method': 'GET', 93 | 'muteHttpExceptions': true, 94 | 'headers': { 95 | 'Authorization': 'apikey ' + apikey 96 | } 97 | }; 98 | 99 | // call the Mailchimp API 100 | var response = UrlFetchApp.fetch(root+endpoint, params); 101 | var data = response.getContentText(); 102 | var json = JSON.parse(data); 103 | 104 | // Log the list id and stats 105 | Logger.log("List ID:" + json["lists"][0]["id"]); 106 | Logger.log(json["lists"][0]["stats"]); 107 | } 108 | 109 | /**************************************************************************************** 110 | * 111 | * Return more than the default 10 112 | // Add this to the endpoint '?count=20' 113 | */ 114 | function mailchimp3() { 115 | 116 | // get mailchimp api key from properties service 117 | var apikey = getApiKey(); 118 | 119 | // URL and params for the Mailchimp API 120 | var root = 'https://us11.api.mailchimp.com/3.0/'; 121 | var endpoint = 'campaigns?count=20'; 122 | 123 | var params = { 124 | 'method': 'GET', 125 | 'muteHttpExceptions': true, 126 | 'headers': { 127 | 'Authorization': 'apikey ' + apikey 128 | } 129 | }; 130 | 131 | // call the Mailchimp API 132 | var response = UrlFetchApp.fetch(root+endpoint, params); 133 | var data = response.getContentText(); 134 | var json = JSON.parse(data); 135 | 136 | // Log the list id and stats 137 | var campaigns = json['campaigns']; 138 | Logger.log(campaigns.length); 139 | for (var i = 0; i < campaigns.length; i++) { 140 | Logger.log(campaigns[i]["settings"]["subject_line"]); 141 | } 142 | } 143 | 144 | 145 | 146 | /**************************************************************************************** 147 | * 148 | * Step 4: general endpoint 149 | * 150 | */ 151 | 152 | // generalized mailchimp api call 153 | function mailchimpEndpoint(endpoint) { 154 | 155 | // get mailchimp api key from properties service 156 | var apikey = getApiKey(); 157 | 158 | // URL and params for the Mailchimp API 159 | var root = 'https://us11.api.mailchimp.com/3.0/'; 160 | var path = endpoint; 161 | var query = '?count=30'; 162 | 163 | var params = { 164 | 'method': 'GET', 165 | 'muteHttpExceptions': true, 166 | 'headers': { 167 | 'Authorization': 'apikey ' + apikey 168 | } 169 | }; 170 | 171 | Logger.log(root + path + query); 172 | Logger.log(params); 173 | 174 | // call the Mailchimp API 175 | var response = UrlFetchApp.fetch(root + path + query, params); 176 | var data = response.getContentText(); 177 | var json = JSON.parse(data); 178 | 179 | // Return the JSON data 180 | //return json[endpoint]; 181 | return json; 182 | } 183 | 184 | 185 | // get mailchimp campaign data v2 186 | function getMailChimpCampaignData2() { 187 | 188 | // get mailchimp api key from properties service 189 | var apikey = getApiKey(); 190 | 191 | var campaigns = mailchimpEndpoint('campaigns')['campaigns']; 192 | Logger.log(campaigns); 193 | 194 | var campaignData = []; 195 | 196 | // Add the campaign data to the array 197 | for (var i = 0; i < campaigns.length; i++) { 198 | 199 | // put the campaign data into a double array for Google Sheets 200 | if (campaigns[i]["emails_sent"] != 0) { 201 | campaignData.push([ 202 | i, 203 | campaigns[i]["send_time"].substr(0,10), 204 | campaigns[i]["settings"]["title"], 205 | campaigns[i]["settings"]["subject_line"], 206 | campaigns[i]["recipients"]["recipient_count"], 207 | campaigns[i]["emails_sent"], 208 | (campaigns[i]["report_summary"]) ? campaigns[i]["report_summary"]["unique_opens"] : 0, 209 | (campaigns[i]["report_summary"]) ? campaigns[i]["report_summary"]["clicks"] : 0 210 | ]); 211 | } 212 | else { 213 | campaignData.push([ 214 | i, 215 | "Not sent", 216 | campaigns[i]["settings"]["title"], 217 | campaigns[i]["settings"]["subject_line"], 218 | campaigns[i]["recipients"]["recipient_count"], 219 | campaigns[i]["emails_sent"], 220 | "N/a", 221 | "N/a" 222 | ]); 223 | } 224 | } 225 | 226 | return campaignData; 227 | } 228 | 229 | 230 | // add the campaign data to our sheet 231 | function printMailChimpData() { 232 | 233 | var data = getMailChimpCampaignData2(); 234 | 235 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 236 | var sheet = ss.getSheetByName('Campaign Analysis'); 237 | 238 | var numRows = data.length; 239 | var numCols = data[0].length; 240 | 241 | sheet.getRange(4,1,numRows,numCols).setValues(data); 242 | 243 | for (var i = 0; i < numRows; i++) { 244 | sheet.getRange(4+i,9).setFormulaR1C1('=iferror(R[0]C[-2]/R[0]C[-3]*100,"N/a")'); 245 | sheet.getRange(4+i,10).setFormulaR1C1('=iferror(R[0]C[-2]/R[0]C[-4]*100,"N/a")'); 246 | } 247 | 248 | sheet.getRange(4,1,numRows,2).setHorizontalAlignment("center"); 249 | sheet.getRange(4,5,numRows,6).setHorizontalAlignment("center"); 250 | 251 | } 252 | 253 | /* 254 | // data format required for api 255 | 256 | var data = [ 257 | { 258 | 'email_address': 'xxxxxxxxxxx@gmail.com', 259 | 'status': 'subscribed' 260 | }, 261 | { 262 | 'email_address': 'xxxxxxxxxxx@gmail.com', 263 | 'status': 'subscribed' 264 | } 265 | ]; 266 | */ 267 | 268 | // get new email subscribers from Sheet 269 | function getSubscribers() { 270 | 271 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 272 | var sheet = ss.getSheetByName('Email Import'); 273 | var numEmails = sheet.getLastRow()-1; 274 | 275 | var emails = sheet.getRange(2, 1, numEmails, 1).getValues(); 276 | 277 | var emailsArray = emails.map(function(elem) { 278 | return { 279 | 'email_address' : elem[0], 280 | 'status' : 'subscribed' 281 | }; 282 | }); 283 | 284 | /* 285 | emailsArray = [ 286 | {email_address=xxxxxxxxxxx@gmail.com, status=subscribed}, 287 | {email_address=xxxxxxxxxxx@yahoo.com, status=subscribed}, 288 | {email_address=xxxxxxxxxxx@yahoo.com, status=subscribed} 289 | ] 290 | */ 291 | 292 | Logger.log(typeof emailsArray); 293 | Logger.log(emailsArray); 294 | return emailsArray; 295 | } 296 | 297 | 298 | // add new email subs to MailChimp 299 | function importEmailsMailChimp() { 300 | 301 | var emailData = getSubscribers(); 302 | 303 | //Logger.log(emailData); 304 | 305 | var data = { 306 | 'members': emailData 307 | }; 308 | 309 | var payloadData = JSON.stringify(data); 310 | 311 | //Logger.log(payloadData); 312 | /* 313 | { 314 | "members": [ 315 | {email_address=xxxxxxxxxxx@gmail.com, status=subscribed}, 316 | {email_address=xxxxxxxxxxx@yahoo.com, status=subscribed}, 317 | {email_address=xxxxxxxxxxx@yahoo.com, status=subscribed} 318 | ] 319 | } 320 | */ 321 | 322 | // get mailchimp api key from properties service 323 | var apikey = getApiKey(); 324 | 325 | // URL and params for the Mailchimp API 326 | var root = 'https://us11.api.mailchimp.com/3.0/'; 327 | var listID = getListID(); 328 | var path = '/lists/' + listID; // for batch upload of subs. For single upload, also add '/members' 329 | 330 | var options = { 331 | 'method' : 'post', 332 | 'contentType': 'application/json', 333 | 'payload': payloadData, 334 | 'muteHttpExceptions': true, 335 | 'headers': { 336 | 'Authorization': 'apikey ' + apikey 337 | } 338 | }; 339 | 340 | var response = UrlFetchApp.fetch(root + path, options); // POST emails to mailchimp 341 | var responseData = response.getContentText(); 342 | var json = JSON.parse(responseData); 343 | 344 | //Logger.log(json); 345 | 346 | var chimpLog = logMailChimpImport(json); 347 | 348 | //Logger.log("this is it here:"); 349 | //Logger.log(chimpLog); 350 | 351 | // [Fri Jan 13 22:38:43 GMT-05:00 2017, 0, 0, 3, {email_address=xxxxxxxxxxx@gmail.com, 352 | // error=xxxxxxxxxxxx@gmail.com is already a list member, do you want to update? please provide update_existing:true in the request body}] 353 | 354 | printMailChimpLog(chimpLog); 355 | 356 | emailMailChimpLog(chimpLog); 357 | 358 | 359 | //return json; 360 | 361 | } 362 | 363 | 364 | // log time and details of imports, e.g. how many emails 365 | function logMailChimpImport(response) { 366 | 367 | var timestamp = new Date(); 368 | 369 | var mailchimpLog = [ 370 | timestamp, 371 | response['total_created'], 372 | response['total_updated'], 373 | response['error_count'], 374 | response['errors'][0] 375 | ]; 376 | 377 | return mailchimpLog; 378 | } 379 | 380 | // print the import log into the Google Sheet 381 | function printMailChimpLog(chimpLog) { 382 | 383 | var ss = SpreadsheetApp.getActiveSpreadsheet(); 384 | var logSheet = ss.getSheetByName('Import Log'); 385 | 386 | //Logger.log(typeof chimpLog); 387 | //Logger.log(chimpLog) 388 | 389 | logSheet.appendRow(chimpLog); 390 | 391 | } 392 | 393 | 394 | function emailMailChimpLog(data) { 395 | 396 | Logger.log('working'); 397 | Logger.log(data); 398 | 399 | var body = 'Time of import ' + data[0].toLocaleString() + '\n' 400 | + 'Total subscribers created: ' + data[1] + '\n' 401 | + 'Total subscribers updated: ' + data[2] + '\n' 402 | + 'Total error count: ' + data[3] + '\n' 403 | + 'Example error: ' + data[4]["error"]; 404 | 405 | var admin = 'benlcollins@gmail.com'; 406 | 407 | GmailApp.sendEmail(admin, 'Your mailchimp import has finished - status inside', body); 408 | 409 | } 410 | 411 | // Feature requests: 412 | // 413 | // http://developer.mailchimp.com/documentation/mailchimp/reference/lists/#create-post_lists_list_id 414 | // use response data including error data to build report 415 | // deal with multiple errors, currently just showing first one 416 | // split up if more than 500 emails 417 | 418 | 419 | 420 | 421 | // get mailchimp campaign data v1 422 | function getMailChimpCampaignData1() { 423 | 424 | // get mailchimp api key from properties service 425 | var apikey = getApiKey(); 426 | 427 | var campaigns = mailchimpEndpoint('campaigns')['campaigns']; 428 | Logger.log(campaigns); 429 | 430 | //Logger.log(campaigns[15]); 431 | 432 | // Log the campaign data 433 | for (var i = 0; i < campaigns.length; i++) { 434 | //Logger.log("i: " + i); 435 | (campaigns[i]["settings"]["title"]) ? Logger.log("Campaign title: " + campaigns[i]["settings"]["title"]) : Logger.log("No title"); 436 | (campaigns[i]["send_time"]) ? Logger.log("Send time: " + campaigns[i]["send_time"]) : Logger.log("No emails sent"); 437 | (campaigns[i]["settings"]["subject_line"]) ? Logger.log("Campaign: " + campaigns[i]["settings"]["subject_line"]) : Logger.log("No subject line recorded"); 438 | (campaigns[i]["recipients"]["recipient_count"]) ? Logger.log("Recipient count: " + campaigns[i]["recipients"]["recipient_count"]) : Logger.log("No recipient count"); 439 | (campaigns[i]["emails_sent"]) ? Logger.log("Emails sent: " + campaigns[i]["emails_sent"]) : Logger.log("No emails sent"); 440 | 441 | if ("report_summary" in campaigns[i]) { 442 | Logger.log("Unique opens: " + campaigns[i]["report_summary"]["unique_opens"]); 443 | Logger.log("Clicks: " + campaigns[i]["report_summary"]["clicks"]); 444 | } 445 | else { 446 | Logger.log("No unique opens or clicks recorded"); 447 | } 448 | 449 | Logger.log("\n"); // add blank line 450 | } 451 | 452 | } 453 | --------------------------------------------------------------------------------