I am trying to implement a script that locks a certain range of cells when a condition is true. Here is the link to my document:
https://docs.google.com/spreadsheets/d/1XShGxlz2fA2w2omth-TvYc7cK0nXvVMrhwRKafzVjOA/edit?usp=sharing
Basically I am sharing this document with a group of people so they fill their mail addresses in column B and put a number 1 in column C so it increments my counters for each slot. What I am trying to do is to lock each slot when it is full so other people can no more edit these slots but the problem is with my if statement if (cell1 == 10). The range is always locked even if the if condition is not realized. Here is my code :
function onOpen() {
var ss = SpreadsheetApp.getActive();
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var cell=60;
var cell1 = source.getRange("G2").getValue();
if (cell1 == 10){
// Protect range B2:B11, then remove all other users from the list of editors.
var ss = SpreadsheetApp.getActive();
var range = ss.getRange('B2:B11');
var protection = range.protect().setDescription('Sample protected range');
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script will throw an exception upon removing the group.
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
}
As Andy says in the comments, you need to explicitly remove the protection if cell G2 does not equal 10. (This code removes all protections).
Reading the Protection Class page, where you got the snippets from, I couldn't get a handle on the way editor privileges would factor into your needs, so this script will work if others are editors. If you don't want them to be editors, you'll have to add the relevant code.
function onOpen() {
var ss = SpreadsheetApp.getActive();
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var cell = source.getRange("G2").getValue();
var range = ss.getRange('B2:B11');
if (cell == 10) {
// Protect range B2:B11 if cell 'G2' = 10
var protection = range.protect().setDescription('Sample protected range');
Logger.log
} else {
// Remove protection if cell 'G2' is anything other than 10
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
protection.remove();
}
}
}
Related
I am trying to protect a range through google apps script in my google sheet. Whenever the data point in column O is checked i.e. value is yes. I would like that row be protected.
Secondly, I have prior protected columns E:H and M:N, which should stay protected.
There are around 1000 rows, 10-15 new rows that need to be protected daily. By the code I have currently written, it removes the protection and then re-adds it, which takes a lot of time. If I remove the part where it removes the rights then it still re-adds the same protection regardless.
Is there anyway to check if the cell is protected, if protected move onto the next row?
Secondly, I'm unable to provide access to the other emails i.e. "add editors"
function removecompleted(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var purchased = ss.getSheetByName("Purchased Inventory")
last_row_purchased = purchased.getLastRow()
var emails = [
'user#domain.com'
];
var protections = purchased.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.canEdit()) {
protection.remove();
}
}
for(var i = 1; i < last_row_purchased; i++) {
if(purchased.getRange(i, 15).getValue() == "Yes")
{
target_range = purchased.getRange(i, 1, 1, 15)
protection = target_range.protect().setDescription('Sample protected range');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors())
protection.addEditors(emails);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
}
var range = purchased.getRange('E:H');
var protection = range.protect().setDescription('Always Protected');
var range = purchased.getRange('M:N');
var protection = range.protect().setDescription('Always Protected');
}
You can do this on edit, but rather than checking to see if the cell is protected (which is not that much faster than just setting the protection anyway) you can just check the row of each protected range and remove the protection if its row is equal to the row of the cell that was just unticked:
function onEdit(e) {
// List of sheet names the function should run on
const sheets = ["Sheet1", "Sheet2", "Sheet3", "etc"]
const sheet = e.source.getActiveSheet()
// if current sheet is not in permitted sheets, return
if (!~sheets.indexOf(sheet.getName())) {
return
}
const row = e.range.getRow()
if (e.range.getColumn() === 15) {
const ss = e.source
if (e.value === "TRUE") {
range = sheet.getRange(`${row}:${row}`)
const me = Session.getEffectiveUser().getEmail()
const protection = range.protect()
protection.getEditors().forEach(user => {
protection.removeEditor(user.getEmail())
})
protection.addEditor(me)
}
else {
const protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE)
protections.forEach(function(p) {
if (p.getRange().getRow() === row) {
if (row === 1 && p.getRange().getColumn() !== 1) return
p.remove()
}
})
}
}
}
Code Rundown:
Get the row number of the edited range
Check if the edited cell was column 15
If the value of the cell is "TRUE", protect the row, and remove all editors aside yourself.
If the value of the cell is "FALSE", then get all the sheet's protections, check the value of their row, and if the row matches the edited cell's row, then remove that protection
NB : The final check also has a condition to check if the column is not equal to 1 so to not remove the protections on E:H or M:N.
References:
Class Protection
Class: Sheet
Class: Range
Making a self-scheduling spreadsheet for my co-workers. The goal is for them to put their hours (12 or 6) in the cell that corresponds with the date and their name. I am trying to have it so that a date column will lockout after the sum cell for that column reaches a certain total.
I am using this (Google Script Lock Cells) as my basis but I am not having much luck.
function myFunction() {
function onOpen() {
var ss = SpreadsheetApp.getActive();
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var cell = source.getRange("B12").getValue();
var range = ss.getRange("B2:B11");
if (cell == 10) {
// Protect range B2:B11 if cell 'B12' = 10
var protection = range.protect().setDescription('Sample protected range');
Logger.log
} else {
// Remove protection if cell 'B12' is anything other than 10
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
protection.remove();
}
}
}
}
I am also looking to have the sum represent shits rather than hours so if a person wrote "12" the sum column would record "1"
Any help would be amazing.
You should change several things
Do not nest onOpen inside myFunction - it will not work
If you want the protections to be update on every update of B12 - you should use the onEdit trigger instead of onOpen
It is better to replace cell == 10 through cell >= 10 to account for the possibility that the value accidentally trespasses the maximum
4.It is not enough to create a protection, to make it useful you need to remove editors from it
Only the owner of the script (you) should maintain access
For this, use an installable trigger instead of a simple one, to make sure that it runs always as you and not the user that opens the document
Sample (to be bound to an installable onEdit trigger):
function bindAnOnEditTiggerToMe() {
var ss = SpreadsheetApp.getActive();
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var cell = source.getRange("B12").getValue();
var range = ss.getRange("B2:B11");
if (cell >= 10) {
// Protect range B2:B11 if cell 'B12' = 10
var protection = range.protect().setDescription('Sample protected range');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
} else {
// Remove protection if cell 'B12' is anything other than 10
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
protection.remove();
}
}
}
I'm currently using Google Sheets as a way for people to sign up for certain time shifts. I'm using the following script to automatically protect cells after data entry so that people can't discretely erase their signups without notifying me:
function onEdit(e) {
var range = e.range;
var timeZone = Session.getScriptTimeZone();
var stringDate = Utilities.formatDate(new Date(), timeZone, 'dd/MM/yy HH:mm');
var description = 'Protected on ' + stringDate;
var protection = range.protect().setDescription(description);
// below code taken directly from Google's documentation (second comment is my own):
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script throws an exception upon removing the group.
var me = Session.getEffectiveUser();
//user who installed trigger
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
The issue at hand is that I am working with many many shifts and people, which makes it very difficult and tedious to remove any protections in the event that someone needs to cancel for valid reasons (google sheets does not provide a way to search through your protected ranges). I understand the logic of writing scripts but am very inexperienced working with them. I could really use some help creating something that will remove all protections on any cell that I clear the data from.
one way would be to open the protect range menu and click the corner. then delete them manually
script would be:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0]; // assuming you want the first sheet
var protections = sheet.getProtections();
for (var i = 0; i < protections.length; i++) {
if (protections[i].getDescription() == 'Protect column A') { //name of protected range
protections[i].remove();
}
}
and for mass unprotecting see: https://webapps.stackexchange.com/a/99304/186471
You can get all the protections for a sheet with getProtections [1] and search which protection from all the protections in the sheets is being cleared using getRange method [2] on each Protect object to know the protected range and clear the protection in case the A1 notation is the same as the edited range (the range from the onEdit event), like this:
function onEdit(e) {
var range = e.range;
var newValue = range.getValue();
//If cell's new value is empty then remove protection
if(newValue == '') {
var sheet = range.getSheet();
var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
//Iterate through all sheet's protections
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
if (protection.getRange().getA1Notation() == range.getA1Notation()) {
protection.remove();
}
}
}
else {
var timeZone = Session.getScriptTimeZone();
var stringDate = Utilities.formatDate(new Date(), timeZone, 'dd/MM/yy HH:mm');
var description = 'Protected on ' + stringDate;
var protection = range.protect().setDescription(description);
// below code taken directly from Google's documentation (second comment is my own):
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script throws an exception upon removing the group.
var me = Session.getEffectiveUser();
//user who installed trigger
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
}
[1] https://developers.google.com/apps-script/reference/spreadsheet/sheet#getprotectionstype
[2] https://developers.google.com/apps-script/reference/spreadsheet/protection.html#getrange
[3] https://developers.google.com/apps-script/reference/spreadsheet/range#geta1notation
I am trying to implement a script that locks a certain range of cells when a condition is true. Here is the link to my document:
https://docs.google.com/spreadsheets/d/1XShGxlz2fA2w2omth-TvYc7cK0nXvVMrhwRKafzVjOA/edit?usp=sharing
Basically I am sharing this document with a group of people so they fill their mail addresses in column B and put a number 1 in column C so it increments my counters for each slot. What I am trying to do is to lock each slot when it is full so other people can no more edit these slots but the problem is with my if statement if (cell1 == 10). The range is always locked even if the if condition is not realized. Here is my code :
function onOpen() {
var ss = SpreadsheetApp.getActive();
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var cell=60;
var cell1 = source.getRange("G2").getValue();
if (cell1 == 10){
// Protect range B2:B11, then remove all other users from the list of editors.
var ss = SpreadsheetApp.getActive();
var range = ss.getRange('B2:B11');
var protection = range.protect().setDescription('Sample protected range');
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script will throw an exception upon removing the group.
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
}
}
As Andy says in the comments, you need to explicitly remove the protection if cell G2 does not equal 10. (This code removes all protections).
Reading the Protection Class page, where you got the snippets from, I couldn't get a handle on the way editor privileges would factor into your needs, so this script will work if others are editors. If you don't want them to be editors, you'll have to add the relevant code.
function onOpen() {
var ss = SpreadsheetApp.getActive();
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var cell = source.getRange("G2").getValue();
var range = ss.getRange('B2:B11');
if (cell == 10) {
// Protect range B2:B11 if cell 'G2' = 10
var protection = range.protect().setDescription('Sample protected range');
Logger.log
} else {
// Remove protection if cell 'G2' is anything other than 10
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
protection.remove();
}
}
}
I really need help for my code. What I do along with some other friends of mine is tutor as a part-time job. Every week, I create a sheet and have my friends fill out columns based on which group of people they tutored. Because sometimes some of my friends mistakenly fill out the wrong columns, I protect the columns and allow them to edit their respective columns by protecting every cell that they're not supposed to fill out. Because this is too tedious to do every week, I wanted to write a code instead so that when I run it it will see which editor is accessing the sheet and protect every other cell except the ones they're supposed to edit. Below is a similar code that I am working on that I can't make work. Cell, cell1 and cell2 represents three different groups of people that are tutored with each listing 1 email except cell2 which consist of two emails. These emails represent the editors (that tutor their respective group of people) who input data to their respective column. Range, range1 and range2 consists of cells that the tutors need to fill out. I have little to no knowledge for coding and this is what I can muster based on what I can find or learn. I really appreciate it if someone can help me edit my code as I don't know what to do.
function onOpen() {
var ss = SpreadsheetApp.getActive();
var source = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("test 3");
var email = Session.getActiveUser().getEmail();
var cell = source.getRange("A6").getValue();
var cell1 = source.getRange("C6").getValue();
var cell2 = source.getRange("E6:E7").getValue();
var range = ss.getRange('H5:H20');
var range1 = ss.getRange('J5:J20');
var range2 = ss.getRange('L5:L20');
if (cell == email) {
// Remove protection if cell 'A6' is email#gmail.com
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
protection.remove();
}
}else {
// Protect range H5:H20 if cell 'A6' is not email#gmail.com
var protection = range.protect().setDescription('Sample protected range');
Logger.log
}
if (cell1 == email) {
// Remove protection if cell 'C6' is email1#gmail.com
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
protection.remove();
}
}else {
// Protect range H5:H20 if cell 'C6' is not email1#gmail.com
var protection = range.protect().setDescription('Sample protected range');
Logger.log
}
if (cell2 == email) {
// Remove protection if cell 'C6' is email2#gmail.com
var protections = ss.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var protection = protections[i];
protection.remove();
}
}else {
// Protect range H5:H20 if cell 'C6' is not email2#gmail.com
var protection = range.protect().setDescription('Sample protected range');
Logger.log
}
}