Data from Patreon into Google Sheets - google-apps-script

I'm trying to pipe data from a specific Patreon Creator Page into a Google Spreadsheet such as: Member first name, member last name, tier, etc. etc.
I've read the Patreon Developers Documentation here. https://docs.patreon.com
I referenced Ben Collin's tutorial on integrating Google Sheets with the Strava API here: https://www.benlcollins.com/spreadsheets/strava-api-with-google-sheets/
I've successfully connected Patreon to my Google App and have granted access but still no data. I am getting the following error when I run the script:
TypeError: Cannot find function forEach in object [object Object].
Any ideas as to how I can get the data I'm after?
var CLIENT_ID = 'HIDDEN';
var CLIENT_SECRET = 'HIDDEN';
var redirectURL = 'https://script.google.com/macros/d/HIDDEN:scriptID/usercallback'
// configure the service
function getPatreonService() {
return OAuth2.createService('Patreon')
.setAuthorizationBaseUrl('https://www.patreon.com/oauth2/authorize')
.setTokenUrl('https://api.patreon.com/oauth2/token')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('included:read_all');
}
// handle the callback
function authCallback(request) {
var patreonService = getPatreonService();
var isAuthorized = patreonService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
// custom menu
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Patreon App')
.addItem('Get data', 'getPatreonPledgeData')
.addToUi();
}
// Get pledge data
function getPatreonPledgeData() {
// get the sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
// call the Patreon API to retrieve data
var data = callPatreonAPI();
// empty array to hold pledge data
var patreonData = [];
// loop over pledge data and add to patreonData array for Sheet
data.forEach(function(pledge) {
var arr = [];
arr.push(
pledge.first_name,
pledge.full_name,
pledge.email,
pledge.last_name
);
patreonData.push(arr);
});
// paste the values into the Sheet
sheet.getRange(sheet.getLastRow() + 1, 1, patreonData.length, patreonData[0].length).setValues(patreonData);
}
// call the Patreon API
function callPatreonAPI() {
// set up the service
var service = getPatreonService();
if (service.hasAccess()) {
Logger.log('App has access.');
var endpoint = 'https://www.patreon.com/api/oauth2/api/campaigns/<HIDDEN:CampaignID>/pledges';
var params = '?include=patron.null';
var headers = {
Authorization: 'Bearer ' + service.getAccessToken()
};
var options = {
headers: headers,
method : 'GET',
muteHttpExceptions: true
};
var response = JSON.parse(UrlFetchApp.fetch(endpoint + params, options));
return response;
}
else {
Logger.log("App has no access yet.");
// open this url to gain authorization
var authorizationUrl = service.getAuthorizationUrl();
Logger.log("Open the following URL and re-run the script: %s",
authorizationUrl);
}
}

The error comes because the Oauth flow is not being completely executed (It may be that it's not presenting the consent screen, you're not logging in with your account, etc).
As stated in the Oauth2 library documentation for Apps Script that you're using [1] in the "Connecting to a Google API" part, a more simple way to obtain the access token is using ScriptApp.getOAuthToken() function [2] instead of service.getAccessToken(), and set the needed scopes in the manifest file [3].
In any case, I hardly believe that could give you access to the Patreon API [4]. Also, I don't see the url you're using in the Patreon API documentation [5].
[1] https://github.com/gsuitedevs/apps-script-oauth2
[2] https://developers.google.com/apps-script/reference/script/script-app#getoauthtoken
[3] https://developers.google.com/apps-script/concepts/manifests#editing_a_manifest
[4] https://docs.patreon.com/#oauth
[5] https://docs.patreon.com/?javascript#api-endpoints

Related

Google App Script oAuth2 to Questrade API Invalid Token

I'm trying to used Google Apps Script to pull Questrade account information into a Google sheets spreadsheet. I've added the oAuth2 library from GitHub(https://github.com/googleworkspace/apps-script-oauth2) then mostly copy and pasted (with minor edits) from the example code.
The weird thing is this code has worked, exactly how it is, but a day later it no longer works and returns the following:
Exception: Request failed for https://api01.iq.questrade.com returned code 401. Truncated server response: {"code":1017,"message":"Access token is invalid"} (use muteHttpExceptions option to examine full response)
My Google Apps Script is posted below. I've only removed my Questrade Client_ID and Google Script Script_ID. I have three buttons in my spreadsheet which I've linked to functions in the script:
Button 1 - QT oAuth - calls showSidebar
Button 2 - Load Account Info - calls makeRequest
Button 3 - QT Logout - calls logout
Typically, I press the QT Logout button to reset 0Auth2 services then I press the QT oAuth button. This seems to successfully go through the authorization process. I then press the Load Account Info button and about 99 times out of 100 I get the invalid access token message. I don't know if it's relevant, but when I log into Questrades API hub I can see that the script is adding an authorization after the QT oAuth button is pressed but it seems to disappear after about a minute.
The script:
function getQTService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
return OAuth2.createService('QT')
// Set the endpoint URLs.
.setAuthorizationBaseUrl('https://login.questrade.com/oauth2/authorize')
.setTokenUrl('https://login.questrade.com/oauth2/token')
// Set the client ID and secret.
.setClientId('Client_ID')
.setClientSecret(' ') //there is no client secret but oAuth2 requires one
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
.setCache(CacheService.getUserCache())
// Set the scopes to request (space-separated for Google services).
.setScope('read_acc')
}
function showSidebar() {
var QTService = getQTService();
if (!QTService.hasAccess()) {
var authorizationUrl = QTService.getAuthorizationUrl();
var template = HtmlService.createTemplate(
'Authorize. ' +
'Reopen the sidebar when the authorization is complete.');
template.authorizationUrl = authorizationUrl;
var page = template.evaluate();
SpreadsheetApp.getUi().showSidebar(page);
} else {
// ...
}
}
function authCallback(request) {
var QTService = getQTService();
var isAuthorized = QTService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
function makeRequest() {
var QTService = getQTService();
var token = QTService.getAccessToken();
var spreadsheet = SpreadsheetApp.openById("Script_ID");
// Get account number
var response = UrlFetchApp.fetch('https://api01.iq.questrade.com/v1/accounts',{
headers: {
Authorization: 'Bearer ' + token
}
});
var json = response.getContentText();
var accountdata = JSON.parse(json);
var j = 0;
while(j < accountdata.accounts.length) {
var Account_num = accountdata.accounts[j].number;
var Account_type = accountdata.accounts[j].type;
var sheet = spreadsheet.getSheetByName(Account_type);
// GET CASH BALANCE
var response = UrlFetchApp.fetch('https://api01.iq.questrade.com/v1/accounts/' + Account_num + '/balances',{
headers: {
Authorization: 'Bearer ' + token
}
});
json = response.getContentText();
var balancedata = JSON.parse(json);
var i = 0;
while(balancedata.perCurrencyBalances[i].currency != 'CAD') {
i=i+1;
}
//send cash value to spreadsheet
sheet.getRange("G1").setValue(balancedata.perCurrencyBalances[i].cash);
// GET POSITIONS
var response = UrlFetchApp.fetch('https://api01.iq.questrade.com/v1/accounts/' + Account_num + '/positions',{
headers: {
Authorization: 'Bearer ' + token
}
});
json = response.getContentText();
var positionsdata = JSON.parse(json);
var num_of_positions = positionsdata.positions.length;
var i = 0;
while(i < num_of_positions) { //this loop is not that smart assumes the positions are where I specify, fix later
if(positionsdata.positions[i].symbol == 'VCN.TO'){
sheet.getRange("D5").setValue(positionsdata.positions[i].openQuantity);
}
if(positionsdata.positions[i].symbol == 'VUN.TO') {
sheet.getRange("D6").setValue(positionsdata.positions[i].openQuantity);
}
if(positionsdata.positions[i].symbol == 'VIU.TO') {
sheet.getRange("D7").setValue(positionsdata.positions[i].openQuantity);
}
if(positionsdata.positions[i].symbol == 'VEE.TO') {
sheet.getRange("D8").setValue(positionsdata.positions[i].openQuantity);
}
i=i+1;
}
j=j+1;
}
//send cash value to spreadsheet
// sheet.getRange("G1").setValue(data.perCurrencyBalances[i].cash);
}
function logout() {
var service = getQTService();
service.reset();
}
Any advice on what might be going wrong here would be greatly appreciated.
I don't think you can rely on using api01. I think you have to extract the api_server from the auth call that gives you a token (or at least I did this using the example on https://www.questrade.com/api/documentation/getting-started with refresh_token). My last 3 refresh_token auths for a bearer have yielded the api06 endpoint. I took your code and with the oauth authorizing and using api06 it works fine.
The magic sauce is var api_server = QTService.getToken().api_server;

Using Google Apps Script to configure OAuth

I'm having some trouble configuring my Google Apps Script to properly handle the token that comes from the API I'm reaching out to. Everything from what I can tell is compatible.
I am using the Apps Script oAuth2 here.
When I run the below scripts I am able to get to the oAuth screen where i validate on the app, and when it passes the credentials back to google scripts on usercallback i get the below error.
Error: Error retrieving token: {"id":"401","name":"unauthorized","detail":"Unauthorized"} (line 541, file "Service")
My oAuth Script is below:
var CLIENT_ID = '...1';
var CLIENT_SECRET = '...2';
// configure the service
function getYNABService() {
return OAuth2.createService('YNAB')
.setAuthorizationBaseUrl('https://app.youneedabudget.com/oauth/authorize')
.setTokenUrl('https://api.youneedabudget.com/v1/budgets?access_token')
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('read-only')
.setGrantType('authorization_code');
}
// Logs the redict URI to register
// can also get this from File > Project Properties
function logRedirectUri() {
var service = getService();
Logger.log(service.getRedirectUri());
}
// handle the callback
function authCallback (request) {
var YNABService = getYNABService();
var isAuthorized = YNABService.handleCallback(request);
if (isAuthorized) {
return HtmlService.createHtmlOutput('Success! You can close this tab.');
} else {
return HtmlService.createHtmlOutput('Denied. You can close this tab');
}
}
My Google Sheets script is below
// add custom menu
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('YNAB for Sheets')
.addItem('Authorize','showSidebar')
.addItem('Fetch Budget','FetchBudgets')
.addItem('Reset','reset')
.addToUi();
}
/***************************************/
// Show sidebar for Authorization
function showSidebar() {
var YNABService = getYNABService();
if (!YNABService.hasAccess()) {
var authorizationUrl = YNABService.getAuthorizationUrl();
var template = HtmlService.createTemplate(
'Authorize. ' +
'Reopen the sidebar when the authorization is complete.');
template.authorizationUrl = authorizationUrl;
var page = template.evaluate();
SpreadsheetApp.getUi().showSidebar(page);
} else {
// ...
}
}
function reset() {
getYNABService().reset();
}
function FetchBudgets() {
var YNABService = getYNABService();
var response = UrlFetchApp.fetch('https://api.youneedabudget.com/v1/budgets/default/accounts', {
headers: {
Authorization: 'Bearer ' + YNABService.getAccessToken()
}
});
// ...
}
Upon deeper investigation on this, it seems that the problem is on my fault. I mixed the URLs for client/server side auth.
https://app.youneedabudget.com/oauth/token? - this is the correct token URL.

0Auth2 problem to get my google photos libraries in a google sheet of mine

I am trying to follow documentation but never get the 0Auth2 to connect.
Btw I'm running the script manually from the google sheets scripting page, where should I get prompting for allowing access?
(I don't understand all this 0Auth2 scheme and I have already gave authorization to run the script and got client id and secret)...
See below my log and script routines (the first get to photo is still minimalistic as I didn't yet get through the 0Auth2 step ;-) .
Thanks in advance for any hint. I thought it would be trivial as it is my own sheet and google photo account...
Log:
[19-01-06 17:50:05:809 CET] starting
[19-01-06 17:50:05:810 CET] getPhotoService
[19-01-06 17:50:05:849 CET] false
[19-01-06 17:50:05:850 CET] redirectURI=https://script.google.com/macros/d/[REMOVED]/usercallback
[19-01-06 17:50:05:864 CET] Open the following URL and re-run the script: https://accounts.google.com/o/oauth2/auth?client_id=[removed].apps.googleusercontent.com&response_type=code&redirect_uri=https%3A%2F%2Fscript.google.com%2Fmacros%2Fd%2F[removed]%2Fusercallback&state=[removed]&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fphotoslibrary.readonly&login_hint=[removed]&access_type=offline&approval_prompt=force
Script:
function getPhotoService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
Logger.log('getPhotoService');
return OAuth2.createService('gPHOTOfj')
// enable caching on the service, so as to not exhaust script's PropertiesService quotas
.setPropertyStore(PropertiesService.getUserProperties())
.setCache(CacheService.getUserCache())
// Set the endpoint URLs, which are the same for all Google services.
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the client ID and secret, from the Google Developers Console.
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
//.setCallbackFunction('https://script.google.com/macros/d/'+SCRIPT_ID+'/authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
// Set the scopes to request (space-separated for Google services).
.setScope('https://www.googleapis.com/auth/photoslibrary.readonly')
// Below are Google-specific OAuth2 parameters.
// Sets the login hint, which will prevent the account chooser screen
// from being shown to users logged in with multiple accounts.
.setParam('login_hint', Session.getActiveUser().getEmail())
// Requests offline access.
.setParam('access_type', 'offline')
// Forces the approval prompt every time. This is useful for testing,
// but not desirable in a production application.
.setParam('approval_prompt', 'force');
}
function authCallback(request) {
Logger.log('Called back!');
var photoService = getPhotoService();
var isAuthorized = photoService.handleCallback(request);
if (isAuthorized) {
Logger.log('Authorisation Success!');
} else {
Logger.log('Authorisation Denied...!');
}
}
// Modified from http://ctrlq.org/code/20068-blogger-api-with-google-apps-script
function photoAPI() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var albums_sh = ss.getSheetByName("albums") || ss.insertSheet("albums", ss.getSheets().length);
albums_sh.clear(); var nrow = new Array(); var narray = new Array();
Logger.log("starting");
var service = getPhotoService();
Logger.log(service.hasAccess());
Logger.log('redirectURI='+service.getRedirectUri());
if (service.hasAccess()) {
var api = "https://photoslibrary.googleapis.com/v1/albums";
var headers = {
"Authorization": "Bearer " + service.getAccessToken()
};
var options = {
"headers": headers,
"method" : "GET",
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch(api, options);
var json = JSON.parse(response.getContentText());
for (var i in json.items) {
nrow = []; nrow.push(json.items[i].id); nrow.push(json.items[i].name); nrow.push(json.items[i].url); narray.push(nrow);
}
albums_sh.getRange(1,1,narray.length,narray[0].length).setValues(narray);
} else {
var authorizationUrl = service.getAuthorizationUrl();
Logger.log("Open the following URL and re-run the script: " + authorizationUrl);
}
}
So it works, if others want to use it. But it is quite slow (I have 500 albums...):
function photoAPI() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var albums_sh = ss.getSheetByName("albums") || ss.insertSheet("albums", ss.getSheets().length);
albums_sh.clear();
var narray = [];
var api = "https://photoslibrary.googleapis.com/v1/albums";
var headers = { "Authorization": "Bearer " + ScriptApp.getOAuthToken() };
var options = { "headers": headers, "method" : "GET", "muteHttpExceptions": true };
var param= "", nexttoken;
do {
if (nexttoken)
param = "?pageToken=" + nexttoken;
var response = UrlFetchApp.fetch(api + param, options);
var json = JSON.parse(response.getContentText());
json.albums.forEach(function (album) {
var data = [
album.title,
album.mediaItemsCount,
album.productUrl
];
narray.push(data);
});
nexttoken = json.nextPageToken;
} while (nexttoken);
albums_sh.getRange(1, 1, narray.length, narray[0].length).setValues(narray);
}

403 error when executing Google Apps Script form a different google account

I have this javascript to extract html table and then pass the arrays to google apps script as parameters.
var CLIENT_ID = 'some ID';
var SCRIPT_ID = 'some ID';
var SCOPES = ['https://www.googleapis.com/auth/drive.file'];
function handleAuthClick(event) {
gapi.auth.authorize(
{'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': true},
handleAuthResult);
}
function handleAuthResult(authResult) {
if (authResult) {
// Access token has been successfully retrieved, requests can be sent to the API
} else {
// No access token could be retrieved, force the authorization flow.
gapi.auth.authorize(
{'client_id': CLIENT_ID, 'scope': SCOPES, 'immediate': false},
handleAuthResult);
}
}
function exportGsheet() {
var myTableArray = [];
$("table#fin tr").each(function() {
var arrayOfThisRow = [];
var tableData = $(this).find('td');
if (tableData.length > 0) {
tableData.each(function() { arrayOfThisRow.push($(this).text()); });
myTableArray.push(arrayOfThisRow);
}
});
var params = JSON.stringify(myTableArray);
var request = {
'function': 'setData',
'parameters': params,
'devMode': true // Optional.
};
var op = gapi.client.request({
'root': 'https://script.googleapis.com',
'path': 'v1/scripts/' + SCRIPT_ID + ':run',
'method': 'POST',
'body': request
});
op.execute(function(resp){opensheet(resp)});
}
Below is the apps script. This uses Drive API and Executable API.
var DOC_ID = 'some id';
var formattedDate = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd'T'HH:mm:ss'Z'");
var folder = DriveApp.getFolderById('some id');
function setData(parameters) {
var getFile = DriveApp.getFileById(DOC_ID);
var file = getFile.makeCopy(formattedDate, folder);
var ss = SpreadsheetApp.open(file);
var ssId = ss.getId();
ss.getSheets()[0].getRange(5,1,50,24).clear();
var e = JSON.parse(parameters);
var outerArray = [];
for(var i = 0; i < e.length; i++) {
outerArray.push(e[i]);
}
ss.getSheets()[0].getRange(5, 2, outerArray.length, outerArray[0].length).setValues(outerArray);
return {"url":ssId};
Logger.log(ssId);
}
Everything works fine when I authorize using the gmail ID that owns the apps script and project (my own gmail account). But when I authenticate using a different gmail account I get the below error:
error: {code: 403, message: "The caller does not have permission", status: "PERMISSION_DENIED"}
code: 403
message: "The caller does not have permission"
status: "PERMISSION_DENIED"
I intend to make this application public and anyone should be able to authenticate using their gmail account and execute the script. How do I do that? Please help.
Folks, I figured out the problem later. It happened to be permission issue n Developer console. We have to assign permission under Developer Console Project for the project which the apps-script is associated. So follow these steps:
Open your apps script Go to Resources-Developers Console Project
Click on the project name appearing in blue under "This script is
currently associated with project:" It will redirect you to Developer
Console Project.
Click on Menu on the left hand side upper corner and click on
Permissions
Under Permissions click on Add members
In the member type the email ID or domain you want to provide
permission and desired permission level. Click on 'Add'
You are done.
However, I wasnt able to add the entire gmail domain, nor able to add allAuthenticatedUsers. I have raised an issue with google support

How to request unsampled report from Google Analytics Management API using Google Apps Script?

What I have done:
I have Google Analytics Premium
I have authorized OAuth2 for Apps Script by following this instruction: https://github.com/googlesamples/apps-script-oauth2
I have enabled Google Analytics API and Drive API on Advanced Google Services and on the Developers Console.
I'm trying to follow this instruction to request the unsampled report: https://developers.google.com/analytics/devguides/config/mgmt/v3/mgmtReference/management/unsampledReports/insert#request
My problem:
I've written the code below on Google Apps Script editor to request unsampled report from Google Analytics API. As far as I know, if it works correctly, it's supposed to trigger the unsampled request on Google Analytics interface. However, I don't see it in the Pending or Completed section in the interface. And when I ran the code, nothing happened. I didn't even see any error. Could you please help on what I have done wrong? Thank you in advance.
Here is my code:
function insertView()
var request = gapi.client.analytics.management.unsampledReports.insert(
{
'accountId': 'XXXXXX',
'webPropertyId': 'UA-XXXXXX-XX',
'profileId': 'XXXXXXXX',
'resource': {
'title': 'A test Report',
'start-date': '2016-03-31',
'end-date': '2016-04-04',
'metrics': 'ga:itemRevenue',
'dimensions': 'ga:date'
}
});
return request;
}
}
function outputToSpreadsheetNext(request) {
var sheetId = '1RSkx8n-YRMq7Cnco-mvC83bJPKSnsb3QPx3BItAWmN8';
var sheetPrevious= SpreadsheetApp.openById(sheetId).getSheets()[0];
var headerNamesPrevious = []
for (var i = 0, header; header = request.getColumnHeaders()[i]; ++i) {
headerNamesPrevious.push(header.getName());
}
sheetPrevious.getRange(1, 1, 1, headerNamesPrevious.length)
.setValues([headerNamesPrevious]);
// Print the rows of data.
sheetPrevious.getRange(2, 1,request.getRows().length,headerNamesPrevious.length)
.setValues(request.getRows());
}
}
I have written instructions on how to do it here: http://sophearychiv.com/how-to-pull-and-automate-unsampled-reports-from-google-analytics-into-google-spreadsheet/
Here's a working version you might want to try.
Instructions
Create a new Google Spreadsheet.
Copy the content bellow into a new script
Go into Resources > Advanced Google Services
Enable the Google Analytics API toggling it to ON
Click the Google Developer Console link still on the Advanced Google Services dialog
From the Cloud API Manager find and Enable the Analytics API
Now you can run the function insertReport(), this will insert an Unsampled Report using the API. Remember that just like I told you in the previous question, these may take a few hours to process.
Run the updateAllReports() function after a while and it should try to get updated status for the reports.
As a bonus, if the status is complete it will give you the link to the file on Google Drive and also import the data from the CSV into a second sheet.
var LOG_SHEET_NAME = 'Unsampled Report Logs';
var ss = SpreadsheetApp.getActive();
var ui = SpreadsheetApp.getUi();
function insertReport() {
var resource = {
'title': 'A test Report',
'start-date': '2016-03-31',
'end-date': '2016-04-04',
'metrics': 'ga:itemRevenue',
'dimensions': 'ga:date'
};
var accountId = 'XXXXXXXX';
var webPropertyId = 'UA-XXXXXXXX-1';
var profileId = 'YYYYYYYY';
try {
var request = Analytics.Management.UnsampledReports.insert(resource, accountId, webPropertyId, profileId);
} catch (error) {
ui.alert('Error Performing Unsampled Report Query', error.message, ui.ButtonSet.OK);
return;
}
var sheet = ss.getSheetByName(LOG_SHEET_NAME);
if (!sheet) {
sheet = ss.insertSheet(LOG_SHEET_NAME);
sheet.appendRow(['User', 'Account', 'Web Property', 'View', 'Title', 'Inserted Time', 'Updated Time', 'Status', 'Id', 'File']);
sheet.getRange(1, 1, 1, 10).setFontWeight('bold');
}
sheet.appendRow([
Session.getEffectiveUser().getEmail(),
request.accountId,
request.webPropertyId,
request.profileId,
request.title,
request.created,
request.updated,
request.status,
request.id
]);
}
// Scans LOG_SHEET_NAME and tries to update any report that is PENDING
function updateAllReports() {
var sheet = ss.getSheetByName(LOG_SHEET_NAME);
var lastRow = sheet.getLastRow();
var dataRange = sheet.getRange(2,1, lastRow, 10);
var data = dataRange.getValues();
for (var i=0; i<data.length; i++) {
// If data is PENDING let's try to update it's status. Hopefully it's complete now
// but it may take up to 24h to process an Unsampled Reprot
if (data[i][0] == Session.getEffectiveUser().getEmail() && data[i][7] == 'PENDING') {
try {
var request = Analytics.Management.UnsampledReports.get(data[i][1], data[i][2], data[i][3], data[i][8]);
} catch (error) {
ui.alert('Error Performing Unsampled Report Query', error.message, ui.ButtonSet.OK);
return;
}
data[i] = [
Session.getEffectiveUser().getEmail(),
request.accountId,
request.webPropertyId,
request.profileId,
request.title,
request.created,
request.updated,
request.status,
request.id,
request.status == 'COMPLETED' ? DriveApp.getFileById(request.driveDownloadDetails.documentId).getUrl() : ''
];
// If data is Complete let's import it into a new sheet
if (request.status == 'COMPLETED') {
importReportFromDrive(request.title, request.driveDownloadDetails.documentId);
}
}
}
// Write only once to the spreadsheet this is faster
dataRange.setValues(data);
}
function importReportFromDrive(title, fileId) {
var file = DriveApp.getFileById(fileId);
var csvString = file.getBlob().getDataAsString();
var data = Utilities.parseCsv(csvString);
// Find a suitable name for the new sheet
var i=1;
var sheetName = title;
while (ss.getSheetByName(sheetName)) {
sheetName = title + ' ('+ i++ +')';
}
var sheet = ss.insertSheet(sheetName);
var range = sheet.getRange(1, 1, data.length, data[0].length);
range.setValues(data);
}
PS: I work for Google Analytics support, as "Zig Mandel" said in the comments feel free to reach out to Google Analytics Premium Support and we're happy to help. We're very friendly.