Running a web app from a google sheet menu click - html

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.

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

Displaying a prompt and getting user input in Google Apps script bound to a Google Sheet

I have an Google sheet with some apps script code in it and I am trying to make it interactive by displaying a prompt and getting some user input. I have added a simple function to test that this works:
function displayPrompt() {
var ui = SpreadsheetApp.getUi();
var result = ui.prompt("Please enter a name for your report:");
Logger.log(result.getResponseText());
};
When I run it, I get the error:
"Exception: Cannot call SpreadsheetApp.getUi() from this context."
What am I doing wrong please?
Thanks Annette
If I run it using a trigger it works as soon as I open the file
function onOpen() {
var ui = SpreadsheetApp.getUi();
var result = ui.prompt("Please enter a name for your report:");
Logger.log(result.getResponseText());
}

Pushing Slack data to Google Sheets w/ Event Subscription

I'm trying to create a bot on Slack that sends the data of new messages sent to a private channel (that the bot is in) to a Google Sheet. I was successfully able to do this with data following a Slack slash command, by using this script:
function doPost(e) {
if (typeof e !== 'undefined') {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
sheet.getRange(1,1).setValue(JSON.stringify(e));
}
}
I tried using the same script with the Events API, but it needs to pass a request with a challenge parameter, and the endpoint must respond with the challenge value. Using the GScript web app's URL, I keep getting a failed response. How do I have the URL Verification Handshake work with Google Sheets and respond with the correct challenge string?
HTTP Post Fail
How about this modification?
The official document says as follows. This has already been mentioned in your question.
challenge: a randomly generated string produced by Slack. The point of this little game of cat and mouse is that you're going to respond to this request with a response body containing this value.
So please modify your script for returning the value of challenge from doPost as follows.
Modified script:
function doPost(e) {
if (typeof e !== 'undefined') {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
sheet.getRange(1,1).setValue(JSON.stringify(e));
}
var v = JSON.parse(e.postData.contents); // Added
return ContentService.createTextOutput(v.challenge); // Added
}
Note:
When you modified the script of Web Apps, please redeploy the Web Apps as new version. By this, the latest script is reflected to Web Apps. Please be careful this.
References:
Subscribing to event types
createTextOutput(content)
Added:
From your replying of I'm getting the same error., I thought that the latest script might not be reflected to Web Apps. And as a simple script, please copy and paste the following script instead of your script. And please redeploy the Web Apps as new version. Then, please test it again.
Sample script:
function doPost(e) {
var v = JSON.parse(e.postData.contents);
return ContentService.createTextOutput(v.challenge);
}

Calling Google Apps Script in another Project File

I am trying to call a Google Apps Script file that is in another project file following the sample here using UrlFetchApp.fetch.
I'm getting the same error that the original poster mentions but I am not having an success with my sample.
Did Google change something in the last 4 years that prevents me from calling the other script file?
See script below.
Below is the function that I am using to call the other project file
function makeRequest()
{
var webAppUrl = "https://script.google.com/macros/s/***/exec";
var auth = ScriptApp.getOAuthToken();
var header = { 'Authorization': 'Bearer ' + auth };
var options = { 'method':'post', 'headers':header };
var resp = UrlFetchApp.fetch(webAppUrl, options);
Logger.log(resp);
}
Below is the function that I am trying to call. Additionally, I have ran the authorizeDrive function and published as a webapp.
function authorizeDrive()
{
var forScope = DriveApp.getRootFolder();
}
function doPost()
{
var ss = SpreadsheetApp.openById('ssID');
var name = ss.getName();
Logger.log('called');
return ContentService.createTextOutput(name);
}
You want to run the Google Apps Script in the GAS project A by accessing to Web Apps from the GAS project B.
In your case, Web Apps is deployed by Who has access to the app: of Only myself or Anyone.
You want to access to Web Apps using the access token.
The GAS project A and B are in your Google Drive.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
I think that in your case, the scope is required to be added to the project including makeRequest(). So in order to add the scope for accessing to Web Apps using the access token, how about the following modification?
Modified script:
function makeRequest()
{
var webAppUrl = "https://script.google.com/macros/s/***/exec";
var auth = ScriptApp.getOAuthToken();
var header = { 'Authorization': 'Bearer ' + auth };
var options = { 'method':'post', 'headers':header };
var resp = UrlFetchApp.fetch(webAppUrl, options);
Logger.log(resp);
}
// DriveApp.getFiles() // This comment line is used for automatically detecting the scope.
Please add the // DriveApp.getFiles() of the comment line. This comment line is used for automatically detecting the scope.
In this case, https://www.googleapis.com/auth/drive.readonly is added to the scopes. If this didn't resolve your issue, please add the comment line of // DriveApp.createFile(blob). In this case, https://www.googleapis.com/auth/drive is added.
Note:
When the script of Web Apps side is modified, please redeploy it as new version. By this, the latest script is reflected to Web Apps. Please be careful this.
If the owner of GAS project of Web Apps is not your account which has the script of makeRequest(), at first, please share the GAS project file of Web Apps with your account. Then, please test it. This specification has added at April 11, 2018. Also, please be careful this.
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script
If I misunderstood your question and this was not the result you want, I apologize.

Authorization Lifecycle on published add-on is not working

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