Make spreadsheet only editable through script - google-apps-script

I have a script which adds new rows and changes the sheet in some ways.
I'd like to lock this sheet so it cannot be edited manually, but allow the script to be run.
Is there a way to do this?

Yes, it's not the most easier thing to do, but it's possible.
But before we start it's important to understand how Google spreadsheet/sheet protection works.
There's no way to protect a sheet or range from the file owner. So, if you also want to protect a file from yourself (assuming you're the owner). Then the only solution available now (I do hope they change this in the future) is to change the ownership of the file to another account. What most people do is use another Google account that they don't use actively (you can create a bogus easily if you don't already have one).
Then, after you have transferred the file to another account, you can easily lock changes to ranges, sheets or the whole spreadsheet using the regular GUI.
Ok, now to the script. When a script runs, it's always using the authorization of a specific account, and it can do everything that this account can. For example, when someone runs a script directly from the script editor, or clicking on a custom menu or image: it runs under the account of who's clicking. But if you set a installable trigger, then the script always runs under the account of who setup the trigger in the first place (not who's performing the action that actually triggers it). Simple event triggers run as who's triggering the action (you can think anonymously), but they can't do much, it's a security feature (read the link for a better understanding).
Lastly, when one is publishing a script as a web-app, then there's a selection box to choose if the script runs as the developer or the user. Very simple.
Back to the problem. Since we have locked out everybody from the desired sheet/range. For a script to make changes to this locked area, it must run as the file owner!
If the changes you do are automatic, e.g. via a installable trigger, then you're good. Just setup the trigger using the file owner account and that's it. Also, if your users are accessing the script "externally", that is, via a web-app. Then that's easy to, just setup the web-app to run as the developer (the file owner).
The most complicated scenario is if you need to run the script from a custom menu, which will then run under the privileges of who's clicking on it, which themselves can not make changes to the protected area. The solution to this is to deploy the script as web-app running as the developer, and have the function running from the button click to call the deployed url using UrlFetch, possibly passing some parameters to designate what needs to be done. Then, since the webapp runs as the developer (which is the file owner), it can make any changes required, and return (if there's something to return) any value (usually a JSON) to the calling function (which is running as the user and is associated with his session), so you can show him a message on a popup or toaster, etc.
It's kind of tricky but works great, and you can do all that on the same script contained in the spreadsheet. But if you're concerned that your users may access the script editor and change the code (which is possible), than you should separate the web-app part on a different file, that you don't need to share with them.

Yes but only for others not for the script owner. Just use 2 accounts one as the owner and the other one as the reader.

Related

Scripts are not executing for users with reader permission

I have added an image on my grid, and assign script to it. But script executes only when I click on image, and when another user(with reader permission) clicks on image nothing happens. The same situation is with onOpen() trigger - nothing happens when user whith reader permission opens the grid. I understand that editor permission will fix it, but I don't need the user to be able to edit the table, I only need that user be able click buttons(image)/get alive triggers/menus that i create, but not edit anything manually. How can i do this(may be i should give some extended reader permission, or to turn on something in GAS project)?
When users execute a script for the first time, they will get an allow permissions prompt, so they can authorize the script to make changes on their behalf.
However, if the user has viewing permissions over the sheet or file, they cannot authorize the script to run or make changes on their behalf since they cannot make changes to the file. (I found a similar question, with the difference that the sheet was embedded in a website that has some information about why it does work here).
And it's documented in the Apps Script documentation here:
An installable open trigger runs when a user opens a spreadsheet, document, or form that they have permission to edit.
You can also request a feature request to Google asking for an option to allow users with "viewing permissions" to run scripts here.
In this case I think you may give editor's permissions but protect the sheet/range so only you can edit them with this option -->
https://support.google.com/docs/answer/1218656?hl=en&co=GENIE.Platform%3DDesktop#zippy=%2Cprotect-a-range-or-sheet
Let me know if this worked!
Option 2:
Adding to those protected ranges you can too create a Library with your functions in another spreadsheet (or in Google App Script independently) -> read about it here
You can now set buttons/menus associated with those original functions, but I think that this can give you an altenative
For example:
function function1_toOrigin() {
LibraryName.function1()
}
function function2_toOrigin() {
LibraryName.function2()
}
Yes, they'll be able to access to these linking functions but nothing more, I think they won't be that unreliable??
IMPORTANT: If there are modifications to the script you should deploy them again as a new version of the library and update the version in your spreadsheet by double-clicking in your library

How to avoid saving a google sheet and have multiple people editing at the same time?

I’ve created a Google Sheet – kind of like an app – using script. It’s a number of blank cells where once added some information, it creates a string with that information in the right order. I created this to help some colleagues. We are using free accounts.
I face 2 problems:
The app is supposed to be used by only one person at a time, but I’m sure at some point two or more people will want to use it at the same time. Is there a way to allow this without they interfering with each other? I’ve read you can share a link that creates copies of your doc, but that wouldn’t work in this case because I intend to keep updating it regularly.
The changes people make to the sheet will stay there. Right now I have a onOpen function that just rewrites everything, but if someone accesses the document while someone is using it they’ll rewrite everything and ruin their work.
Any ideas on how to solve these two problems? Thank you so much in advance!
I think that you have to find another way to implement your "app" because Google Sheets not a good tool for limiting that only one user edit a spreadsheet a time, but if for any reason you decide to keep with it,...
... you need to implement a workflow like the following
Save the active user email on PropertiesService.getUserProperties().
This should be done by each user by running a script themselves. The most user-friendly will be by using a macro, custom menu or button (a drawing with an assigned Google Apps Script function). You might use an open installable trigger to validate that the active user have already done this.
You might have to make the function that clears the data a "smart" function.
You might have to consider additional cases, like if the owner of the spreadsheet opens it when there is an editor working on the spreadsheet.
Use installable triggers to manage the sharing settings.
Use an open trigger to remove all the editors except the active user
Use a time-driven trigger to add again the editors. To make this work effectively should define how the time-driven trigger will know that the last editor have finished their session, i.e. you might use DriveApp.getFileById(SpreadsheetApp.getActiveSpreadsheet().getId()).getLastUpdated()
The above should help you with both problems, as long you as the owner do not open the spreadsheet as is used by someone else.
Other alternatives that might work better is to create an add-on or a web application.
Related
Determine current user in Apps Script
Last modified date in Google App Script GAS sheets

Can I create a shortcut to execute a Google Apps script?

I have a script that runs on a Google Sheets that is fed by a Forms entry. Basically, when I fill out a form, it creates an entry on the sheet. From that entry, a new document is created by my script that "prettifies" the fields on the sheet for distribution.
This sheet is located on a Team Drive, but in order to have the resulting document created in my drive, I had to place the unbounded script in my drive and reference the sheet. If I have it bounded to the sheet, it will always put the newly created document in the Team Drive -- which I don't want.
When it was bounded to the sheet, I had a trigger that would automatically create the document when the form was submitted. Now that the script is on my drive, triggering on submission is not an option. The only options I have are time based or calendar based, and neither of these really work -- unless I only want to get the document once a month or every single minute.
So now, the only way I know to execute the script is to do it manually every time, which is a major hassle and requires multiple steps no matter how you go about it.
Is there a way to trigger this script on command without having to open the Script editor, click the script I want, and then click run?
Why are there no keyboard shortcuts in Apps? I know about Ctrl+R -- but this only works if you already have the script you want highlighted in the top action bar. If I type Ctrl+R without it already highlighted, nothing happens. Nothing happens with Alt+R or Alt anything, really. I have tried simply tabbing 187 times to get to where I need, but the tab never seems to focus "in" the script menu area. It just bounces around the address bar, the shortcuts bar, etc.
NOTE: I do not want to make major changes to THIS script. It took forever to get this working right and I don't want to jack it up. I just want to be able to trigger it without having to go through 18 steps to do so.
There is no way to execute a standalone script project's function with a keyboard shortcut from within the Apps Script Editor. If your script was bound, you would have the option of keyboard shortcuts from the container Google Sheets file (as a google-sheets-macro), but macros have some restrictions.
However, you are not without options. Two of them:
Publish the script project as a webapp and use a page visit as the trigger.
Open the page / click a bookmark -> execute the function via your doGet().
Convert your script to a 'polling' style that processes any number of form responses, and use a time-based trigger (e.g. hourly, daily) to automate the whole process.
(Include a "did I process this response yet" flag to prevent reprocessing a response)
There are more elaborate configurations (e.g. Apps Script API + local cron job) but those are unlikely to be simpler than the above two options.
As I mentioned in my comment, you more than likely just needed an extra step for the original bound script to create the file in your Google Drive and not the host Team Drive. If you're interested in that avenue, you'll want to ask the appropriate (read: new) question.
This is a workaround not an answer.
I use the Alt/ menu to efficiently look up functions by name (For me, its faster than using a cursor to work thru the nest of menus). If you design your function names so they differ from the built-in function names, the lookup may take only a few keystrokes)

How to allow to run google script on a protected sheet (in a spreadsheet) [Can't use trigger and web app]

I'm coding a script for a spreadsheet. This script creates a menu.
Then by choosing an option in this menu a function (which uses API) will run in order to filter some columns and hide others.
The problem is:
This sheet is protected (because shared with coworkers) but I want to allow people to run the script, which is impossible without the permission.
I already looked at different solutions:
Using a trigger: Doesn't work because a trigger can't correctly call a function which uses API (yes, my functions use API).
Web App: When the script is run from the spreadsheet, the script is run as the current user, not the script editor. (the web app is efficient if the user uses the HTML page.)
Remove protection -> run the function -> Re-add protection: Can't modify the protection without permission, which is logical.
Add the current user in the list editor -> run the function -> Remove the current user from the list editor: Can't modify the editor list without permission, which is logical.
How can I solve this problem?
This is a pain that I have not seen a good workaround. Google should know that in a collaborative environment that the owner would create script and want users to be able to run those scripts while at the same time not messing with formulas or cells that you desire to protect. The only way I have found to solve this on the sheet itself is to Unprotect and then Protect the cell or range you are making modifications to during the script run. Do be mindful that if the script fails in the middle (after you have unprotected it) the cell remain unprotected. Might want to run within a "try" script.
Are you the spreadsheet owner?
If no, you are not authorized to bound an apps script on it.
But you can make a copy of the spreadsheet by duplicate it and save in your drive.
If the spreadsheet is created by you yourself, maybe you created it by another username. If it does, log in by that user and change the sharing option to allow the specific user can edit it.

Access - Scripts Bound to Google Sheets

From the documentation of the the bound script:
https://developers.google.com/apps-script/guides/bound
"Only users who have permission to edit a spreadsheet, document, or form can run its bound script. Collaborators who have only view access cannot open the script editor, although if they make a copy of the parent file, they become the owner of the copy and will be able to see and run a copy of the script."
This feature is kinda limited. I have created a big sheet that are used by multiple users. I need the script to be executable by Read Only access users. The script that I created are not making changes to the document, so it should not affect by the access level of the users.
Administrator have Edit access to the document. They have access to all calculation/ configuration cells/ sheet.
Managers have Edit access to the document. Managers have Edit access to most of the cells/ sheet. Managers task is to update the cells
All remaining users only have Read Only access to the document. They can view cells and the automated calculation.
Because the cells have too many columns, I have created a button (eventually I want to move it to onOpen) for easy navigation to a specific cell. This is done dynamically based on today's date.
This is working fine as expected for Administrator and Manager (have Edit access), however not available for the rest of the users with Read Only access.
Is there any workaround for this?
Thanks
Unfortunately not. You are the edge case. The whole point of GAS is to make editing easier, providing tools. A Google document/Spreadsheet/etc. normally isn't THAT hard to maneuver through.
However, if your REALLY want viewers to see specific parts of your spreadsheet, but not edit it, you could try making a standalone script. Have it pull data from the spreadsheet using the spreadsheet's id and then project it on the HTML page, in a table or list.
I Agree with EvSunWood, though I would go about the task in a slightly different way. You could give read only access to the main sheet to the user. And then give them full access to a separate sheet with code attached which onOpen updates itself from the original with all of the latest data and then navigates to the appropriate row.
I agree too with this answer, it's not possible to allow view only users to execute scripts, but contrary to using an script to overwrite edited data, I suggest you use sheets/range protection this way we reduce risks like a failure on the script by on open trigger due to "change collisions" caused by several users opening the same file at almost the same time.