Google Apps Script getting information from google directory - google-apps-script

I have been tasked with creating an apps script for google forms that when submitted will send an email with the responses to several people. The form is for bonus recommendation so it will need to go to HR, the executive team, and the employees manager. I have the script working to where it will email the requested HR and the executive team but not the manager. HR and executive was simple because those are static teams, but the manager will change depending on the employee. I have the script where it will get the get the name of the employee and store it in the variable employeeName. I see that apps script has the admin directory service that I should be able to pull from the I am struggling to make it work the way I need. Below is the script so far.
function onFormSubmit(e) {
var responses = e.namedValues;
var htmlBody = '<ol>';
var ss = SpreadsheetApp.openById('redacted');
var gSheet = ss.getSheetByName('Form Responses 1');
var lastRow = gSheet.getLastRow();
var range = gSheet.getRange(lastRow,3);
var employeeName = range.getValue();
for (Key in responses) {
var header = Key;
var data = responses[Key];
htmlBody += '<li>' + header + ': ' + data + '</li>';
};
htmlBody += '</ol>';
GmailApp.sendEmail('redacted', 'Bonus Recommendation', '', {htmlBody:htmlBody})
}
I feel like I am missing something super simple. I should also add that I am NOT a scripter or programmer by any stretch. I'm just the net admin who drew the short straw for this project. (It does seem that I will be learning javascript so I can use apps script better).

Each namedValues is a array so try this:
responses[Key][0];
The reason they do that is because if you reuse the same form repeated the form continues to add new columns for different questions and you can end up with the same name in two different columns.
Personally, I would have used e.values.

Related

My first Apps Script - can this be more efficient?

I am a maths teacher who is learning programming and this is my first attempt at using Apps Script. I have used this site to find various bits of code and put them together to form a script that works (thank you to the numerous posters on this site who have unknowingly helped me already!).
My question is: can it be polished and made more efficient? I'm assuming it probably can - I'm grateful for help anyone is kind enough to provide.
Outline:
There are 2 existing Google Sheets - "DATA", containing a list of students and their data; "TEMPLATE", used to create a separate Google Sheet for each student.
The script collects the StudentID numbers from DATA and creates a new Google Sheet for each student based on the TEMPLATE Google Sheet.
Put the studentID in the filename and copy the studentID to cell U1 in the first tab [TEMPLATE contains 2 tabs] then hide the 2nd tab [called 'import'].
Add the student as a viewer.
Restrict copy/download/print for the viewer.
Many thanks,
Dan
function createSheets()
{
// ID of the Google Sheet to be used as a template for the student Sheets
var templateId = '###TEMPLATE###';
// Collect all the studentIDs from DATA and store in a variable called 'students'
var students = Sheets.Spreadsheets.Values.get('###DATA###', '###SheetName###');
for(var i = 0; i < students.values.length; i++)
{
var studentId = students.values[i][0];
// Make a copy of the template file
var documentId = DriveApp.getFileById(templateId).makeCopy().getId();
// Rename the copied file
DriveApp.getFileById(documentId).setName(studentId + ' Learner Map');
// Insert the studentId in cell U1 (of the first tab?)
SpreadsheetApp.openById(documentId).getRange('U1').setValue(studentId);
// Hide the 'import' tab
SpreadsheetApp.openById(documentId).getSheetByName('import').hideSheet();
// Add the student as a viewer
SpreadsheetApp.openById(documentId).addViewer(studentId + '###EMAIL EXTENSION##');
// Restrict copy/download/print for the viewer
// get the file with the Advanced Drive API (REST V2)
var file = Drive.Files.get(documentId);
Logger.log('File "%s", restricted label was: %s', file.title, file.labels.restricted);
// set the restricted label
file.labels.restricted = true;
//update the file
Drive.Files.update(file, documentId);
// check the updated file
var updatedFile = Drive.Files.get(documentId);
Logger.log('File "%s", restricted label is: %s', updatedFile.title, updatedFile.labels.restricted);
}
}

Maintaining "table status" when fetching Google Sheets values

I have a list of people that I need to send a schedule to every week. The schedule, and the list of emails for the people it needs to go to, are on a Google Sheet. I'd like to create a script that (a) gets the schedule, and (b) sends it to the list of emails.
My problem, right now, is my Google Apps Script code only sends the schedule as a string (e.g. "role1, person1, role2, person2, role3, person3"), instead of "keeping" its formatting as a table,
I've considered a loop that would grab the values of every row and add a "\n" value at the end, which would break the string after each person. That's not an unworkable solution, but I'd prefer to keep the table because it's more readable.
I suspect that I need to create an HTML table within Google Apps Script, populate it with values from my spreadsheet, and set that HTML table as my email body. That seems odd, because it's already a table (in the spreadsheet).
Is there a way to fetch values while maintaining their "table status"? If not, what are the bare-bones of creating/populating an HTML table?
Here's my code so far, for reference:
function WeeklyReminder() {
var ss = SpreadsheetApp.getActiveSpreadsheet(); // this directs the script to the spreadsheet
var sheet = ss.getSheetByName("Automated WVS Weekly Reminder Email"); // this directs the script to the right sheet
var schedule_values = sheet.getRange("D2:E").getDisplayValues(); // this gets the schedule values; "display values" because we want "what's seen," and not the function that's used to populate the cell
Logger.log("schedule_values = " + schedule_values);
var test_email = "o...#...org";
var volunteer_values = sheet.getRange("B2:B").getDisplayValues();
Logger.log("volunteer_values = " + volunteer_values);
MailApp.sendEmail({
to: test_email,
subject: 'WVS Weekly Reminder',
htmlBody: schedule_values.toString(),
});
}
Note: I'm aware my htmlBody sends...toString() at the moment, that's what I'm looking to change.
Building the html table
function WeeklyReminder() {
var ss=SpreadsheetApp.getActive();
var sheet=ss.getSheetByName("Automated WVS Weekly Reminder Email");
var vs=sheet.getRange(1,4,sheet.getLastRow(),2).getDisplayValues();
var html='<style>td,th{border:1px solid black;}</style><table>';
vs.forEach(function(r,i){
if(i==0) {
html+=Utilities.formatString('<tr><th>%s</th><th>%s</th></tr>',r[0],r[1]);//I changed the range so that it included the headers
}else{
html+=Utilities.formatString('<tr><td>%s</td><td>%s</td></tr>',r[0],r[1]);
}
html+='</table>';
});
var test_email="o...#...org";
var volunteer_values=sheet.getRange(2,2,sheet.getLastRow()-1,1).getDisplayValues();
MailApp.sendEmail({to: test_email,subject: 'WVS Weekly Reminder',htmlBody:html});
}

From Google Site manipulate a Google Sheet (as a simpler page visit counter)

I am aware, that I should track my Google Site with Analytics, but I am (for certain reasons) not able to use.
Therefore I would like to add a VERY SIMPLE page counter for the Google Site.
So for every page displayed, I would like to have a counter in Google Sheets (so add +1). [A plus to display the page counter]
Anyone done this?
Thanks
I don't know how robust this is gonna be you could give it a try
Option 1: Storing data in Spreadsheet
It would be very simple to get a cell and sum it on on every request that you get.
function doGet(e){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cellCounter = sheet.getRange(1, 1);
cellCounter.setValue(cellCounter.getValue() + 1);
return HtmlService.createHtmlOutput("<b>current sum is at " + cellCounter.getValue() + "</b>");
}
Option 2: Storing data in script Properties
Another option is to use the PropertiesService to store the data "inside the script".
function doGet(e){
var prop = PropertiesService.getScriptProperties();
var key = "COUNTER";
var counter = prop.getProperty(key);
if(counter){
prop.setProperty(key, parseInt(counter) + 1)
}else(
prop.setProperty(key, 1)
)
return HtmlService.createHtmlOutput("<b>current sum is at " + prop.getProperty(key) + "</b>");
}
Although both options are not very robust, although depending on the traffic you expect it could work very well.

Efficient Way of sending Spreadsheet over email using GAS function?

I am creating an addon for Google Sheets that my local High School's volunteer clubs can use to keep track of their member's volunteer hours. Most of the code is done and works very nicely, and I am currently working on a system that will send a member a spreadsheet listing all of the volunteer events that they have logged. I have GAS create a separate spreadsheet, and then send an email with that separate spreadsheet attached in PDF. When the email is received, the PDF is empty except for a singular empty cell at the top left of the page.
I am pretty new to GAS but have been able to grasp the content pretty easily. I have only tried one method of sending the Spreadsheet and that is by using the .getAs(MimeType.PDF). When I changed the "PDF" to "GOOGLE_SHEETS," GAS returned the error: "Blob object must have non-null data for this operation." I am not entirely sure what a Blob object is, and have not found any website or video that has fully explained it, so I am not sure how to go about troubleshooting that error.
I think I'm having a problem grabbing the file because it either sends an empty PDF or it returns an error claiming it needs "non-null data."
function TigerMail()
{
var Drive = DriveApp;
var app = SpreadsheetApp;
var LOOKUP = app.getActiveSpreadsheet().getSheetByName("Student
Lookup");
var Name = LOOKUP.getRange("E1").getValue();
Name = Name + "'s Hours";
//app.openById(Name+"'s Hours");
var HOURS = app.create(Name);
var ESheet = HOURS.getSheets()[0];
var ROW = LOOKUP.getLastRow();
var arr = LOOKUP.getRange("D1:J"+ROW).getValues();
var cell = ESheet.getRange("A1:G"+ROW);
cell.setValues(arr);
////////////////////////////////////////////////////
var LOOKUP = app.getActiveSpreadsheet().getSheetByName("Student
Lookup");
var cell = LOOKUP.getRange("D1");
var Addr = cell.getValue();
var ROW = LOOKUP.getLastRow();
var file = Drive.getFilesByName(Name);
var file = file.next();
var FORMAT = file.getAs(MimeType.GOOGLE_SHEETS);
TigerMail.sendEmail(Addr, "Hours", "Attached is a list of all of the
events you have volunteered at:", {attachments: [FORMAT]} );
}
the final four lines are where the errors are occurring at. I believe I am misunderstanding how the .next() and .getFilesByName() work.
(above the comment line: creating a spreadsheet of hours)
(below the comment line: grabbing the spreadsheet and attaching it to an email)
Here is the link to the Google Sheet:
https://docs.google.com/spreadsheets/d/1qlUfTWaj-VyBD2M45F63BtHaqF0UOVkwi04XwZFJ4vg/edit?usp=sharing
In your script, new Spreadsheet is created and put values.
You want to sent an email by attaching the file which was converted from the created Spreadsheet to PDF format.
If my understanding is correct, how about this modification? Please think of this as just one of several answers.
Modification points:
About Drive.getFilesByName(Name), unfortunately, there is no method of getFilesByName() in Drive.
I think that when you want to use the created Spreadsheet, HOURS of var HOURS = app.create(Name) can be used.
About var FORMAT = file.getAs(MimeType.GOOGLE_SHEETS), in the case of Google Docs, when the blob is retrieved, the blob is automatically converted to PDF format. This can be also used for your situation.
In order to save the values put to the created Spreadsheet, it uses SpreadsheetApp.flush().
When above points are reflected to your script, it becomes as follows.
Modified script:
Please modify as follows.
From:
var file = Drive.getFilesByName(Name);
var file = file.next();
var FORMAT = file.getAs(MimeType.GOOGLE_SHEETS);
To:
SpreadsheetApp.flush();
var FORMAT = HOURS.getBlob();
Note:
In your script, it seems that var ROW = LOOKUP.getLastRow() is not used.
References:
flush()
getBlob()
If I misunderstood your question and this was not the result you want, I apologize.

Google Apps Script in Form

I'm building a form for students to enter in and I want to Auto input their email address and I'm unsure how to do this. I'm come up with the following but I'm very new to this and may be way off. I'm unsure how to implement it and I'm getting a null response. Do I need a form question which says email ? how do I get the user's email to be recorded but in a hidden way?
function formEnterEmail(e) {
var userEmail = Session.getActiveUser().getEmail();
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow = sheet.getLastRow();
// Set the status of the new ticket to 'New'.
// Column F is the Status column
sheet.getRange(lastRow, getColIndexByName("Email")).setValue(userEmail);
function getColIndexByName(colName) {
var sheet = SpreadsheetApp.getActiveSheet();
var numColumns = sheet.getLastColumn();
var row = sheet.getRange(1, 1, 1, numColumns).getValues();
for (i in row[0]) {
var name = row[0][i];
if (name == colName) {
return parseInt(i) + 1;
}
}
return -1;
}
}
You can collect the user's email address in Google Forms only if you are using Google Apps for Business or Google Apps for Education, and then only from users in your domain. If you don't meet those requirements, then your only option is to request that users fill in the information, or to email a URL to a pre-filled-form.
This isn't really "hidden", as the live form will report that the user id is being collected.
If you're creating your form from a script, you can control the email collection feature by using Form.setCollectEmail(true). However, you can also set this up without using any code.
In the form editor, look for "Form Settings". They should appear above all the questions. Set the check boxes that require domain login, and username collection.
The spreadsheet that collects responses will automatically contain a "Username" column:
If you are building a form that you will be emailing to the students, then when you set up the form you can have it log all their email addresses for you without you having to write any script at all.
Here is a great way to get started writing a new form... go to this page:
http://www.google.com/drive/apps.html?usp=ad_search
and scroll down to the "Forms" section then click on "Create".
This should walk you through everything you will need to set up the form, and the results will be put into a spreadsheet for you, along with the students' email addresses. You can keep the resulting spreadsheet private so that you will be the only one who can view all the responses.
I hope that helps.