In google AppsScripts howto fetch users Email or ID whos editing the sheet? - google-apps-script

We do keep up with googlesheet. So to help the team I've made our sheets more automated and everything worked well for time. The signature stamp stopped to work a while ago, and tried to find different solutions for this before asking on my free time.
This is our first on to fetch names, but nowdays does not work.
function whatsMyName()
{
var email = Session.getEffectiveUser().getEmail();
var self = false;
if (self)
{
var name = self.getGivenName();
if (!name)
{
name = self.getFullName();
}
return name;
}
else
{
var userName = Session.getEffectiveUser().getUsername();
return userName;
}
}
Been tried different kind of solutions like this found here:
function getCurrentUserEmail()
{
var userEmail = Session.getActiveUser().getEmail();
if (userEmail === '' || !userEmail || userEmail === undefined)
{
userEmail = PropertiesService.getUserProperties().getProperty('userEmail');
if (!userEmail)
{
var protection = SpreadsheetApp.getActive().getRange('A1').protect();
protection.removeEditors(protection.getEditors());
var editors = protection.getEditors();
if (editors.length === 2)
{
var owner = SpreadsheetApp.getActive().getOwner();
editors.splice(editors.indexOf(owner), 1);
}
userEmail = editors\[0\];
protection.remove();
PropertiesService.getUserProperties().setProperty('userEmail', userEmail);
}
}
return userEmail;
}
Pretty much this did return our "owner" of sheet, not user.
Is there somekind of workaround for this anymore?
So most of those tips and tricks I've found seems to be outdated and not usable anymore.
Trying to reCode this back in action, without win here.
Edit; Trigger on this is
function onEdit()
var s = SpreadsheetApp.getActiveSheet();
var r = s.getActiveCell();
if (s.getName() == "exampleSheet")
{
if (r.getColumn() == 6) //Cell we check for finished job
{
var nCell = r.offset(0, -4);
if (nCell.getValue() == "")
{
name = whatsMyName();
if(name === "example#eMail.com")
{
nCell.setValue("EI");
}
}
}
}"
So after checking that work is done, code should stamp initials to Column2, time and date stamps works, coloring the background works etc.

In my automated sheets I always use 'Session.getActiveUser().getEmail()' to stamp the person editing the cell, however I use this as part of an 'onEdit()' function. I am not sure if it would work when it comes from a dedicated function.
Where are you planning on using it?

Related

Why does getEventById() return null?

So I'm pretty new to coding with GAS and I've been working on this the other day. The idea is to have a spreadsheet of events and create them in my calendar and check if the event already exists and update it if there are any changes to the name or date of the event.
Here's my code for reference:
function events() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("test");
const cal = CalendarApp.getCalendarById("calID");
for (i = 3; i <= sheet.getLastRow(); i++) {
var date = sheet.getRange(i, 8).getValue();
if (date > 0) {
var title = sheet.getRange(i, 3).getValue();
var id = sheet.getRange(i, 9).getValue();
if (id != 0) {
var ide = cal.getEventById("id");
var idf = ide.getAllDayStartDate();
var idn = ide.getTitle();
if (date != idf) {
ide.setAllDayDate(fecha);
}
if (title != idn) {
ide.setTitle(nombre);
}
}
else {
var nid = cal.createAllDayEvent(name, date).getId();
sheet.getRange(i, 9).setValue(nid);
}
}
}
}
I was able to create the events succesfully but when it checks the date of an already existing one it says this:
Error TypeError: Cannot read property 'getAllDayStartDate' of null
Later, using the Logger.log() I found out that this is returning as null even tho the event with that ID exists and it has access to the calendar:
var ide = cal.getEventById("id");
I then looked online and found this but when i tried running the code marked as a solution this returns empty:
var event = CalendarApp.getDefaultCalendar().getEvents(now, nextEvent);
I then tried deleting and allowing again the permissions for calendar and sheets but it didn't work.
I even tried editing the appsscript.json file by hand like this:
{
...
"oauthScopes": [
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/calendar.readonly",
"https://www.google.com/calendar/feeds",
"https://www.googleapis.com/auth/spreadsheets.currentonly",
"https://www.googleapis.com/auth/spreadsheets"
]
...
}
But that didn't work either.
Any help would be much appreciated!
Edit:
I've now tested with the default calendar and creating a new calendar but it doesn't work. I'm starting to think it's a bug but I'm not sure what could be causing it.
I was writting getEventById("id") and it should've been getEventById(id):
...
var id = sheet.getRange(i, 9).getValue();
if (id != 0) {
var ide = cal.getEventById(id);
...

How to continue running the script even if a user exists in Google Group using google scripts?

I need help with Google groups. The code currently checks if a member already exists but it stop when it does find one. How can I modify the code to allow it to process the next row without stopping?
TIA!
function updateGroup() {
const s = SpreadsheetApp.openById("ID HERE");
const sheet_name = s.getSheetByName("REPORT HERE");
const sheet_data = sheet_name.getRange(2,1,sheet_name.getLastRow(),sheet_name.getLastColumn());
const sheet_dataVal = sheet_data.getValues();
for (var i = 0; i < sheet_dataVal.length-1; i++) {
var member_Email = sheet_dataVal[i][9]; // REWS Projects Email Address
var groupEmail = "GROUP EMAIL ADDRESS HERE";
var member_Role = "MEMBER";
var member_Type = "USER";
var group = GroupsApp.getGroupByEmail(groupEmail);
var comment = sheet_dataVal[i][13];
if (comment === "Member Added to Group" || comment === "Member already exists") {continue;}
var checkMembers = AdminDirectory.Members.list(groupEmail).members
for (var m in checkMembers) {
if (checkMembers[m].email == member_Email);
return sheet_name.getRange(i+2,14).setValue("Member already exists");
}
addNewMembersToGroup(member_Email,member_Role,groupEmail,i,sheet_name);
}
}
function addNewMembersToGroup(member_Email,member_Role,groupEmail,i,sheet_name) {
/* Member does not exists in group, add */
var addNewMember = {
kind: "admin#directory#member",
email: member_Email,
role: member_Role
};
AdminDirectory.Members.insert(addNewMember,groupEmail);
sheet_name.getRange(i+2,14).setValue("Member Added to Group");
}
When you are using a return, the execution of the function is stopped - hence the issue you are getting.
In order to fix this, you should remove the return and have the if statement like this:
if (checkMembers[m].email == member_Email);
sheet_name.getRange(i+2,14).setValue("Member already exists");
Reference
JavaScript return statement.

How do I send an automated email to a specific person, depending on task status, using an aux sheet to store emails?

Gory title but I couldn't find a way of being clearer.
I have no experience with coding and I was wondering if doing something like what I'm about to explain would be possible.
This is my example sheet:
What I'm looking to do is to have automated emails sent out to the person assigned to the task if the task status is set to urgent, while referencing people by names and having an auxiliary sheet with all the names and corresponding emails.
I've browsed around and found some similar questions which I unfortunately had no success in adapting. The one thing I got is that I need to setup an onEdit trigger, which I've done, but I'm completely clueless from here on out.
Can someone point me in the right direction? I don't have a clue where to start.
Looking forward to hearing your advice.
Thanks and stay safe in these crazy times!
It was a funny exercise. I tried to make the script as clean and reusable as possible for others to be able to adapt it to their needs.
Usage
Open spreadsheet you want to add script to.
Open Script Editor: Tools / Script editor.
Add the code. It can be configured by adjusting variables in the top:
var trackerSheetName = 'Tracker 1'
var trackerSheetStatusColumnIndex = 2
var trackerSheetNameColumnIndex = 4
var triggeringStatusValue = 'Urgent'
var peopleSheetName = 'AUX'
var peopleSheetNameColumnIndex = 1
var peopleSheetEmailColumnIndex = 2
var emailSubject = 'We need your attention'
var emailBody = 'It is urgent'
function checkStatusUpdate(e) {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet()
var activeSheet = spreadsheet.getActiveSheet()
// skip if different sheet edited
if (activeSheet.getName() !== trackerSheetName) {
return
}
var editedRange = e.range
// skip if not a single cell edit
if (editedRange.columnStart !== editedRange.columnEnd || editedRange.rowStart !== editedRange.rowEnd) {
return
}
// skip if edited cell is not from Status column
if (editedRange.columnStart !== trackerSheetStatusColumnIndex) {
return
}
// skip if Status changed to something other than we're looking for
if (e.value !== triggeringStatusValue) {
return
}
var assigneeName = activeSheet.getRange(editedRange.rowStart, trackerSheetNameColumnIndex, 1, 1).getValue()
var peopleSheet = spreadsheet.getSheetByName(peopleSheetName)
var people = peopleSheet.getRange(2, 1, peopleSheet.getMaxRows(), peopleSheet.getMaxColumns()).getValues()
// filter out empty rows
people.filter(function (person) {
return person[peopleSheetNameColumnIndex - 1] && person[peopleSheetEmailColumnIndex - 1]
}).forEach(function (person) {
if (person[peopleSheetNameColumnIndex - 1] === assigneeName) {
var email = person[peopleSheetEmailColumnIndex - 1]
MailApp.sendEmail(email, emailSubject, emailBody)
}
})
}
Save the code in editor.
Open Installable Triggers page: Edit / Current project's triggers.
Create a new trigger. Set Event Type to On edit. Keep other options default.
Save the Trigger and confirm granting the script permissions to access spreadsheets and send email on your behalf.
Go back to your spreadsheet and try changing status in Tracker 1 tab for any of the rows. Corresponding recipient should receive an email shortly.
This should get you started:
You will need to create an installable trigger for onMyEdit function. The dialog will help you to design you email by giving you an html format to display it. When you're ready just comment out the dialog and remove the // from in front of the GmailApp.sendEdmail() line.
function onMyEdit(e) {
//e.source.toast('Entry');
const sh=e.range.getSheet();
if(sh.getName()=="Tracker") {
if(e.range.columnStart==2 && e.value=='Urgent') {
//e.source.toast('flag1');
const title=e.range.offset(0,-1).getValue();
const desc=e.range.offset(0,1).getValue();
const comm=e.range.offset(0,3).getValue();
if(title && desc) {
var html=Utilities.formatString('<br />Task Title:%s<br />Desc:%s<br />Comments:%s',title,desc,comm?comm:"No Additional Comments");
//GmailApp.sendEmail(e.range.offset(0,2).getValue(), "Urgent Message from Tracker", '',{htmlBody:html});
SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(html).setWidth(600), 'Tracker Message');
e.source.toast('Email Sent');
}else{
e.source.toast('Missing Inputs');
}
}
}
}
GmailApp.sendEmail()

My code is working from the script editor but not as an add-on

i have made a guessing on games with friends spreadsheet and i want to hide the code i wrote from the editors
I was reading a lot on the net about that and i seems that the best option is to make my code as an add-on, so i tried that and done everything that guide said , the add-on added to my spreadsheet but the code is not working, not the onEdit and not the Trigger (that set up to work every hour). at the chrome web store i think i did everything fine (again i used the guide) as "draft" status or "Published to Testers" not difference its not working! trying hours to make it work but i couldn't, im new to codding and that project went bigger then i expected, i must hide that code ill appreciate any help!
this is my code:
var colMin = 7;
var minRow = 3;
function onEdit(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getActiveRange();
var currRow = range.getRow();
var currCol = range.getColumn();
if(sheet.getName() == "Bets") {
if(currCol >= colMin && currCol <= getLastCol("Bets") && currRow >= minRow) {
betingRange(sheet, ss, currRow, currCol);
} else if (currCol == 5 && currRow >= minRow) {
dataValBuilder(currRow, sheet.getRange(currRow, 5).getValue());
}
}
if(sheet.getName() == "Players") {
if(currCol == 3) {
.............................. etc...................
..............using some Protection and named ranged commands........
SpreadsheetApp.getActiveSpreadsheet().setNamedRange(player.gamesLogNR, gamesLogSheet.getRange(3,lastColgamesLog+3,1000));
SpreadsheetApp.getActiveSpreadsheet().addEditor(player.email);
var protection = rangePro.protect().setDescription(player.name+" betting area, player id: "+player.id);
protection.setRangeName(player.betsNR);
protection.removeEditors(protection.getEditors());
if (player.email.length > 5) {
protection.addEditor(player.email);
}
}
.......... etc...........
.......timesup is the Trigger function (works hourly)............
function timesUp() {
var betsScore = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("betsScoreHolder");
var listsSheet = .......ETC........
} else {
SpreadsheetApp.getActiveSpreadsheet().setNamedRange("rowsBlock", betsSheet.getRange(3, 7, (n+1)-3, betsLastCol-6));
}
}
break;
}
}
}
Again, the add on with my code already installed to the spreadsheet, but its not acting like the code in on the script editor,i mean its not working at all.
please help.

Google Scripts: Match Range and Update corresponding Value

Sheet1: DashBoard | Range: A7:B17
(B7: Has a Filter Function that displays results of all Open Tasks from BackEnd Sheet)
Sheet2: BackEnd | Range: J56:M
Match B7:B17 with M56:M
if there is a match then
Paste values from A7:A17 to J56:J
Click here for Sample Sheet
The below script does the above operation but ONLY on the first instance of running it. Trying to repeat the process does not do anything. No errors on the code.
I'm a beginner to any form of coding and the below code was scripted by referring to various solutions on the forum. I might be missing some logic here and not in a position to de-code it in order to achieve the desired end result.
Thanks in advance
function updateToDo2() {
var sh, toDo, status, update, i;
sh = SpreadsheetApp.getActive().getSheetByName('DashBoard')
toDo = sh.getRange('B7:B17').getValues();
status = sh.getRange('A7:A17').getValues();
update = SpreadsheetApp.getActive().getSheetByName('BackEnd').getRange('J56:M');
update.setValues(update.getValues()
.map(function(r, i) {
if (r[3] == toDo[i]) {
r[0] = status[i];
}
return r;
})
)
}
EDIT: Working Code but very slow. Needs optimization.
Please help!
function rowOfStatus(status) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('BackEnd');
var data = sheet.getRange('M56:M60').getValues();
for (var i = 0; i < data.length; i++) {
if (data[i][0] == status) { //[1] because column B
return i + 1;
}
}
}
function updateToDo() {
var sh, sh1, dashboard, results, noteText, status, i, counter;
sh = SpreadsheetApp.getActive().getSheetByName('DashBoard');
sh1 = SpreadsheetApp.getActive().getSheetByName('BackEnd');
dashboard = sh.getRange('A7:B11');
results = dashboard.getDisplayValues();
results.forEach(function(row) {
status = row[0];
noteText = row[1];
counter = Number(rowOfStatus(noteText));
if (counter > 0 && status != '') {
counter = 55 + Number(rowOfStatus(noteText));
sh1.getRange('J' + counter).setValue(status);
}
});
}
I'm not completely understanding what your doing but I thought I'd take a stab and trying to help you. So this might not be what you want. In that case sorry to bother you.
function updateToDo2() {
var sh=SpreadsheetApp.getActive().getSheetByName('DashBoard')
var toDo=sh.getRange('B7:B17').getValues();
var status=sh.getRange('A7:A17').getValues();
var update=SpreadsheetApp.getActive().getSheetByName('BackEnd').getRange('J56:M'+SpreadsheetApp.getActive().getSheetByName('BackEnd').getLastRow());
var vA=update.getValues();
for(var i=0;i<vA.length;i++){
if(vA[i][3]==toDo[i]){
vA[i][0]=status[i];
}
}
update.setValues(vA);
}
I got help in optimizing this code from Google Docs Help Forum and was provided by Jean-Pierre. Since I first posted my query on that Forum and was advised to post my query on StackOverflow by it's community member. Hence, here is the solution just in case it helps someone here. It's short & pretty fast!
Google Forum Link
Code:
function updateToDo() {
var ss, arr, values, colB, backendValues, backendColM;
ss = SpreadsheetApp.getActive();
arr = [];
values = ss.getSheetByName('DashBoard').getRange('A7:B17').getValues()
colB = values.map(function (v) {
return v[1];
})
backendValues = ss.getSheetByName('BackEnd').getRange('J56:M').getValues()
backendColM= backendValues.map(function (bv) {return bv[3]}).forEach(function (el, i) {
arr[i] = (el && colB.indexOf(el) > -1) ? ['Closed', 'Cancelled'].indexOf(values[colB.indexOf(el)][0]) > -1 ? [values[colB.indexOf(el)][0]] : [backendValues[i][0]]
: [backendValues[i][0]];
})
ss.getSheetByName('BackEnd').getRange(56, 10, arr.length, 1).setValues(arr)
ss.getSheetByName('DashBoard').getRange('A7:A17').setValue(null);
}