I'm trying to build an Approval flow with Google Apps Script. I would also like to add an "if" cycle that creates a Calendar event if e.parameter.approval is true.
So, everything works but the system doesn't recognize the "if" cycle. I've tried this:
function doGet(e){
var answer = (e.parameter.approval == 'true') ? 'Approved!' : 'Not this time';
MailApp.sendEmail(e.parameter.reply, "Request",
"The answer is: "+ answer);
// here I tried both with (e.parameter.approval === 'true') and (check === answer) and also with "=" "==" and "==="...
var check = 'Approved!';
if(e.parameter.approval === 'true'){
var calendar = CalendarApp.getCalendarById('xxxxxxx')
//create event
var newEventTitle = 'Event Test';
var newEvent = calendar.createAllDayEventSeries(newEventTitle,
Date,
CalendarApp.newRecurrence().addDailyRule().times(10),
{description:'test'});
//get ID
var newEventId = newEvent.getId();
}
var app = UiApp.createApplication();
app.add(app.createHTML('<p><br><h2>An email was sent to '+ e.parameter.reply + ' saying: '+ answer + '</h2>'))
return app
}
Do you have any idea why the system skips the "if" cycle and goes directly to "var app"?
e.parameter.approval might not be returning anything. I could be "undefined". It could be "null". You need to know for sure what e.parameter.approval is doing. There is also the possibility that the if condition is actually working, but then there is an error that kills the code and stops it. You'll need to debug every line. Try using the "debug" tool.
Apps Script Debugging Tool
You are using:
if(e.parameter.approval === 'true'){
The word 'true' is in quotes, which means it's a string value, not a true/false value.
Try:
if(e.parameter.approval === true){
Related
A previously working solution that was resolved here by #tanaike suddenly returns an empty cell upon execution. I don't get an error message and in the google apps scripts edit page I get "Notice Execution completed".
It looks like it's working in the background but having trouble returning a value to the cell, my guess would be something wrong with the last line that may resolve it?
function pressReleases(code) {
var url = 'https://finance.yahoo.com/quote/' + code + '/press-releases'
var html = UrlFetchApp.fetch(url).getContentText().match(/root.App.main = ([\s\S\w]+?);\n/);
if (!html || html.length == 1) return;
var obj = JSON.parse(html[1].trim());
// --- I modified the below script.
const { _cs, _cr } = obj;
if (!_cs || !_cr) return;
const key = CryptoJS.algo.PBKDF2.create({ keySize: 8 }).compute(_cs, JSON.parse(_cr)).toString();
const obj2 = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(obj.context.dispatcher.stores, key)));
var res = obj2.StreamStore.streams["YFINANCE:" + code + ".mega"].data.stream_items[0].title;
// ---
return res || "No value";
}
The CryptoJS code saved as a script in google apps script is here
When I tested this script, at if (!_cs || !_cr) return;, I confirmed that the values of _cs and _cr are undefined. From this result, I understood that recently, the specification of the key for decrypting the data has been changed at the server side. When I saw this thread, I confirmed the same situation. In the thread, I noticed that, in the current stage, the key can be simply retrieved from the HTML data. So, as with the current script, how about the following modification?
Usage:
1. Get crypto-js.
Please access https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js. And, copy and paste the script to the script editor of Google Apps Script, and save the script.
2. Modify script.
function pressReleases(code) {
var url = 'https://finance.yahoo.com/quote/' + code + '/press-releases'
var html = UrlFetchApp.fetch(url).getContentText().match(/root.App.main = ([\s\S\w]+?);\n/);
if (!html || html.length == 1) return;
var obj = JSON.parse(html[1].trim());
var key = Object.entries(obj).find(([k]) => !["context", "plugins"].includes(k))[1];
if (!key) return;
const obj2 = JSON.parse(CryptoJS.enc.Utf8.stringify(CryptoJS.AES.decrypt(obj.context.dispatcher.stores, key)));
var res = obj2.StreamStore.streams["YFINANCE:" + code + ".mega"].data.stream_items[0].title;
// console.log(res); // Check the value in the log.
return res || "No value";
}
When this script is run with code = "PGEN", the value of Precigen Provides Pipeline and Corporate Updates at the 41st Annual J.P. Morgan Healthcare Conference is obtained.
Note:
If you want to load crypto-js directly, you can also use the following script. But, in this case, the process cost becomes higher than that of the above flow. Please be careful about this.
const cdnjs = "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js";
eval(UrlFetchApp.fetch(cdnjs).getContentText());
I can confirm that this method can be used for the current situation (January 14, 2023). But, when the specification in the data and HTML is changed in the future update on the server side, this script might not be able to be used. Please be careful about this.
Reference:
crypto-js
I wrote the code below about a month ago. All it does it highlight the row when the checkbox is checked and clears it when unchecked. It was working fine, now it's not and I did not change anything.
In the executions section I can see it failing with:
Exception: The parameters (String,number,number,number) don't match the method signature for SpreadsheetApp.Spreadsheet.getRange.
at onEdit(Code:43:55)
and
Exception: The parameters (String,number,number,number) don't match the method signature for SpreadsheetApp.Spreadsheet.getRange.
at onEdit(Code:44:56)
Clearly it thinks that the variable "editRow" is a string but I have no idea why it does now and didn't before. 43:55 and 44:56 are the if statements for TRUE and FALSE, this code is clipped from all the rest (other things not relivant).
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();var sheet = ss.getSheetByName("Form Responses 1")
var editRange = sheet.getActiveRange();var editRow = e.range.rowStart;var editColumn = e.range.columnStart;var editValue = e.value;
var sheet = SpreadsheetApp.getActiveSpreadsheet();var formResponses = sheet.getSheetByName ("Form Responses 1");
if(ss.getActiveSheet().getName() == "Form Responses 1"){}
else{return};
if (editValue == "TRUE" && editColumn == 20) {sheet.getRange(editRow,1,1,21).setBackground("yellow")};
if (editValue == "FALSE" && editColumn == 20) {sheet.getRange(editRow,1,1,21).setBackground(null)};
}
The error messages says that e.range.rowStart and e.range.columnStart are returning a string rather than a number. That string might occurr, among other possibilities, if they are undefined i.e. because onEdit is triggered by something that provides a range property but that hasn't rowStart and columnStart properties.
Add console.log(JSON.stringify(e)); after function onEdit(e){ so you could see in the logs the values properties of e.
I started commenting out lines that did other things in the onEdit function. I narrowed it down to these lines that set variables for an email that is sent. It does not edit any of the already established variables, just makes new ones.
I do not understand why commenting these lines out allows it to work but it does. I was able to move them to below the lines that were erroring out and it's working again.
var recipient = formResponses.getRange("E"+editRow).getValue();
var subject = "Chromebook " + formResponses.getRange("B"+editRow).getValue() + " was marked as returned";
if (formResponses.getRange("H"+editRow).getValue() === ''){
var body = "Chromebook " + formResponses.getRange("B"+editRow).getValue() + " was marked as returned. Action taken: Returned from //ITSavvy"
}
else{var body = "Chromebook " + formResponses.getRange("B"+editRow).getValue() + " was marked at returned. Action taken: " + formResponses.getRange("H"+editRow).getValue()};
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()
I have some code where there are some if/else if statements to determine the reason that a Google Form has closed. I want to pass this reason to another function which will send an email notifying me that the form has closed and the why. I don't know why the reason, which should be a string, is not getting passed to the function that sends the email.
I'm not dealing with the form at all in this code. For simplicity, I opened a new standalone script, not linked to any Google Form or Sheet, to test just this portion (determine reason and send email). Here is the code:
First function to determine reason the form closed and to call second function to send email:
function FindReason() {
var Day1Seats = 5;
var Day2Seats = 5;
var Day1Responses = 6;
var Day2Responses = 1;
var FormClose = false;
if(Day1Responses >= Day1Seats) {
var reason = "All seats taken for Day 1";
SendAnEmail(reason);
}
else if(Day2Responses >= Day2Seats) {
var reason = "All seats taken for Day 2";
SendAnEmail(reason);
}
else if(FormClose) {
var reason = "Form close date";
SendAnEmail(reason);
}
}
Second function, which sends email (email address obviously changed for privacy):
function SendAnEmail(closereason) {
var recipientTO = "name#example.com";
var subject = "This is the subject";
//var closereason = "All seats taken for Day 1";
MailApp.sendEmail({
to: recipientTO,
subject: subject,
htmlBody: (new Date()) + "<br>Your form has been closed because: <br>" + closereason + "<br>End of message."
});
}
When I run FindReason(), I do get an email but the body doesn't properly show the reason. This is an example of the emails I get:
Sun Feb 24 2019 12:26:01 GMT-0800 (PST)
Your form has been closed because:
undefined
End of message.
I don't know why the reason is shown as undefined. I tried setting the reason inside the SendAnEmail function (the line that has been commented out) and that worked properly, but I need to be able to change the reason.
Edit: It works now. It turns out the "run" button was set to run the "SendAnEmail" function rather than the "FindReason" function. Thanks to everyone who offered suggestions.
What's probably happening is that else if(FormClose = TRUE) is not going to work.
= is the assignment operator, you want equality, which is ===.
TRUE is lowercase in js, so you want true.
You also use False, which should be false.
If you look in the google scripts editor's console, you should see an error of some sort, because it won't know what False or TRUE are (it will think they are undeclared variables).
try else if(FormClose === true) or even more simply, else if (FormClose), because if it evaluates to true, that will do the job.
function FindReason() {
var Day1Seats = 5;
var Day2Seats = 5;
var Day1Responses = 6;
var Day2Responses = 1;
var FormClose = false;
if(Day1Responses >= Day1Seats) {
var reason = "All seats taken for Day 1";
SendAnEmail(reason);
} else if(Day2Responses >= Day2Seats) {
var reason = "All seats taken for Day 2";
SendAnEmail(reason);
} else if(FormClose) {
var reason = "Form close date";
SendAnEmail(reason);
}
}
I recently adapted a short piece of script to automatically send an e-mail to me when a specific response appears (the word FAIL) in a 'Google docs' spreadsheet, that collects responses from volunteers using a 'Google Form' to record their weekly checks on life-saving equipment.
The email on FAIL is working well, having tested it with a few FAIL responses. However, as the form 'owner' I am receiving notifications from Google, for each normal PASS response submitted, telling me that the script failed to finish successfully.
8/4/15 10:57 AM
SendGoogleForm
ReferenceError: "found" is not defined. (line 35, file "Code")
formSubmit
It finishes successfully if a FAIL response is submitted, so I suspect that, due to my inexperience with scripts, I have not defined what should happen when found is 'not true'.
It's probably glaringly obvious to a more experienced script writer but none of the things I have tried with 'Else' seem to work.
Any suggestions would be greatly appreciated.
function Initialize() {
var triggers = ScriptApp.getProjectTriggers();
for (var i in triggers)
ScriptApp.deleteTrigger(triggers[i]);
ScriptApp.newTrigger("SendGoogleForm")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit().create();
}
function SendGoogleForm(e) {
if (MailApp.getRemainingDailyQuota() < 1) return;
// Recipients email address
var email = "12345#abcde.co.uk";
// Subject for Google Form email notification
var subject = "Weekly Checks - FAIL Submitted";
var s = SpreadsheetApp.getActiveSheet();
var columns = s.getRange(1, 1, 1, s.getLastColumn()).getValues()[0];
var message = "A check form has been submitted containing a ** FAIL ** response: ";
// Look for a 'FAIL' response
var key = columns[keys];
for ( var keys in columns ) {
if ( e.namedValues[columns[keys]] == 'FAIL') {
found = true;
}
}
// Only include form fields that are not blank
if (found)
for (var keys in columns) {
var key = columns[keys];
if (e.namedValues[key] && (e.namedValues[key] !== "")) {
message += key + ' : ' + e.namedValues[key] + "\n\n";
}
}
MailApp.sendEmail(email, subject, message);
}
Your found variable is null whenever a non-"FAIL" occurs in your script and I think your if(found) is creating the error message.
You could Initialise your variable:
var found = false;
before you start testing it. That way, your if(found) will be false and it will skip down to your send email code.
Perhaps u can use
if ( e.namedValues["Pass or Fail"] == "Fail" ) { ... }
where "Pass or Fail" is the form question title. And also use e.range.getRow() to capture the sheet row that the responses were written.