Reputation: 75
I am sharing a set of Google Sheet documents with other users. I am the owner of all the spreadsheets and they are housed on my Google Drive. Every user has their own dedicated sheet. Users need to be able to run scripts on their sheet that collect and manipulate data from the sheet, which means the sheet needs to be unprotected while the scripts run. However, at the end end of the script, I want to protect the sheet again so that the user running the script is unable to edit the protected cells once the script is done running.
I am able to easily remove the protections from the sheet at the beginning of the script, but I am unable to protect the sheet again via the script without the user who is running the script being listed as an editor. I have tried using the "removeEditors" function to no avail (see below for basic example for one of the protected ranges).
var userEmail = Session.getActiveUser().getEmail();
var protection = newPickSheet.getRange('A1:M3').protect();
protection.removeEditor(userEmail);
For your reference, here is the code I'm using at the beginning of the script to remove all protections:
var protections = newPickSheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for(var i = 0; i < protections.length; i++){
protections[i].remove();
}
To summarize, I need my script to:
I was able to accomplish this very easily using VBA when deploying Excel Macros, but it seems this is not nearly as simple using App Scripts.
If anyone can help me figure out a solution, it would be greatly appreciated.
Upvotes: 2
Views: 3003
Reputation: 149
I did some modifications on Tanaike's answer, because of this error:
Exception: Request failed for https://script.google.com returned code 404. Truncated server response: <!DOCTYPE html><html lang="en"><head><meta name="description" content="Web word processing, presentations and spreadsheets"><meta name="viewport" c... (use muteHttpExceptions option to examine full response)
Just change these lines in main()
:
const options = {
headers: { Authorization: "Bearer " + ScriptApp.getOAuthToken() }
}
var url="https://script.google.com/URL/exec";
UrlFetchApp.fetch(url+"?key=removeprotect",options);
// do Something: Please put the script of "Execute the main part of the script" here.
SpreadsheetApp.flush(); // This is required to be here.
UrlFetchApp.fetch(url+"?key=addprotect",options);
It removed the error and now my codes works as expected!
To my understanding the main problem was &
in url , in this case we have to use ?
. Also ScriptApp.getService().getUrl()
has to be changed.
Upvotes: 0
Reputation: 201378
newPickSheet.getRange('A1:M3')
.If my understanding is correct, I think that the important point is who run each function. So how about this workaround? I think that there are several workarounds for your situation. So please think of this as just one of them.
Execute the main part of the script
includes the methods depending on user.By above points, the flow of this workaround is as follows.
1. Remove the protected range by owner using Web Apps.
2. Run the script of Execute the main part of the script
by each user.
3. Protect the range by owner using Web Apps.
Please run the following flow before you use the modified script.
main()
for the main function. If you are using other name, please modify it.#####
of var newPickSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("#####");
.In this modified script, I used main()
for the main function. If you are using other name, please modify it.
// This is the main function. Please set this function to the run button on Spreadsheet.
function main() {
// DriveApp.getFiles(); // This is a dummy method for detecting a scope by the script editor.
var url = ScriptApp.getService().getUrl() + "?access_token=" + ScriptApp.getOAuthToken();
UrlFetchApp.fetch(url + "&key=removeprotect"); // Remove protected range
// do Something: Please put the script of "Execute the main part of the script" here.
SpreadsheetApp.flush(); // This is required to be here.
UrlFetchApp.fetch(url + "&key=addprotect"); // Add protected range
}
function doGet(e) {
var newPickSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("#####"); // Please set here.
if (e.parameter.key == "removeprotect") {
// Remove protected range.
var protections = newPickSheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
protections[i].remove();
}
} else {
// Add protected range.
var ownersEmail = Session.getActiveUser().getEmail();
var protection = newPickSheet.getRange('A1:M3').protect();
var editors = protection.getEditors();
for (var i = 0; i < editors.length; i++) {
var email = editors[i].getEmail();
if (email != ownersEmail) protection.removeEditor(email);
}
}
return ContentService.createTextOutput("ok");
}
newPickSheet
. newPickSheet
is declared as var newPickSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("#####")
. If you want to modify this, please modify to your situation.Upvotes: 4