I've been trying to get some custom validations and access checks done in spreadsheets,
based on the groups the users belong to.
As far as I know, the following trigger bound to a container(a spreadsheet) should have the rights of the user accessing the spreadsheet:
function onEdit(event) {
var groups = GroupsApp.getGroups();
Logger.log(groups);
}
Still, it runs into an error: "Execution failed: You do not have permission to call getGroups".
The same function called from a standalone script file(in theory the same access) will see the groups of the user.
My questions are:
Am I doing something wrong?
If not, is there a way to access the groups of a user from a spreadsheet event?
Probably not relevant, but using Windows 8 and Chrome 30.0.1599.101 m.
Zig Mandel's answer is correct as simple events like onEdit are unable to call methods that require authorization,however you were trying to get the user's group and that will be a problem since installable triggers run under the authority of the author of the script (in fact the person that set up the trigger which is usually the script author) which means not the user's group but yours...
So I'm afraid what you are trying to do won't be possible because in contradiction with the privacy rules in spreadsheet scripts.(read the doc that Zig refers to in his answer)
The only way to access the user's group information is using a direct function call in a menu or using a button that will ask for authorization., no automation in there ...
If you were to read onEdit documentation it says that you cant call methods that require authentication. Install the trigger with a different name instead of using the simple trigger.
Related
When I call Session.getActiveUser() from a function called by an installable trigger (e.g. an OnOpen Event trigger in Google Sheets - but not the Simple Trigger) in Apps Script, what user information am I getting?
I understand that installable triggers run under the owner/creator of the trigger regardless of who has opened the sheet. So would this always return that person's info?
Either way, how do I get the information of the other person? (e.g. if it gives owner info, how do I get the info of the user actually opening it - and vice-versa)
Update:
I got another user to test my script. I watched the logs while they were in the file, and it definitely reported THEM as the user, even when the installable OnOpen trigger was triggered.
This is good from the perspective that it showed them the correct menu options - he and I saw different menus per my OnOpen script, which is what I want.
However, this raises two issues for me:
This seems to go against the Google Documentation, which states: "Installable triggers always run under the account of the person who created them. For example, if you create an installable open trigger, it runs when your colleague opens the document (if your colleague has edit access), but it runs as your account. This means that if you create a trigger to send an email when a document is opened, the email is always sent from your account, not necessarily the account that opened the document."
In a future function, I will be calling an API from another App. This API will need my credentials (API ID and Secret). I was hoping / expecting that I could "sandbox" my credentials in an installable trigger - invisible to other users - that will allow them to use my credentials just for the specific functions which I would script into the API. If the installable trigger is in fact, NOT using my credentials, then how can I do this? I don't want to have to make every user go to the other App and generate their own set of API credentials, that will be unsustainable in this organization, and not everyone should need to do that.
It should return whomever triggered the script. But it depends if the security policy does allow you to access the user's identity. Seeing the documentation:
Gets information about the current user. 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).
I have tested it and even an installable trigger won't return anything if it belongs to a different organization.
But you might be able to if other users belong to the same organization.
However, these restrictions generally do not apply if the developer runs the script themselves or belongs to the same Google Workspace domain as the user.
Workaround:
One thing I guess would be to assign the triggered function into a button and have the users click that upon opening the sheet. Via clicking the button, I have been able to show the User object using that method.
Or a webapp that will serve as a relay and will get the User details.
i wrote code for getting all viewers of spreadsheet in app script .
i have used getViewers() method to get viewers names who actually viewed it. but that method is returning me the names of people to whom i actually shared the spreadsheet....
is there any other way that i can get all viewers of spreadsheet.?
is there any web automation tools that can solve my problem?
Answer:
It is not possible to get a list of people that have opened your a Google Drive file using Google Apps Script - a method that returns this list does not exist. The getViewers() method returns the list of people with view and comment permissions for a file, while getEditors() retrieves the list of people that have edit permissions.
The Issue:
is there any other way that i can get all viewers of spreadsheet.? is there any web automation tools that can solve my problem?
There is no way of getting viewers of a Google Sheet as this is a huge security issue. This information is not stored and is therefore not retrievable.
Workaround:
You can make a custom function which stores the username of a person when they open the file - though be aware that triggers have restrictions and will only run if the person opening the file has edit access. I have included a list of Apps Script Trigger Restrictions below for you to look through and decide what is the best approach for you.
Code:
function onOpen(e) {
var user = e.user.getEmail();
// do some code to store or save this parameter
// for example save it to a hidden sheet or email it to yourself
// though an email would require an installable trigger to be made
}
Simple Trigger Restrictions:
These are not all of the restrictions (full restrictions are available here), but these are the ones that I believe to be most relevant for you.
As per the Google Apps Script Simple Triggers documentation:
They do not run if a file is opened in read-only (view or comment) mode.
They cannot access services that require authorization. For example, a simple trigger cannot send an email because the Gmail service requires authorization, but a simple trigger can translate a phrase with the Language service, which is anonymous.
They can modify the file they are bound to, but cannot access other files because that would require authorization.
They may or may not be able to determine the identity of the current user, depending on a complex set of security restrictions.
This last point is important - getting information about the current user is possible depending on the security policies of the the G Suite domain. A detailed explanation of this can be found in the getActiveUser() method documentation:
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 runs the script themselves or belongs to the same G Suite domain as the user.
There are big security issues with getting a list of people that have viewed a file, for good reason, and so what you are looking to do it highly restricted by Google.
References:
Class File of Google Apps Script
getViewers() method of Class File
getEditors() method of Class File
Simple Triggers
onOpen(e) Trigger
Simple Trigger Restrictions
Installable Triggers
Event objects
Class User of Apps Script
User.getEmail() method
Class Session
getActiveUser() method of Session Class
I am building an Google Apps Script add-on for Google Spreadsheets.
In the manifest I have explicitly requested the following scopes:
"https://www.googleapis.com/auth/script.container.ui",
"https://www.googleapis.com/auth/spreadsheets"
Also the "OAuth consent screen" within my Google Cloud project has the same scopes and these are already verified by Google.
Nevertheless it is not possible for me to give feedback to my users in case of a wrong input. I have tried the following:
SpreadsheetApp.getActiveSpreadsheet().show(htmlApp);
SpreadsheetApp.getActiveSpreadsheet().toast(message);
SpreadsheetApp.getUi().alert('Wrong input.');
SpreadsheetApp.getUi().showSidebar(html);
Browser.msgBox('Wrong input.');
Nothings seems to work, I always see the error "Authorisation is required to perform that action" within the stackdriver logs.
What would work is to create an "error sheet" and log all input errors into it, or to make one cell within the main sheet to an "error cell" and log all input errors into it. I think this is not a good solution in terms of user experience.
It seems that this problem has something to do with the authMode: https://developers.google.com/gsuite/add-ons/concepts/editor-auth-lifecycle#authorization_modes
Because "Access to user interface" is only possible within "FULL" authMode, which is not the case during onEdit().
The strange thing is, that other add-ons are able to show an alert/popup. Is this a hack? Or do I need more scopes? Or do I have to change anything else?
EDIT 08.10.2019:
#Jacques-Guzel Heron:
For instance: the user inputs a date in cell A1 and another in cell B1. Within the onEdit(e) trigger I want to check if the date in B1 is after the date in A1, if not I want to alert the user. All the above listed methods lead to the error "Authorisation is required to perform that action", when the app is published. When the app is not published .toast(), .alert() and .msgBox() work within my test environment. The strange thing is, that these methods then create a DIV-element, whereas the other add-ons create an IFRAME-element for their alert/dialog-box. Therefore I think they use another method and it has nothing to do with scopes. In addiation I had a look during the OAuth verification process of these add-ons and the scopes are listed within the dev-tools. They do not use any special "ui-scope", so I doubt the cause for this error is scope related.
EDIT 09.10.2019:
Now I know how an alert/dialog-box containing of an IFRAME-element can be made. To do this, these methods can be used:
var htmlString, msg, htmlOutput;
htmlString = '<p>my html string</p>';
msg = 'my message';
htmlOutput = HtmlService
.createHtmlOutput(htmlString)
.setSandboxMode(HtmlService.SandboxMode.IFRAME)
.setHeight(140);
SpreadsheetApp
.getUi()
.showModalDialog(htmlOutput, msg);
But it is also not possible to call this method during onEdit(e).
All the above listed methods can be called, through clicking on the menu items and also through clicking on buttons within the sidebar, but not during onEdit(e).
In addition I have added all the scopes which other add-ons are using, but in vain. So again my assumption got confirmed that the problem is not scope related.
I have the impression that some smart people have managed to find an inofficial workaroung, please let me know :)
You are right on all your approach. And yes, this is intended behavior as documented on authorization modes.
Those add-ons use custom menus to use a formula that checks the cell after being called pressing a button.
On that documentation you can find information to develop your alert. Please describe what you are trying to accomplish so I can help you better, otherwise ask me for more clarification without hesitating.
The solution are installable triggers: https://developers.google.com/apps-script/guides/triggers/installable
They are running in FULL authMode and therefore are allowed to access the user interface: https://developers.google.com/gsuite/add-ons/concepts/editor-auth-lifecycle#authorization_modes
I've published a Google Apps Script standalone spreadsheet add-on, while I met some problem using PropertiesService.getUserProperties() in a custom function.
If User A has installed the add-on and saved some data in the user property.
Then User A shared the spreadsheet to User B. When user B run the custom function, he can get the saved data in user property for user A. This is not what I suppose user Property works. Both User A and B should get their own saved data.
So what is the active user for a shared spreadsheet? I don't want all the spreadsheet viewers to get the saved data for the spreadsheet creator. Is there anything I'm doing wrong in code or "Cloud Platform project" option?
In other words, how can I get different data saved in user properties for different viewers in a shared spreadsheet?
I tried to get the active user email in a custom function, but it does not work.
Please note, I can't use Session.getActiveUser in the custom function, because Google Apps Script Custom function does not support Session service. It will get an invalid permission exception.
https://developers.google.com/apps-script/guides/sheets/functions#Advanced
Thanks,
After writing tons of code to test different scenarios, I believe it has no way to solve the above problem.
So I will use a workaround to achieve the goal. In case someone also run into the trouble. I will put down my test results here.
If Google account A shared spreadsheet to Google account B.
In custom function, they all get A's user property.
From a webpage, call into server function via script.run, both A and B can
get their own user property.
Custom functions can't access PropertiesServices.userProperties() (maybe the exception is the spreadsheet owner).
According to https://developers.google.com/apps-script/guides/sheets/functions
Unlike most other types of Apps Scripts, custom functions never ask users to authorize access to personal data. Consequently, they can only call services that do not have access to personal data, specifically the following:
While Properties is included on the list and there isn't any note for this service, since the custom function doesn't ask users to authorize to access personal data it should not return PropertiesServices.userProperties() as it potentially store user personal data.
I am attempting to call Session.getActiveUser in order to auto-fill certain fields in a Google Sheets document when other fields are edited. All users are in the same domain; however, I receive an error message, "You do not have permission to call getActiveUser." I was under the impression from existing documentation that users within the same domain can access one another's information through custom scripts - is this incorrect? If so, I know that there are several workarounds, but if not, is there something else I could be doing wrong?
Thanks in advance!
"user3889423" is correct, you need Authorization of the user, in order to call the getActiveUser().
You can find this information in this link below:
https://developers.google.com/apps-script/guides/sheets/functions#advanced
The link in KRR's answer contains the information you need. Here's the excerpt answering you question:
You definitely cannot call Session.getActiveUser() without user authorization, even for users within the same domain:
If your custom function throws the error message You do not have permission to call X service., the service requires user authorization and thus cannot be used in a custom function.
However, even with user authorization, you still cannot use Session.getActiveUser() in custom functions (directly in cells). You need to create a custom menu instead:
To use a service other than those listed above, create a custom menu that runs an Apps Script function instead of writing a custom function. A function that is triggered from a menu will ask the user for authorization if necessary and can consequently use all Apps Script services.
If that script runs without the explicit authorization of the user, you won't be able to get the ActiveUser (I think). It should work though when a user authorizes the script first.