Session.getActiveUser().getEmail() results are inconsistent - google-apps-script

I am trying to create a google sheets custom menu based on the user email.
Code is as follows:
var AllowedReportRecipients = ["u1#gmail.com", "u2#gmail.com", "u3#gmail.com"];
var ReportRecipient = null;
function onOpen()
{
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('Custom');
menu.addItem('Edit', 'editHtm')
.addItem('History', 'historyHtm');
var usr = Session.getActiveUser().getEmail();
var isReportee = false;
for (var i=0;i<AllowedReportRecipients.length; i++)
if (AllowedReportRecipients[i] == usr)
{
ReportRecipient = usr;
isReportee = true;
}
if (isReportee)
menu.addItem('Request abc', 'sendABC');
menu.addToUi();
}
This is an unpublished sheet script. As others have reported the call to getActiveUser().getEmail() returns blank when the sheet is opened by the non-owner of the sheet. However, a call to getActiveUser().getEmail() executed at a later time correctly returns the logged in user email. For example, when called in historyHtm in response to the "History" menu item click it works. Why the difference? How do I properly load my menus?

The onOpen() function is a special reserved function, one of the [Simple Trigger][1] functions built into Google Apps Script. These functions run without requiring user authorization, so there are restrictions on what capabilities of the system they may access.
For your case, the important restriction is this:
They may or may not be able to determine the identity of the current user, depending on a [complex set of security restrictions][2].
ref
For users with consumer accounts or accounts that are not in the same Google Apps Domain as the developer, the onOpen() function will not be able to obtain the email address of the person running the script.
When you run other functions, for example those that are invoked via menu, they kick off the authorization cycle for the script, after which they are able to do more than the simple triggers.
That seems inconsistent - but is by design.
I think you need to rethink your user interface - I haven't been able to find a work-around that will produce the "privileged" portion of your menu upon opening the spreadsheet.
An installed onOpen trigger will have greater abilities than the simple trigger, but will run under the authority of the developer so it won't help your situation, as it will come up with your email, not the active user's.
Setting a timed trigger in the onOpen to update the menu seemed promising... except for the restriction that the timed trigger function has no access to the spreadsheet UI, of course.

Related

Add button to trigger script along top bar in google sheets

I have written the script below to hid all rows that have a specific box checked. I set a trigger using the clock and every 10 minutes but instead seems to run every time I check a box and it screws up the view every time I check it. I would like to change it to a manual trigger that is a button along the top bar that someone manually clicks. Can anyone help me edit it?
function onEdit(e) {
var s = SpreadsheetApp.getActive().getSheetByName('2 Week Snapshot');
s.showRows(1, s.getMaxRows());
s.getRange('C:C')
.getValues()
.forEach( function (r, i) {
if (r[0] == 1)
s.hideRows(i + 1);
});
}
As mentioned by I'-'I, the name given to your function causes your script to run when an edit is made to the sheet. From the Apps Script documentation on Simple Triggers:
To use a simple trigger, simply create a function that uses one of these reserved function names:
- onOpen(e) runs when a user opens a spreadsheet, document, presentation, or form that the user has permission to edit.
- onEdit(e) runs when a user changes a value in a spreadsheet.
- onInstall(e) runs when a user installs an add-on.
- doGet(e) runs when a user visits a web app or a program sends an HTTP GET request to a web app.
- doPost(e) runs when a program sends an HTTP POST request to a web app.
The e parameter in the function names above is an event object that is passed to the function. The object contains information about the context that caused the trigger to fire, but using it is optional.
Renaming your function to avoid binding this simple trigger will prevent edits of your sheet from triggering your function.
Documentation to look at:
Guide to Menus
Guide to Triggers

Error: no permission to append row

I have the following google script. Trying to append the results to row and I get this error
"You do not have permission to call appendRow (line 11)."
function webs() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var sheet = ss.getActiveSheet();
var url = "https://api.pipedrive.com/v1/mailbox/mailMessages/17685?include_body=1";
var token = "&api_token=token"
var response = UrlFetchApp.fetch(url+token);
var dataSet = JSON.parse(response.getContentText());
sheet.appendRow([dataSet.data.body]);
}
Anyway around this? if I can't append in google sheets, is there anyway to add results to a row?
I believe you need to use an Installable Trigger instead of using a Simple Trigger which have restrictions on what they can do.
See how to install it manually here:
From the script editor, choose Edit > Current project's triggers.
Click the link that says: No triggers set up. Click here to add one now.
Under Run, select the name of function you want to trigger.
Under Events, select either Time-driven or the Google App that the script is bound to (for example, From spreadsheet).
Select and configure the type of trigger you want to create (for example, an Hour timer that runs Every hour or an On open trigger).
Optionally, click Notifications to configure how and when you will be contacted by email if your triggered function fails.
Click Save.
Edit: I could also be restrictions on custom functions:
A custom function cannot affect cells other than those it returns a value to. In other words, a custom function cannot edit arbitrary cells, only the cells it is called from and their adjacent cells. To edit arbitrary cells, use a custom menu to run a function instead.
Edit: Other times you just need to authorize it first. Try going to Run > Run Function > then choose any function to run. Apps Script will pop-up with a authorization window for all the new scopes you are using.

onEdit trigger doesn't catch current user

I'm trying to build a simple log for sheets that makes use of cell notes.
Somehow i can't include the email of the user who triggers the onEdit-event.
function onEdit(e){
var email = Session.getActiveUser().getEmail();
var date = String(Utilities.formatDate(new Date(), 'Europe/Berlin', 'HH:mm dd/MM/yy'));
var range = e.range;
range.setNote(email + " # " + date);
}
The note appears on the cell but the email is empty. Could that have to do with missing permissions? I assume if something would be wrong with my code the note wouldn't appear at all on the edited cell in sheets...
Here's what Google documentation says about the Session class
The Session class provides access to session information, such as the
user's email address (in some circumstances) and language setting.
In regards to 'getActiveUser()' method, it states
If security policies do not allow access to the
user's identity, User.getEmail() returns a blank string. The
circumstances in which the email address is available vary: for
example, the user's email address is not available in any context that
allows a script to run without that user's authorization, like a
simple onOpen(e) or onEdit(e) trigger, a custom function in Google
Sheets, or a web app deployed to "execute as me" (that is, authorized
by the developer instead of the user). However, these restrictions
generally do not apply if the developer and the user belong to the
same G Suite domain.
Because you use the simple trigger - onEdit() - the code will not execute unless explicitly authorized by the user. For installable triggers, that would mean executing the function manually from the script editor.
You can publish the project as a sheets add-on. In this case, users will be asked to grant permissions declared in the add-on manifest.
More info https://developers.google.com/apps-script/reference/base/session

custom onEdit function that updates external sheet fails for other user, but only when using inputBox

I'm at a loss to explain the cause. I have a small Google sheet which I copied to my wife to allow her to use. Her version has scripting to update my sheet (if it detects a missing value).
I wrote a custom onEdit() function which is called via Installable Triggers. I have confirmed she can edit my sheet: by opening it and hand editing, manually running the script, or by commenting out the inputBox and replacing it with a static value.
The update does occur if:
* She manually triggers the custom_onEdit function from the code -> run menu
* I modify the code to comment out the inputBox and use a static value
Simplified code:
function custom_onEdit(){
var sheet = SpreadsheetApp.getActiveSheet(),
range = sheet.getActiveRange(),
col = range.getColumn(),
row = range.getRow(),
value = range.getValue();
if (value != "" && sheet.getRange(row,col+1).getValue() === ""){
Dialog(value);
}
}
function Dialog(v){
var sheet = SpreadsheetApp.getActiveSheet(),
result;
result = Browser.inputBox('Populate the value required',Browser.Buttons.OK_CANCEL);
if (result != 'cancel'){
UpdateExternalSS(result,sheet.getName());
}
}
function UpdateExternalSS(value, name){
sheet = SpreadsheetApp.openById('abcd1234').getSheetByName(name);
sheet.getRange('A1').setValue(value);
}
If I comment out the call to Browser.inputBox and add:
//var result = Browser.inputBox('Populate the value required',Browser.Buttons.OK_CANCEL);
var result = '9999';
It works fine.
(edit) - More reading - is seems the Installable Trigger I setup actually runs as my account, so there should be zero reason why it's not running (I am the owner of both spreadsheets)...
Installable triggers always run under the account of the person who created them. For example, if you create an installable open trigger, it will run when your colleague opens the document (if your colleague has edit access), but it will run as your account.
This should be an update to the above answers. I created and onEdit script for my spreadsheet using Browser.msgBox calls before I knew that it shouldn't work. They work correctly for both simple comments and for seeking answers to yes-no questions. It fails when using Browser.inputBox calls. That is when I found the above answers. In that case, the script simply quits when it encounters the inputBox call. I tested the script sharing the spreadsheet with another user and found that the msgBox calls still work fine unlike the reports in previous answers. It is just the inputBox calls that do not.
This is an old bug in Google Apps Script.
First reported in 2012: Installable on edit triggered function fails to continue after msgbox for other users.
Then reported here on Stack Overflow: Shared spreadsheet, trigger set by one user, msgBox causes script to fail?
Reported to Google in 2013 again, and closed as a duplicate.
Workaround
Since we can't use Browser methods in triggered scripts intended for other users, an alternative is to indicate that they should enter certain values in certain cells of a spreadsheet, and get those with an on-edit trigger.
As an aside, I suggest using event objects in scripts run by a trigger, which provide the active range and entered value directly to the script.

onedit why cannot send email?

i've this simple script that should send an email when a cell is changed
function onEdit(e) {
var doc = e.source;
var r = doc.getActiveRange().getValue();
if (r == "Niccolò"){
var a = doc.getActiveRange().setBackground('#ff0000');
var b = GmailApp.sendEmail('name#gmail.com', 'subject', 'body');
}
}
This function change also cell colour.
THe problem is that the cell colour works, so it's change while doesn't send any email.
It looks so simple i don't understand why doesn't works!
Simple triggers like onEdit(), onOpen() or onFormSubmit() have a limited set of possible actions because they run without authorization , see the documentation for further details.
So this behavior you describe is normal.
You should use an installable trigger instead as explained in the same doc page.
here is an summary of the documentation :
These simple triggers run in response to actions in Google Spreadsheets, and they run as the active user. For example, if Bob opens the Spreadsheet, then the onOpen function runs as Bob, irrespective of who added the script to the Spreadsheet. For this reason, the simple triggers are restricted in what they are permitted to do:
They cannot execute when the Spreadsheet is opened in read-only mode.
They cannot determine the current user.
They cannot access any services that require authentication as that user. For example, the Google Translate service is anonymous and can be accessed by the simple triggers. Google Calendar, Gmail, and Sites are not anonymous and the simple triggers cannot access those services.
They can only modify the current Spreadsheet. Access to other Spreadsheets is forbidden.
For more information on event permissions, see Executing from a Container-Specific Trigger.