Prevent google script from duplicating protected ranges - javascript

I have this script that I am using to copy over (convert formulas to values) and then protect the range when a user enters a value "Burned" in to a certain cell (A2, A6, etc) at the end of each month (can't make it triggered by date as users may be completing data entry on slightly different dates). The spreadsheet needs users to lock the data every month, so the script is set up for converting and protecting data each month as the user enters "Burned" into each month. The script is working well to convert formulas to values and it is also working to protect the range. However, every time I edit the sheet, it creates duplicate protected ranges so I end up with multiple protected ranges called January Burned, February Burned, etc. Is there any way to prevent the script from duplicating the protected ranges? Any help is greatly appreciated.
function onEdit(e)
//January
{
var ss = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckA = sheet.getRange("A2").getValue();
var rangeA = sheet.getRange("A2:AZ5");
{
if(valueToCheckA == "Burned")
{
rangeA.copyTo(rangeA, {contentsOnly:true});
var protection = rangeA.protect().setWarningOnly(true).setDescription('January Burned');
}
}
}
//February
{
var ss = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckB = sheet.getRange("A6").getValue();
var rangeB = sheet.getRange("A6:AZ9");
{
if(valueToCheckB == "Burned")
{
rangeB.copyTo(rangeB, {contentsOnly:true});
var protection = rangeB.protect().setWarningOnly(true).setDescription('February Burned');
}
}
}
//March
{
var ss = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckC = sheet.getRange("A10").getValue();
var rangeC = sheet.getRange("A10:AZ13");
{
if(valueToCheckC == "Burned")
{
rangeC.copyTo(rangeC, {contentsOnly:true});
var protection = rangeC.protect().setWarningOnly(true).setDescription('March Burned');
}
}
}

You had some weird things going on in your code. So I'd reformat it like this:
//January
function onEdit(e)
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckA = sheet.getRange("A2").getValue();
var rangeA = sheet.getRange("A2:AZ5");
if(valueToCheckA == "Burned")
{
rangeA.copyTo(rangeA, {contentsOnly:true});
var protection = rangeA.protect().setWarningOnly(true).setDescription('January Burned');
}
}
Try it again and let me know if anything has changed.
After looking over you code again. I grabbed entire code and took a close look at it and I made an interesting discovery. Several of your sections of code are not within the function onEdit so they run every time you access your scripts even when onEdit is not called. In fact, when I think about it, I believe you just run this once a month so why not just put it in a separate function and call once a month and forget the onEdit trigger.
function onEdit(e)
{
var ss = SpreadsheetApp.getActive();//January
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckA = sheet.getRange("A2").getValue();
var rangeA = sheet.getRange("A2:AZ5");
if(valueToCheckA == "Burned")
{
rangeA.copyTo(rangeA, {contentsOnly:true});
var protection = rangeA.protect().setWarningOnly(true).setDescription('January Burned');
}
}
// This section is not in the onEdit function so it's run every time you come to this page
var ss = SpreadsheetApp.getActive();//February
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckB = sheet.getRange("A6").getValue();
var rangeB = sheet.getRange("A6:AZ9");
if(valueToCheckB == "Burned")
{
rangeB.copyTo(rangeB, {contentsOnly:true});
var protection = rangeB.protect().setWarningOnly(true).setDescription('February Burned');
}
// This section is not in the onEdit function so it's run every time you come to this page
var ss = SpreadsheetApp.getActive();//March
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckC = sheet.getRange("A10").getValue();
var rangeC = sheet.getRange("A10:AZ13");
if(valueToCheckC == "Burned")
{
rangeC.copyTo(rangeC, {contentsOnly:true});
var protection = rangeC.protect().setWarningOnly(true).setDescription('March Burned');
}
So here's a rough start of a function that could do the job for you and you can just run it once a month. I haven't tested it and it most likely has some mistakes in it so check it out.
function monthlyBurn()
{
var ui = SpreadsheetApp.getUi();
var response = ui.prompt('Enter checkCell,protectRange,description all separate by commas', ui.ButtonSet.OK);
var t = response.getResponseText().split(',');
if(t.length !== 3)
{
ui.alert('Invalid input. Your missing a parameter')
return;
}
var ss = SpreadsheetApp.getActive();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Caseload");
var valueToCheckC = sheet.getRange(t[0]).getValue();
var rangeC = sheet.getRange(t[1]);
if(valueToCheckC == "Burned")
{
rangeC.copyTo(rangeC, {contentsOnly:true});
var protection = rangeC.protect().setWarningOnly(true).setDescription(t[2]);
}
}

Thanks for all the input and assistance, I have spoken with a colleague who was able to write this script which is working great.
function onEdit(e)
{
var sheet = e.range.getSheet();
if (sheet.getName() != "Caseload" || e.value != "Burned") return;
var moment = Moment.load();
var date = moment.utc(e.range.offset(0, 1).getValue());
if (!date.isValid()) return;
var month = date.format('MMMM');
var range = sheet.getRange(e.range.getRow(), e.range.getColumn(), 4, 26*2); // 4 rows and 26*2 columns (AZ)
range.copyTo(range, {contentsOnly: true});
range.protect().setWarningOnly(true).setDescription(month + ' Burned');

Related

Google Apps Script trigger to create Google Calendar events is failing

My Google Apps Script works with the "On edit" trigger with no issues.
However, when I try to put a time based daily trigger it gets a 100% error rate.
Can someone help me understand why this may be happening? The App Script code is below.
function schedule_shifts() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var calendarId = spreadsheet.getRange("D1").getValue();
var eventCal = CalendarApp.getCalendarById(calendarId);
var signups = spreadsheet.getRange("A3:C19").getValues();
for (x=0; x<signups.length; x++) {
var shift = signups[x]
var startTime = shift[0];
var endTime = shift[1];
var name = shift[2];
eventCal.createEvent(name, startTime, endTime)
}
}
'''
Try it this way
function schedule_shifts() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var calendarId = spreadsheet.getRange("D1").getValue();
var eventCal = CalendarApp.getCalendarById(calendarId);
var signups = spreadsheet.getRange("A3:C19").getValues();
for (x=0; x<signups.length; x++) {
var shift = signups[x]
var startTime = new Date(shift[0]);
var endTime = new Date(shift[1]);
var name = shift[2];
eventCal.createEvent(name, startTime, endTime)
}
}
Be more specific about what is wrong

I want to apply script to multiple subsheet in one Sheet

I followed youtube instruction and copied this script
var SHEET_NAME = 'Sheet1';
var DATETIME_HEADER = '입력일시';
function getDatetimeCol(){
var headers = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).getDataRange().getValues().shift();
var colindex = headers.indexOf(DATETIME_HEADER);
return colindex+1;
}
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell();
var datecell = ss.getRange(cell.getRowIndex(), getDatetimeCol());
if (ss.getName() == SHEET_NAME && cell.getColumn() == 1 && !cell.isBlank() && datecell.isBlank()) {
datecell.setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm:ss");
}
};
I want to apply this script to all subsheet in the file.
so I tried to add more sheet name like
var SHEET_NAME = 'Sheet1'; => var SHEET_NAME = ['Sheet1','Sheet2','Sheet3',]
or
var SHEET_NAME = 'Sheet1';
var SHEET_NAME = 'Sheet2';
var SHEET_NAME = 'Sheet3';
and they didn' work.
I don't have any, even rudimentary knowledge to this area, could you teach me how can I apply this script on whole subsheet, please?
I have changed your code slightly according to the task at hand:
SHEET_NAMES = ['Sheet1','Sheet2','Sheet3'];
DATETIME_HEADER = '입력일시';
function onEdit(e) {
let range = e.range,
sheet = range.getSheet();
if (SHEET_NAMES.includes(sheet.getName()) && range.rowStart > 1 && range.columnStart == 1 && !e.value == '') {
let colindex = sheet.getDataRange().getValues().shift().indexOf(DATETIME_HEADER)+1,
datecell = sheet.getRange(range.rowStart,colindex);
if (datecell.isBlank()) datecell.setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm:ss");
}
};
I don't think it's a good idea to run getDatetimeCol() every time you make a change in the table - it's better to do it only when the changes occur in the right sheets and cells

How to solve a problem time expired in javasrcipt

I am trying to send data to Google Sheet in my mobile application.
The data arrives well but the code does not return the result quickly
here is my JavaScript code.
The problem is that it takes a long time (around 360s) to return the result
it's ok
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/177kUZc61U8huVsq2OcGsiF2OGdPCSxMjkoh2C4KIWPM/edit#gid=0");
var sheet = ss.getSheetByName('Info');
function doGet(e) {
var action = e.parameter.action;
if (action == 'UpdateInfo') {
//return UpdateInfo(e);
}
}
function doPost(e) {
var action = e.parameter.action;
if (action == 'UpdateInfo') {
return UpdateInfo(e);
}
}
function UpdateInfo(e) {
var values = sheet.getRange(2, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
var email = e.parameter.email;
var password = e.parameter.password;
//var date = sheet.getRange('A').getValues();//new Date();
var name = e.parameter.name; ///Item1
var lname = e.parameter.lname;
var itemuserImage = e.parameter.itemuserImage;
var region = e.parameter.region;
var provaince = e.parameter.provaince;
var ecole = e.parameter.ecole;
var Unite = e.parameter.unite;
var niveau = e.parameter.niveau;
//var flag = 0;
var lr = sheet.getLastRow();
for (var i = 1; i <= lr; i++) {
var IDuser = sheet.getRange(i, 1).getValue();
//row[1];
var shetemail=sheet.getRange(i,2).getValue();
var shetpassword=sheet.getRange(i,3).getValue();
if (shetpassword==password && shetemail==email ) {
sheet.getRange(i,4).setValue(name);
// sheet.getRange(i,5).setValue(lname);
//row[2];
///zoydghnmayad sheet.getRange(i,7).setValue(region);
//row[4];
sheet.getRange(i,8).setValue(provaince);
//row[5];
sheet.getRange(i,9).setValue(ecole);
//row[5];
sheet.getRange(i,10).setValue(Unite);
//row[5];
sheet.getRange(i,11).setValue(niveau);
//row[5];
var dropbox="USERSIMAGE prof";
var folder, folders=DriveApp.getFoldersByName(dropbox);
if (folders.hasNext()) {
folder=folders.next();
} else {
folder=DriveApp.createFolder(dropbox);
}
var fileName=IDuser+"profile_pic.jpg";
var contentType="image/jpg" , bytes=Utilities.base64Decode(itemuserImage), blob=Utilities.newBlob(bytes, contentType,fileName);
var file=folder.createFile(blob);
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK,DriveApp.Permission.VIEW);
var fileIdumage=file.getId();
var fileUrlumage="https://drive.google.com/uc?export=view&id=" +fileIdumage; sheet.getRange(i,6).setValue(fileUrlumage);
//row[5];
return ContentService.createTextOutput("its ok").setMimeType(ContentService.MimeType.TEXT);
}
} ///thiya loop
}
Not quite sure.But do you check your image size of "profile_pic.jpg".
In my experience,if you capture the profile image using mobile app camera,the image size is extremely large.It will take ages to upload the image if you forget to compress it(no need such high HD image for profile, and compression is neccesary).
As a matter of that,please double check size of the image you were uploading.And please do not forget to compress it if it occupy too much space.

google app script copy values !=0 into new column

I am trying to copy cells with the value 0 into another cell. Can't seem to get the if statement to work.
function pushGeo()
{
var ssA = SpreadsheetApp.openById('###')
var ss = ssA.getSheetByName('thissheet');
var lastRow = ss.getLastRow();
for(var row=2;row<=lastRow;row++)
{
if(ss.getRange('G'+row).getValue() != 0){
var source = ss.getRange('G2:G'+lastRow);
var destination = ss.getRange('N2:N'+lastRow);
source.copyTo(destination);
}
}
Right now it's copying all cells into the new column.
==
Ah, nevermind. I was silly with the range. Time to stop coding for the day.
function pushGeo()
{
for(var row=2;row<=lastRow;row++)
{
if(ss.getRange('G'+row).getValue() != 0){
var source = ss.getRange('G'+row);
var destination = ss.getRange('N'+row);
source.copyTo(destination);
}
}
Ah, nevermind. I was silly with the range. Time to stop coding for the day.
function pushGeo()
{
for(var row=2;row<=lastRow;row++)
{
if(ss.getRange('G'+row).getValue() != 0){
var source = ss.getRange('G'+row);
var destination = ss.getRange('N'+row);
source.copyTo(destination);
}
}

sending data from a google spreadsheet program to google calender

Here is my case.
A user fills a form for event booking, the submitted form is stored in a google spreadsheet which I have synced to a google calender so that it automatically sends the data to it.
Everything is working fine apart from the fact that event times could clash.
When customers book an event centre for let's say on 13/3/2015 T 10:00AM, if another user enters the same date and time, the entry should not be accepted.
To summarise it, I want to avoid a clash of events booking. Thank you all.
here is my script.
var calendarId = "mycalenderid";
//below are the column ids of that represents the values used in the spreadsheet (these are non zero indexed)
var startDtId = 9;
var endDtId = 10;
var titleId = 6;
var descId = 11;
var formTimeStampId = 1;
function getLatestAndSubmitToCalendar() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var lr = rows.getLastRow();
var startDt = sheet.getRange(lr,startDtId,1,1).getValue();
//set to first hour and minute of the day.
//startDt.setHours(0);
//startDt.setMinutes(00);
var endDt = sheet.getRange(lr,endDtId,1,1).getValue();
//set endDt to last hour and minute of the day
//endDt.setHours(23);
//endDt.setMinutes(59);
var subOn = "Submitted on:"+sheet.getRange(lr,formTimeStampId,1,1).getValue();
var desc = "Added by :"+sheet.getRange(lr,descId,1,1).getValue()+"\n"+subOn;
var title = sheet.getRange(lr,titleId,1,1).getValue()+"DIA";
createEvent(calendarId,title,startDt,endDt,desc);
}
function createEvent(calendarId,title,startDt,endDt,desc) {
var cal = CalendarApp.getCalendarById(calendarId);
var start = new Date(startDt);
var end = new Date(endDt);
var loc = 'Script Center';
var event = cal.createEvent(title, start, end, {
description : desc,
location : loc
});
};
Here's a pseudocode of what you're trying to do:
function findEvent(desiredDateTime)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getDataRange();
var data = range.getValues();
var lRow = range.getLastRow();
var flag = true;
var count = 0;
while (flag == true || count < lRow)
{
if (desiredDateTime >= data[count][startDtId] && desiredDateTime <= data[count][endDtId])
{
flag = false;
}
else
{
count++;
}
}
if (flag == true)
{
//Call function to add event
}else{
//Tell user desired date-time is not available.
//If you're asking for user's email address,
//simplest approach would be to send an email.
}
}
You might have to modify other bits and pieces of your code as well to accommodate this but it shouldn't be too hard. Hope this provides you with a certain direction to follow through.

Categories

Resources