Required permissions: https://www.googleapis.com/auth/spreadsheets in a custom function - google-apps-script

I have read through the official documentation that states, you are not allowed to use services that require authorization such as SpreadsheetApp.openById within a custom function.
I am using a script to call a spreadsheet in its functions and it's doing that fluently. My custom function is not using the service SpreadsheetApp.openById, but still tells me that I do not have the permission. I just want to know whether it is possible to run the custom function or not, even though I am not calling a spreadsheet in the function itself?
Updated:
My custom function build's a reference id for a particular quotation.
I've also tried using https://www.googleapis.com/auth/spreadsheets in oauthScopes in the json file, didn't work.
This is the function calling openById:
var ss1 = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var dukeid = "1WGbEo1Xr99HwHY_4ZaeTRIgCOuNcjVfqCzZx4dcQX4I"
var duke = SpreadsheetApp.openById(dukeid);
var totalstockd = duke.getSheetByName("Total Stock").getRange(2,3,2500,7).getValues();
var avmid = "1a6bm2O_iljHZUoF2BhYeyxUT13tB06-JJCYeYCZZ10Q"
var avm = SpreadsheetApp.openById(avmid);
var totalstocka = avm.getSheetByName("Total Stock").getRange(2,3,1000,7).getValues();
function when(e){
var activeCell = e.range;
var val = activeCell.getValue();
var r = activeCell.getRow();
var c = activeCell.getColumn();
var ssName = activeCell.getSheet().getName();
if (ssName=="General Information" && (r==3 || r==6) && c==3){
var rescell = ss1.getRange(r,6);
var unitcell = ss1.getRange(r,7);
rescell.clearContent();
if(val[0]=="A"){
var result = sumalt(val,totalstocka,unitcell);
rescell.setValue(result);
}
else {
var result = sumalt(val,totalstockd,unitcell);
rescell.setValue(result);
}
}
else{
console.log("No Edit");
}
}
And this is my custom function:
function QREF(Company,ID){
var td=new Date().valueOf();
var year = new Date().getFullYear();
var hd=new Date(year, 0, 0).valueOf();
var year2 = year - 2000
var sec=1000;
var min=60*sec;
var hour=60*min;
var day=24*hour;
var diff=td-hd;
var julian=Math.floor(diff/day);
Logger.log(year2);
string = Company + ID + "-"+ "" + julian + "/" + year2 + "-";
return string;
}

Modification points:
When I saw your script, I noticed that SpreadsheetApp.openById is used as the global. By this, when your custom function is run, SpreadsheetApp.openById is run. So, such error occurs. I think that this is the reason of your issue.
When you want to use both script in your Google Apps Script, how about the following modification?
Modified script:
function when(e) {
// These scripts are included in a function.
var ss1 = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var dukeid = "1WGbEo1Xr99HwHY_4ZaeTRIgCOuNcjVfqCzZx4dcQX4I"
var duke = SpreadsheetApp.openById(dukeid);
var totalstockd = duke.getSheetByName("Total Stock").getRange(2, 3, 2500, 7).getValues();
var avmid = "1a6bm2O_iljHZUoF2BhYeyxUT13tB06-JJCYeYCZZ10Q"
var avm = SpreadsheetApp.openById(avmid);
var totalstocka = avm.getSheetByName("Total Stock").getRange(2, 3, 1000, 7).getValues();
var activeCell = e.range;
var val = activeCell.getValue();
var r = activeCell.getRow();
var c = activeCell.getColumn();
var ssName = activeCell.getSheet().getName();
if (ssName == "General Information" && (r == 3 || r == 6) && c == 3) {
var rescell = ss1.getRange(r, 6);
var unitcell = ss1.getRange(r, 7);
rescell.clearContent();
if (val[0] == "A") {
var result = sumalt(val, totalstocka, unitcell);
rescell.setValue(result);
} else {
var result = sumalt(val, totalstockd, unitcell);
rescell.setValue(result);
}
} else {
console.log("No Edit");
}
}
function QREF(Company, ID) {
var td = new Date().valueOf();
var year = new Date().getFullYear();
var hd = new Date(year, 0, 0).valueOf();
var year2 = year - 2000
var sec = 1000;
var min = 60 * sec;
var hour = 60 * min;
var day = 24 * hour;
var diff = td - hd;
var julian = Math.floor(diff / day);
Logger.log(year2);
string = Company + ID + "-" + "" + julian + "/" + year2 + "-";
return string;
}
By this modification, when QREF() is run as the custom function, SpreadsheetApp.openById is not run. By this, such error can be removed.
Note:
If you are using the following script at other function, please be careful this. In that case, please include the script to the function. Or, please include the following script as new function, and call the function from other function.
var ss1 = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var dukeid = "1WGbEo1Xr99HwHY_4ZaeTRIgCOuNcjVfqCzZx4dcQX4I"
var duke = SpreadsheetApp.openById(dukeid);
var totalstockd = duke.getSheetByName("Total Stock").getRange(2, 3, 2500, 7).getValues();
var avmid = "1a6bm2O_iljHZUoF2BhYeyxUT13tB06-JJCYeYCZZ10Q"
var avm = SpreadsheetApp.openById(avmid);
var totalstocka = avm.getSheetByName("Total Stock").getRange(2, 3, 1000, 7).getValues();

Related

Google Sheets function runs but does not affect sheet content

I'm working on a Google Sheets script to perform the following:
iterate through a specified sheet, finding rows that do not contain a specified value within a specified column
store these rows as a range in a variable
remove all other rows
replace the sheet content with the stored rows
The script runs without error, but does not affect sheet content. I'm not sure what the issue is - any feedback is appreciated.
Here's the script:
function onOpen() {
const ui = SpreadsheetApp.getUi();
ui.createMenu('Clear OI')
.addItem('Clear OI', 'removeZeroOI')
.addToUi();
}
function removeZeroOI() {
// Deleting Rows Based on Cell Values
//GLOBALS
var SS = SpreadsheetApp.openById("mySheetID");
var SHEET = SS.getSheetByName("mySheetName");
var RANGE = SHEET.getDataRange();
var DELETE_VAL = 0;
var COL_TO_SEARCH = 13; //column N
function main() {
var startTime = new Date().getTime();
var deleteSelectedRows = removeFilterSetVals();
var runTime = (new Date().getTime() - startTime)/1000;
Logger.log("Runtime is: "+runTime + " seconds");
};
function removeFilterSetVals(){
var rangeVals = RANGE.getValues();
var filteredRange = rangeVals.filter(function(val){
return val[COL_TO_SEARCH] != DELETE_VAL ;
});
RANGE.clearContent();
var newRange = SHEET.getRange(1,1,filteredRange.length, filteredRange[0].length);
newRange.setValues(filteredRange);
};
}
If you are actually using your showing script, I think that in your script, when the function of removeZeroOI() is run, main() and removeFilterSetVals() are not run. By this, the script doesn't work while no error occurs.
When you want to run main() and removeFilterSetVals(), how about the following modifications?
Modified script:
function removeZeroOI() {
var SS = SpreadsheetApp.openById("mySheetID");
var SHEET = SS.getSheetByName("mySheetName");
var RANGE = SHEET.getDataRange();
var DELETE_VAL = 0;
var COL_TO_SEARCH = 13; //column N
main(); // Added
function main() {
var startTime = new Date().getTime();
var deleteSelectedRows = removeFilterSetVals();
var runTime = (new Date().getTime() - startTime) / 1000;
Logger.log("Runtime is: " + runTime + " seconds");
};
function removeFilterSetVals() {
var rangeVals = RANGE.getValues();
var filteredRange = rangeVals.filter(function(val) {
return val[COL_TO_SEARCH] != DELETE_VAL;
});
RANGE.clearContent();
var newRange = SHEET.getRange(1, 1, filteredRange.length, filteredRange[0]
.length);
newRange.setValues(filteredRange);
};
}
And,
function removeZeroOI() {
var SS = SpreadsheetApp.openById("mySheetID");
var SHEET = SS.getSheetByName("mySheetName");
var RANGE = SHEET.getDataRange();
var DELETE_VAL = 0;
var COL_TO_SEARCH = 13; //column N
var startTime = new Date().getTime();
// Script of "removeFilterSetVals()" is put here.
var rangeVals = RANGE.getValues();
var filteredRange = rangeVals.filter(function(val) {
return val[COL_TO_SEARCH] != DELETE_VAL;
});
RANGE.clearContent();
var newRange = SHEET.getRange(1, 1, filteredRange.length, filteredRange[0]
.length);
newRange.setValues(filteredRange);
var runTime = (new Date().getTime() - startTime) / 1000;
Logger.log("Runtime is: " + runTime + " seconds");
}

importJSON in Google Sheet reduce API connections?

I have made an other question here:
First question
It seems I'm calling to much the API.
My script calls 23 times the API in one go.
This is how my script looks like :
var ss = SpreadsheetApp.getActiveSheet();
//Creates a menu called Crypto.
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Crypto')
.addItem('Update Prices','updatePrices')
.addItem('Update Sheet','updateSheet')
.addToUi();
}
//Copy cells.
function copyCell() {
ss.getRange("D2:D13").copyTo(ss.getRange("E2"), {contentsOnly:true});
ss.getRange("B2:B13").copyTo(ss.getRange("G2"), {contentsOnly:true});
ss.getRange("M1").copyTo(ss.getRange("M2"), {contentsOnly:true});
ss.getRange("M5").copyTo(ss.getRange("M6"), {contentsOnly:true});
}
/**
* Imports JSON data to your spreadsheet Ex: IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1/?convert=EUR","data/quotes/EUR/price")
* #param url URL of your JSON data as string
* #param xpath simplified xpath as string
* #customfunction
*/
function IMPORTJSON(url,xpath){
try{
// /rates/EUR
var res = UrlFetchApp.fetch(url);
var content = res.getContentText();
var json = JSON.parse(content);
var patharray = xpath.split("/");
//Logger.log(patharray);
for(var i=0;i<patharray.length;i++){
json = json[patharray[i]];
}
//Logger.log(typeof(json));
if(typeof(json) === "undefined"){
return "Node Not Available";
} else if(typeof(json) === "object"){
var tempArr = [];
for(var obj in json){
tempArr.push([obj,json[obj]]);
}
return tempArr;
} else if(typeof(json) !== "object") {
return json;
}
}
catch(err){
return "Error getting data";
}
}
//Importing CMC Data into sheet
function importCMC() {
var btc_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1/?convert=EUR","data/quotes/EUR/price");
var btc_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B2").setValue([btc_eur]);
ss.getRange("H2").setValue([btc_btc]);
var bhc_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1831/?convert=EUR","data/quotes/EUR/price");
var bhc_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1831/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B3").setValue([bhc_eur]);
ss.getRange("H3").setValue([bhc_btc]);
var ltc_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2/?convert=EUR","data/quotes/EUR/price");
var ltc_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B4").setValue([ltc_eur]);
ss.getRange("H4").setValue([ltc_btc]);
var ada_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2010/?convert=EUR","data/quotes/EUR/price");
var ada_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2010/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B5").setValue([ada_eur]);
ss.getRange("H5").setValue([ada_btc]);
var trx_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1958/?convert=EUR","data/quotes/EUR/price");
var trx_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1958/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B6").setValue([trx_eur]);
ss.getRange("H6").setValue([trx_btc]);
var neo_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1376/?convert=EUR","data/quotes/EUR/price");
var neo_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1376/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B7").setValue([neo_eur]);
ss.getRange("H7").setValue([neo_btc]);
var ont_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2566/?convert=EUR","data/quotes/EUR/price");
var ont_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2566/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B8").setValue([ont_eur]);
ss.getRange("H8").setValue([ont_btc]);
var gas_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1785/?convert=EUR","data/quotes/EUR/price");
var gas_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/1785/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B9").setValue([gas_eur]);
ss.getRange("H9").setValue([gas_btc]);
var enj_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2130/?convert=EUR","data/quotes/EUR/price");
var enj_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2130/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B10").setValue([enj_eur]);
ss.getRange("H10").setValue([enj_btc]);
var tky_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2507/?convert=EUR","data/quotes/EUR/price");
var tky_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2507/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B11").setValue([tky_eur]);
ss.getRange("H11").setValue([tky_btc]);
var uuu_eur = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2645/?convert=EUR","data/quotes/EUR/price");
var uuu_btc = IMPORTJSON("https://api.coinmarketcap.com/v2/ticker/2645/?convert=BTC","data/quotes/BTC/price");
ss.getRange("B12").setValue([uuu_eur]);
ss.getRange("H12").setValue([uuu_btc]);
var cmc_usd = IMPORTJSON("https://api.coinmarketcap.com/v2/global/","data/quotes/USD/total_market_cap");
ss.getRange("M1").setValue([cmc_usd]);
}
//Getting euro prices from Coincapmarket and place them in specific cells.
function updatePrices() {
copyCell();
importCMC();
//Get current date
var now = new Date();
ss.getRange('F1').setValue(now)
}
//Getting euro prices from Coincapmarket and place them in specific cells.
function updateSheet() {
copyCell();
importCMC();
//Get date.
var now = new Date();
ss.getRange('F1').setValue(now)
ss.getRange("F1").copyTo((ss.getRange(ss.getRange("A18:A111").getValues().filter(String).length + 18, 1)), {contentsOnly:true});
ss.getRange("D15").copyTo((ss.getRange(ss.getRange("B18:B111").getValues().filter(String).length + 18, 2)), {contentsOnly:true});
//Copy the formula's from row 19 to last filled cell in A and B.
var row = 19;
CopyFormulasDown.copyFormulasDown(ss, row);
}
The problem with V2 api of CMC is that the BTC price has to be checked with an other URL. I'm not a hero in array's. Sorry.
I'm thinking of pulling four times the ticker API and then find the right info
1. https://api.coinmarketcap.com/v2/ticker/?convert=EUR
2. https://api.coinmarketcap.com/v2/ticker/?convert=EUR&start=101
3. https://api.coinmarketcap.com/v2/ticker/?convert=EUR&start=201
4. https://api.coinmarketcap.com/v2/ticker/?convert=EUR&start=301
Because the api limits to 100 tickers I have to create 4. I'm using V2 of the IP and I'm using the ID to get the right currency. That is the number behind the ticker. I have to use 4 downloads because The highest rank of currency is 316.
What is the best way to optimize this script with out calling to much api's?
I have reduced my script. It now has 4 api calls. Sometimes still to much for coinmarketcap.
var ss = SpreadsheetApp.getActiveSheet();
//Creates a menu called Crypto.
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Crypto')
.addItem('Update Prices','updatePrices')
.addItem('Update Sheet','updateSheet')
.addToUi();
}
//Copy cells.
function copyCell() {
ss.getRange("D2:D13").copyTo(ss.getRange("E2"), {contentsOnly:true});
ss.getRange("B2:B13").copyTo(ss.getRange("G2"), {contentsOnly:true});
ss.getRange("M1").copyTo(ss.getRange("M2"), {contentsOnly:true});
ss.getRange("M5").copyTo(ss.getRange("M6"), {contentsOnly:true});
}
//Importing CMC Data into sheet
function importCMC() {
var response = UrlFetchApp.fetch("https://api.coinmarketcap.com/v2/ticker/?convert=EUR");
var content = response.getContentText();
var json = JSON.parse(content);
var btc_eur = json["data"]["1"]["quotes"]["EUR"]["price"];
ss.getRange("B2").setValue([btc_eur]);
var bch_eur = json["data"]["1831"]["quotes"]["EUR"]["price"];
ss.getRange("B3").setValue([bch_eur]);
var ltc_eur = json["data"]["2"]["quotes"]["EUR"]["price"];
ss.getRange("B4").setValue([ltc_eur]);
var ada_eur = json["data"]["2010"]["quotes"]["EUR"]["price"];
ss.getRange("B5").setValue([ada_eur]);
var trx_eur = json["data"]["1958"]["quotes"]["EUR"]["price"];
ss.getRange("B6").setValue([trx_eur]);
var neo_eur = json["data"]["1376"]["quotes"]["EUR"]["price"];
ss.getRange("B7").setValue([neo_eur]);
var ont_eur = json["data"]["2566"]["quotes"]["EUR"]["price"];
ss.getRange("B8").setValue([ont_eur]);
var gas_eur = json["data"]["1785"]["quotes"]["EUR"]["price"];
ss.getRange("B9").setValue([gas_eur]);
Utilities.sleep(5000)
var response = UrlFetchApp.fetch("https://api.coinmarketcap.com/v2/ticker/?convert=EUR&start=101");
var content = response.getContentText();
var json = JSON.parse(content);
var enj_eur = json["data"]["2130"]["quotes"]["EUR"]["price"];
ss.getRange("B10").setValue([enj_eur]);
var tky_eur = json["data"]["2507"]["quotes"]["EUR"]["price"];
ss.getRange("B11").setValue([tky_eur]);
Utilities.sleep(5000)
var response = UrlFetchApp.fetch("https://api.coinmarketcap.com/v2/ticker/2645/?convert=EUR");
var content = response.getContentText();
var json = JSON.parse(content);
var uuu_eur = json["data"]["quotes"]["EUR"]["price"];
ss.getRange("B12").setValue([uuu_eur]);
Utilities.sleep(5000)
var response = UrlFetchApp.fetch("https://api.coinmarketcap.com/v2/global/");
var content = response.getContentText();
var json = JSON.parse(content);
var cmc_usd = json["data"]["quotes"]["USD"]["total_market_cap"];
ss.getRange("M1").setValue([cmc_usd]);
}
//Getting euro prices from Coincapmarket and place them in specific cells.
function updatePrices() {
copyCell();
importCMC();
//Get current date
var now = new Date();
ss.getRange('F1').setValue(now)
}
//Getting euro prices from Coincapmarket and place them in specific cells.
function updateSheet() {
copyCell();
importCMC();
//Get date.
var now = new Date();
ss.getRange('F1').setValue(now)
ss.getRange("F1").copyTo((ss.getRange(ss.getRange("A18:A111").getValues().filter(String).length + 18, 1)), {contentsOnly:true});
ss.getRange("D15").copyTo((ss.getRange(ss.getRange("B18:B111").getValues().filter(String).length + 18, 2)), {contentsOnly:true});
//Copy the formula's from row 19 to last filled cell in A and B.
var row = 19;
CopyFormulasDown.copyFormulasDown(ss, row);
}

Force refresh ImportXML

I want to force an importXML to auto-refresh every five minutes. This is the script I am trying to run and getting the error "Bad value (line 7, file "RefreshImports" . I do not know why. I found it here: Periodically refresh IMPORTXML() spreadsheet function
function RefreshImports() {
var lock = LockService.getScriptLock();
if (!lock.tryLock(5000)) return; // Wait up to 5s for previous
refresh to end.
var id = "[YOUR SPREADSHEET ID]";
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getSheetByName("[SHEET NAME]");
var dataRange = sheet.getDataRange();
var formulas = dataRange.getFormulas();
var content = "";
var now = new Date();
var time = now.getTime();
var re = /.*[^a-z0-9]import(?:xml|data|feed|html|range)\(.*/gi;
var re2 = /((\?|&)(update=[0-9]*))/gi;
var re3 = /(",)/gi;
for (var row = 0; row < formulas.length; row++) {
for (var col = 0; col < formulas[0].length; col++) {
content = formulas[row][col];
if (content != "") {
var match = content.search(re);
if (match !== -1) {
// import function is used in this cell
var updatedContent = content.toString().replace(re2, "$2update=" +
time);
if (updatedContent == content) {
// No querystring exists yet in url
updatedContent = content.toString().replace(re3, "?update=" + time +
"$1");
}
// Update url in formula with querystring param
sheet.getRange(row + 1, col + 1).setFormula(updatedContent);
}
}
}
}
// Done refresh; release the lock.
lock.releaseLock();
// Show last updated time on sheet somewhere
sheet.getRange(7, 2).setValue("Rates were last updated at " +
now.toLocaleTimeString())
}
In the code where it says "[YOUR SPREADSHEET ID]", I am to enter the name of my spreadsheet correct? I do not know anything about this.
On [YOUR SPREADSHEET ID] you should add the spreadsheet id, not it's name.
The spreadsheet id for
https://docs.google.com/spreadsheets/d/1Xhgfr3z4EwPtjS4aahytU_3TOVxjNb8JvHo88h3nZaE/edit#gid=14522064
is
1Xhgfr3z4EwPtjS4aahytU_3TOVxjNb8JvHo88h3nZaE
I found it easier to use the URL instead the id, here is the bit of code:
var url = "URL OF SPREADSHEET";
var sheetName = "NAME OF SPECIFIC SHEET";
var ss = SpreadsheetApp.openByUrl(url);
var sheet = ss.getSheetByName(sheetName);

calendar from apps script : every time authorized required. Only work with primary calendar

In a spreadsheet, I have a app script for count hours in a google calendar and the output is copied in the spreadsheet.
A few days ago, anything worked fine.
but today (monday July 1 2013 ), when I try run the script, every time, I get the message "Authorized required".
http://cl.ly/Q0bd
I press in "Authorized" button, and re-run, and again get the message "Authorized required".
the code in a gist
// add menu
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [{name:"Calcular Horas", functionName: "calculateHours"}];
ss.addMenu("Hours", menuEntries);
// calcular al iniciar
//calculateHours();
}
function authorize() {
var oauthConfig = UrlFetchApp.addOAuthService("calendar");
var scope = "https://www.googleapis.com/auth/calendar";
oauthConfig.setConsumerKey("anonymous");
oauthConfig.setConsumerSecret("anonymous");
oauthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
oauthConfig.setAuthorizationUrl("https://accounts.google.com/OAuthAuthorizeToken");
oauthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
}
/*
* Count hours of events with same name
*/
function countHours(calId, eventName){
authorize();
var cal = CalendarApp.getCalendarById(calId);
var key = "...";
var query = encodeURIComponent(eventName);
calId = encodeURIComponent(calId);
var params = {
method: "get",
oAuthServiceName: "calendar",
oAuthUseToken: "always",
};
var url = "https://www.googleapis.com/calendar/v3/calendars/"+
calId+"/events?q=" + query + "&key=" + key;
var request = UrlFetchApp.fetch(url, params);
//Logger.log(url);
var response = Utilities.jsonParse(request.getContentText());
var items = response.items;
var start, end;
var hours = 0;
for ( i = 0 ; i < items.length ; i++){
if ( items[i].status != "cancelled" ){
if ( items[i].summary == eventName ){
start = items[i].start.dateTime;
end = items[i].end.dateTime;
start = new Date(start.replace(/-/g,'/').replace(/[A-Z]/,' ').substr(0,19) );
end = new Date(end.replace(/-/g,'/').replace(/[A-Z]/,' ').substr(0,19));
hours = hours + ( end - start ) / ( 1000 * 60 * 60 );
}
}
}
return hours;
}
function calculateHours(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheets()[0];
var rows = s.getDataRange();
var nRows = rows.getNumRows();
var values = rows.getValues();
// from second row
for ( var i = 1; i < nRows ; i ++){
var row = values[i];
var h = countHours(row[0], row[1]);
s.getRange(i+1, 3).setValue(h);
}
}
EDIT
When I change the line
var url = "https://www.googleapis.com/calendar/v3/calendars/"+
calId+"/events?q=" + query + "&key=" + key;
to
var url = "https://www.googleapis.com/calendar/v3/calendars/"+
"primary"+"/events?q=" + query + "&key=" + key;
this work, but is only valid for the primary calendar.
finally I changed the access to calendar API to CalendarApp service with .getEvents
var cal = CalendarApp.getCalendarById(cal_id);
var this_year = new Date(2013,0,1);
var now = new Date()
var events = cal.getEvents(this_year, now, {search: event_name});

Replace formula of a cell with script

I am trying to replace some part of a formula in cell D3 of a spreadsheet, but I can't seem to do it. The formula in D3 is very long, but I only need to replace what would be searchtext variable and replace it with replacetext variable. Any ideas? Here's my code.
function dashboards(){
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var origSheet1 = ss1.getSheetByName('Daily');
var searchtext = Browser.inputBox("Enter search text");
var replacetext = Browser.inputBox("Enter replace text");
var form = origSheet1.getRange("D3").getFormulaR1C1();
form.indexof(searchtext);
var updated = form.replace(searchtext, replacetext);
form.setFormula(updated);}
You're not far off. The problem is that form, the below, is a String, not a reference to your Range.
var form = origSheet1.getRange("D3").getFormulaR1C1();
You can see this by inserting
Logger.log(form + "; type: " + typeof form); //String
after that line and checking the log in the Script Editor.
You just need to change
form.setFormula(updated);
to
origSheet1.getRange("D3").setFormulaR1C1(updated);
to update the actual range.
Copy the code below and run it via Script Manager or a menu item.
It operates on whatever the selected range is, whether it's a single cell or extends over multiple rows & columns.
It pops up a toast message to tell you when the procedure has finished but it leaves the UiInstance open in case you want to do more replacing.
You can keep it open and perform multiple search/replace in formulas on multiple selections or the same search on different sheets.
function handySRF() { // script composed by ailish#ahrosters.com
var ss = SpreadsheetApp.getActive();
var app = UiApp.createApplication().setHeight(200).setWidth(270).setTitle('Search and Replace In Formulas');
var panel = app.createAbsolutePanel().setId('panel').setHeight(198).setWidth(268)
.setStyleAttribute('background', 'lightCyan');
var lblSearch = app.createLabel('Search for:').setId('lblSearch');
var txtSearch = app.createTextBox().setId('txtSearch').setName('txtSearch');
var lblReplace = app.createLabel('Replace with:').setId('lblReplace');
var txtReplace = app.createTextBox().setId('txtReplace').setName('txtReplace');
var handler = app.createServerHandler('btnStartSearch');
var btnStartSearch = app.createButton('Start Search').addClickHandler(handler)
.setStyleAttribute('background', 'lightGreen');
handler.addCallbackElement(panel);
var handler2 = app.createServerHandler('btnCloseWindow');
var btnCloseWindow = app.createButton('Close Window').addClickHandler(handler2)
.setStyleAttribute('background', 'lightYellow');
handler2.addCallbackElement(panel);
panel.add(lblSearch, 10, 6)
panel.add(txtSearch, 10, 33)
panel.add(lblReplace, 10, 75)
panel.add(txtReplace, 10, 100)
panel.add(btnStartSearch, 10, 151)
panel.add(btnCloseWindow, 130, 151)
app.add(panel);
ss.show(app);
};
function btnStartSearch(e) {
var ss = SpreadsheetApp.getActive();
var app = UiApp.getActiveApplication();
var search = e.parameter.txtSearch;
var replace = e.parameter.txtReplace;
var rows = ss.getActiveSelection();
var numRows = rows.getNumRows();
var formulas = rows.getFormulas();
var newFormulas = [];
for (var i = 0; i <= numRows - 1; i++) {
var oldData = formulas[i];
var newData = [];
for (var j=0; j<oldData.length; ++j) {
var item = oldData[j].replace(new RegExp(search, "g"), replace);
newData.push(item);
}
newFormulas.push(newData);
}
rows.setFormulas(newFormulas);
var str = 'Finished replacing ' + search + ' with ' + replace;
ss.toast(str, '', 2);
};
function btnCloseWindow(e) {
var ss = SpreadsheetApp.getActive();
var app = UiApp.getActiveApplication();
app.close();
return app;
};