Authorization Lifecycle on published add-on is not working - google-apps-script

Have a problem with my add-on that should, but not creating a menu items in Add-ons on Google Sheets and Docs on install from the store until the page is refreshed.
According to Google Support I should look in to the following:
"Usually this is caused by a problem with the Authorization Lifecycle, specifically the opening stage.
The most common culprit is a global variable in the code that tries to access Google services without authorization, like:
var doc = DocumentApp.getActiveDocument();
See the documentation:
Warning: When your onOpen(e) function runs, the entire script is loaded and any global statements are executed. These statements execute under the same authorization mode as onOpen(e) and will fail if the mode prohibits them. This preventsonOpen(e) from running. If your published add-on fails to add its menu items, look in the browser's JavaScript console to see if an error was thrown, then examine your script to see whether the onOpen(e) function or global variables call services that aren't allowed in AuthMode.NONE."
I have no idea what and how should I deal with this as my add-on was not created by me. I can do minor things, but this is something that I cannot handle on my own and really need your help please.
Hear is my script:
function onOpen(e) {
SpreadsheetApp.getUi().createAddonMenu()
.addItem('Browse Templates', 'browseTemplates')
.addToUi();
}
function onInstall(e) {
onOpen(e);
}
function browseTemplates(){
collectBasicData();
// Display a modal dialog box with custom HtmlService content.
var htmlOutput = HtmlService
.createTemplateFromFile("Gallery").evaluate()
.setWidth(700)
.setHeight(510);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Spreadsheet123 - Template Vault');
}
function collectAllData(){
var sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(DATA_SHEET);
DATA = sheet.getDataRange().getValues();
return DATA;
}
function collectBasicData(){
var sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(PIVOT_SHEET);
var tabSheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(TAB_SHEET);
BASIC_DATA = {
"tab_about" : getValue(tabSheet,"B1"),
"tab_help": getValue(tabSheet,"B2"),
"pivot":sheet.getDataRange().getValues()
};
return false;
}
function getValue(sheet,addr){
return sheet.getRange(addr).getValue().toString().replace(/^\s+|\s+$/g, '');
}
function createACopy(id){
var docName = DocsList.getFileById(id).getName();
return DocsList.getFileById(id).makeCopy(docName).getUrl();
}
function insertInCurrent(id){
var destinationSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheets = SpreadsheetApp.openById(id).getSheets();
for(var i=0;i<sourceSheets.length;i++){
var sheetName = sourceSheets[i].getName();
var source = SpreadsheetApp.openById(id).getSheetByName(sheetName);
source.copyTo(destinationSpreadSheet).setName(sheetName);
}
}
I have looked in to the documentation on Google, but cannot understand how and where I should use it in my script.
Your help is highly appreciated and thanks in advance

Related

GoogleJsonResponseException: API call with error: Login Required

I made a script using the advanced service API Google Drive. It's working fine when we stay into the app script GUI :
/** #OnlyCurrentDoc */
function GetListOfDrivesName() {
const ALL_AVALIBLE_DRIVE = Drive.Drives.list();
return ALL_AVALIBLE_DRIVE.items.map(driveData => driveData = driveData.name)
}
However, when it's called from cell into Google Sheet we got an error
Error message is like below : GoogleJsonResponseException: API call to drive.drives.list failed with error: Login Required.
I guess it's some authentification & authorisation to ask before using the sheet.
Unfortuantly I have no idea how to request that ! I read doc but it's sound like it will be asked promptly.
In addition, trigger have been added for this function but it neither worked
Any idea ? Thanks in advance !
Hi #Yuri Khristich you were right, using ui is a good work around , code turn up to work corectly
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var ui = SpreadsheetApp.getUi();
ui.createMenu('[FM Script for G Drive]')
.addItem('test','showAvaillableDrive')
.addToUi();
}
function showAvaillableDrive(){
var ui = SpreadsheetApp.getUi();
var resultat = ui.prompt(GetListOfDrivesName())
}
function GetListOfDrivesName() {
const ALL_AVALIBLE_DRIVE = Drive.Drives.list();
return ALL_AVALIBLE_DRIVE.items.map(driveData => driveData = driveData.name)
}
As suggested by the comments you can build a menu over the Sheet and run it to write down Drive files that I own.
I have this custom Sheet where you can run the "Drive" function over "Adv Menu"
I automatically get the information of the Sheet and get a list of my Drive files:
function onOpen () {
var ui= SpreadsheetApp.getUi();
ui.createMenu('Adv Menu').addItem('Drive', 'getMyFilesFromDrive').addToUi();
}
function getMyFilesFromDrive() {
var myFiles = DriveApp.searchFiles('"me" in owners');
var sheet = SpreadsheetApp.getActive().getSheetByName("Files");
sheet.clear();
var rows = [];
rows.push(["ID", "Name", "Url"]);
while(myFiles.hasNext()) {
var file = myFiles.next();
if(file != null) {
rows.push([file.getId(), file.getName(), file.getUrl()]);
}
}
sheet.getRange(1,1,rows.length,3).setValues(rows);
}
It would also write it directly to my Sheet. Feel free to review it and use it.
You can also Draw a button (Inserting a Google Drawing) over the Sheet and assign a script:
Reference:
https://developers.google.com/apps-script/guides/menus

Google Docs Apps Script Loading Indicator

I'm running a script when I open/refresh a Google Doc. It takes some time to run and can affect values in the doc, so I want to show some type of loading indicator to the user until it's done. I would prefer to not overlay a modal, so the doc is still accessible, but apart from that any solution, even a hacky one, would be ok.
// EXECUTE SCRIPT ON OPEN
function onOpen() {
// SHOW LOADING TO USER
initializeDoc();
doSomeStuffThatTakesSomeTime();
const ui = DocumentApp.getUi();
ui.createMenu('MyMenu')
.addItem('Click', 'doSomeStuffThatTakesSomeTime')
.addToUi();
// TURN LOADING OFF
}
Loading...
function loading() {
const ui = DocumentApp.getUi();
ui.showModelessDialog(HtmlService.createHtmlOutput("Loading...."),"Please Wait");
Utilities.sleep(5000);
const hl = '<!DOCTYPE html><html><head><base target="_top"></head><script>window.onload=()=>{google.script.host.close();}</script><body></body></html>';
ui.showModelessDialog(HtmlService.createHtmlOutput(hl),"Good Bye")
}
You will require an installable onOpen() such as below:
function onMyOpen(e) {
loading();
}

Running a web app from a google sheet menu click

I am trying to run a webapp from a spreadsheet when the user clicks a menu item. The code is below. My problem is I get this error message
We're sorry, a server error occurred. Please wait a bit and try again
I have deployed it as a webapp and when I do the test deployment all is good but if I try and run it from the spreadsheet I get the above. What am I doing wrong?
function onOpen() {
var ss = SpreadsheetApp.getActive();
var menuEntries = [{name: "xxx", functionName: "doGet"}];
ss.addMenu("yyy", menuEntries);
}
function doGet()
{
var ss = SpreadsheetApp.getActive();
let HTMLString = "<style> h1,p {font-family: 'Helvitica', 'Arial'}</style>"
+ "<h1>Hello World!</h1>"
+ "<p>Welcome to the Web App";
HTMLOutput = HtmlService.createHtmlOutput(HTMLString);
return HTMLOutput
};
It's not possible to directly run a web app from a custom menu but yo might open a dialog with client-side code that will open your web app on a new window. See Google Apps Script to open a URL for details.
Explanation
doGet is a reserved function name that will be triggered when the web app url gets an HTTP GET call. While it can be called from a custom menu, it's not expecting a "return" from the function called, so there is no place available to render the return of your doGet function.

Exception: Cannot call SpreadsheetApp.getUi() from this context. (line 1)

I have a project with two scripts, that is bound to a Google spreadsheet.
The first script opens the UI
var ui = SpreadsheetApp.getUi();
var userProperties = PropertiesService.getUserProperties();
const TOKEN_OLD = 'api.token_old';
function onOpen(){
ui.createMenu('CREDENZIALI')
.addItem('Imposta TOKEN', 'setToken')
.addToUi();
}
function setToken(){
var scriptValue = ui.prompt('Per favore inserisci il token.' , ui.ButtonSet.OK);
userProperties.setProperty(TOKEN_OLD, scriptValue.getResponseText());
}
And the second one does the business logic and implements a custom function that is meant to be used into the spreadsheet.
function getFromApi(book_id,dato) {...}
Obviously, this API is behind authentication and I don't want to hardcode a token into the script, so I've created the first UI in order to let the end-user manage it at runtime.
The UI works flawlessly but when I try to invoke the custom function, I get this error:
I am the owner of the files. What am I missing ?
Try to add SpreadsheetApp.getUi(); inside onOpen() and setToken() separately.
The following script works as standalone:
var userProperties = PropertiesService.getUserProperties();
const TOKEN_OLD = 'api.token_old';
function onOpen(){
SpreadsheetApp.getUi()
.createMenu('CREDENZIALI')
.addItem('Imposta TOKEN', 'setToken')
.addToUi();
}
function setToken(){
var ui = SpreadsheetApp.getUi();
var scriptValue = ui.prompt('Per favore inserisci il token.' , ui.ButtonSet.OK);
userProperties.setProperty(TOKEN_OLD, scriptValue.getResponseText());
}
However, you can not use a custom formula to call this function. See related articles:
Custom Functions in Google Sheets
Custom function throws a "You do not have the permission required to setValue" error

Google Sheets & Docs Script fails to create add-on menu when add-on is installed from Chrome store

Possible cause is the following:
Usually this is caused by a problem with the Authorization Lifecycle, specifically the opening stage.
The most common culprit is a global variable in the code that tries to access Google services without authorization, like:
var doc = DocumentApp.getActiveDocument();
See the documentation:
Warning: When your onOpen(e) function runs, the entire script is loaded and any global statements are executed. These statements execute under the same authorization mode as onOpen(e) and will fail if the mode prohibits them. This preventsonOpen(e) from running. If your published add-on fails to add its menu items, look in the browser's JavaScript console to see if an error was thrown, then examine your script to see whether the onOpen(e) function or global variables call services that aren't allowed in AuthMode.NONE.
Here is my script:
function onOpen(e) {
SpreadsheetApp.getUi().createAddonMenu()
.addItem('Browse Templates', 'browseTemplates')
.addToUi();
}
function onInstall(e) {
onOpen(e);
}
function browseTemplates(){
collectBasicData();
// Display a modal dialog box with custom HtmlService content.
var htmlOutput = HtmlService
.createTemplateFromFile("Gallery").evaluate()
.setWidth(700)
.setHeight(510);
SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Spreadsheet123 - Template Vault');
}
function collectAllData(){
var sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(DATA_SHEET);
DATA = sheet.getDataRange().getValues();
return DATA;
}
function collectBasicData(){
var sheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(PIVOT_SHEET);
var tabSheet = SpreadsheetApp.openById(SPREADSHEET_ID).getSheetByName(TAB_SHEET);
BASIC_DATA = {
"tab_about" : getValue(tabSheet,"B1"),
"tab_help": getValue(tabSheet,"B2"),
"pivot":sheet.getDataRange().getValues()
};
return false;
}
function getValue(sheet,addr){
return sheet.getRange(addr).getValue().toString().replace(/^\s+|\s+$/g, '');
}
function createACopy(id){
var docName = DocsList.getFileById(id).getName();
return DocsList.getFileById(id).makeCopy(docName).getUrl();
}
function insertInCurrent(id){
var destinationSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheets = SpreadsheetApp.openById(id).getSheets();
for(var i=0;i<sourceSheets.length;i++){
var sheetName = sourceSheets[i].getName();
var source = SpreadsheetApp.openById(id).getSheetByName(sheetName);
source.copyTo(destinationSpreadSheet).setName(sheetName);
}
}
Can you please help me a little or a lot.
Thanks in advance
OK, so my code was actually correct, but my mistake was that I should have saved any changes made to my code under the new version before publishing it to the store, which I did not and therefore all changes that I made were simply ignored.
function onOpen(e) {
SpreadsheetApp.getUi().createAddonMenu()
.addItem('Browse Templates', 'browseTemplates')
.addToUi();
}
function onInstall(e) {
onOpen(e);
}