Google Apps Script Compare Active User to Array - google-apps-script

Not sure why this isn't working. I have a simple script that grabs the active user and checks to see if they are in an array of allowed senders. If they are, then it runs another function sendEmail(). If they are not in the array, then it throws an error.
function send(){
var ValidEmailsArray = ['email1#gmail.com', 'email2#gmail.com', 'email3#gmail.com']; //can be any number of emails.
var ActiveUser = Session.getActiveUser().getEmail();
for (var i = 0; i < ValidEmailsArray.length; i++){
if (ActiveUser.indexOf(ValidEmailsArray[i]) == -1) {
throw new Error('Woah! You must send the email from the ' + ValidEmailsArray + ' account.');
}
else {
sendEmail();
return;
}
}
As it is now, it throws the error even if the ActiveUser is in the ValidEmailsArray.
Any help would be much appreciated. Thanks!

Issue:
ActiveUser is of type string.
if (ActiveUser.indexOf(ValidEmailsArray[i]) == -1) {throw new Error
says that if ActiveUser doesn't contain the first email address in ValidEmailsArray, throw a error.
Solution:
Use Array#includes instead of a loop.
Snippet:
function send(){
const validEmailsArray = ['email1#gmail.com', 'email2#gmail.com', 'email3#gmail.com']; //can be any number of emails.
const activeUser = Session.getActiveUser().getEmail();
if(validEmailsArray.includes(activeUser)) sendEmail()
else throw new Error("?!")
}

Related

Adding a tag to an email file creates an error

I created a script that receives last minute emails if they do not contain a "a" tag and sends the content of the message to a function I called "ssfunction" and then adds the "a" tag to it
And this is the script I made:
const threads = GmailApp.search('-{label:a}');
for (const thread of threads) {
const messages = thread.getMessages();
const minuteAgo = new Date(Date.now() - 60000);
if (thread.getLastMessageDate() > minuteAgo) {
for (const message of messages) {
if (message.getDate() > minuteAgo) {
const result = ssfunction(message);
didUpload = result || didUpload;
}
}
thread.addLabel("a");
} else {
const result = ssfunction(messages[messages.length - 1]);
didUpload = result || didUpload;
thread.addeLabel("a");
}
But I get such an error:
TypeError: thread.addeLabel is not a function
Thank you so much for all the willingness to help
In your script, I thought that the method name of addeLabel is required to be modified to addLabel. I think that this is the reason of your error message. And, in the case of addLabel, the argument is GmailLabel object. When these points are reflected in your script, it becomes as follows.
From:
thread.addeLabel('a');
To:
var label = GmailApp.getUserLabelByName("a");
thread.addLabel(label);
Refernce:
addLabel(label)

Two App scripts running on Forms and Sheets, need to connect them both

I have an onboarding form that puts all the responses in a google sheet which has an app script running to add user to google admin and different groups by taking in values from the last row of the sheet. That works fine, it's just that I have to run the script every time the form is filled so I want to create a form trigger.
It made sense to create a form submit trigger on the app script attached to the google form and I added the library and script id of the other appscipt and pulled in a method from there like such
// Create a form submit installable trigger
// using Apps Script.
function createFormSubmitTrigger() {
// Get the form object.
var form = FormApp.getActiveForm();
// Since we know this project should only have a single trigger
// we'll simply check if there are more than 0 triggers. If yes,
// we'll assume this function was already run so we won't create
// a trigger.
var currentTriggers = ScriptApp.getProjectTriggers();
if(currentTriggers.length > 0)
return;
// Create a trigger that will run the onFormSubmit function
// whenever the form is submitted.
ScriptApp.newTrigger("onFormSubmit").forForm(form).onFormSubmit().create();
}
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
function onFormSubmit() {
wait(7000);
AddingUserAutomation.createUserFromSheets()
}
The trouble is I get the error
TypeError: Cannot read property 'getLastRow' of null
at createUserFromSheets(Code:43:19)
My createUserFromSheets function is taking the active sheet
function createUserFromSheets(){
let data = SpreadsheetApp.getActiveSheet();
let row = data.getLastRow();
let firstname = data.getRange(row,2).getValue();
let lastname = data.getRange(row,3).getValue();
... etc etc
}
I think it is unable to pull the getActiveSheet part that is why I had added the wait() function on formSubmit() but it still would not work.
Is there a way to solve this or a better way to do it?
function createWorkspaceUser(recentResponse) {
console.log("Creating account for:\n"+recentResponse[1]);
debugger;
var user = {"primaryEmail": recentResponse[0] + '.' + recentResponse[1] + '#' + recentResponse[3],
"name": {
"givenName": recentResponse[0],
"familyName": recentResponse[1]
},
"password": newPassword(),
};
try {
user = AdminDirectory.Users.insert(user);
console.log('User %s created with ID %s.', user.primaryEmail, user.id);
}catch(err) {
console.log('Failed with error %s', err.message);
}
}
I am doing it this way but it's running an error on primaryemail
Suggestion [NEW UPDATE]
As mentioned by RemcoE33
To have a more simplified setup, perhaps skip the library part and do all the scripting (bound script) in your Google Form itself.
Since we don't have the complete overview of your actual Google Form. See this sample below as a reference:
Google Form Script
function onFormSubmit() {
var form = FormApp.getActiveForm();
var count = 0;
var recentResponse = [];
var formResponses = form.getResponses();
for (var i in formResponses) {
count += 1;
var formResponse = formResponses[i];
var itemResponses = formResponse.getItemResponses();
for (var j = 0; j < itemResponses.length; j++) {
if(formResponses.length === count){ //Process only the recently submitted response
var itemResponse = itemResponses[j];
recentResponse.push(itemResponse.getResponse())
}
}
}
createWorkspaceUser(recentResponse);
}
function createWorkspaceUser(recentResponse){
var user = {"primaryEmail": recentResponse[0].replace(/\s/g, '') + '.' + recentResponse[1].replace(/\s/g, '') + '#' +recentResponse[3],
"name": {
"givenName": recentResponse[0],
"familyName": recentResponse[1]
},
"password":newPassword(),
};
try{
user = AdminDirectory.Users.insert(user);
Logger.log('User %s created with ID %s.', user.primaryEmail, user.id);
}catch (err) {
Logger.log('Failed with error %s', err.message);
}
console.log(user);
}
NOTE: You no longer need to build an on form submit trigger since the onFormSubmit() function will automatically run right after hitting the submit button.
Demonstration
1. Submit user data from sample form:
2. Test user account will be created on Workspace Admin Console Users:
Reference
https://developers.google.com/apps-script/reference/forms/form-response
https://developers.google.com/apps-script/guides/triggers

How do I create a pop up authorization for my Google Web App

I'm new to Web Scripts and deploying web apps, I have an issue where I require users to authorize permission to use the web app, but nothing pops up to request for said authorization.
I found this post here and it seems to be what I needed but I'm unsure how would I use it. I tried calling onOpen function at the start of my doGet but nothing happens. I also don't see where/when the authorize function is being called. My Web App is also using sheets, so I deleted any lines of code dealing with DocumentApp.
Here is my modified version of the code
function onOpen() {
if(!UserProperties.getProperty('author')){
var html = HtmlService.createHtmlOutputFromFile('index1')
.setTitle("Install Menu").setWidth(400);
}else{
var html = HtmlService.createHtmlOutputFromFile('index2')
.setTitle("Mailmerge Menu").setWidth(400);
}
}
function authorize(){
UserProperties.setProperty('author','yes');
var html = HtmlService.createHtmlOutput('Authorization complete<br>Thanks<br><br>please refresh your browser').setTitle("Confirmation").setWidth(400);
}
This is my doGet function just in case I was not utilizing the functions correctly.
function doGet(e)
{
onOpen();
var result;
var sheets = SpreadsheetApp.getActiveSheet();
var values = [];
// Get row 1 data
for( var i = 3; i <= 16; ++i)
{
var char = String.fromCharCode('A'.charCodeAt() + i) // Increment char
values.push(sheets.getRange(char + 1).getValue());
}
// Get row 2 data
for( var i = 3; i <= 16; ++i)
{
var char = String.fromCharCode('A'.charCodeAt() + i) // Increment char
values.push(sheets.getRange(char + 2).getValue());
}
var result = {result:values};
var JsonValue = JSON.stringify(result);
return ContentService.createTextOutput(JsonValue.toString()).setMimeType(ContentService.MimeType.JSON);
}
I know I can set the web app to execute as me by anyone, which does work, but I would like be able to allow other users to authorize themselves to execute the app.
Edit:
I'm using Unity's WebRequest class to call the Get from my web app.
_webRequest = UnityWebRequest.Get("web app url here");
_webRequest.SendWebRequest();
And on receiving the response I will parse it and use the data in "result" in a separate class
if (_webRequest != null && _webRequest.isDone)
{
result = JsonUtility.FromJson<WebResponsePacket>
(_webRequest.downloadHandler.text);
Debug.Log("Successful Request");
return true;
}

Submitting a Google Form via Google Apps Script fails if Form is set to collect email

When submitting a form via Apps script, if the form is set to collect the user e-mail for responses, then the code fails with error:
"Sorry, the form response could not be submitted. Please wait a few
minutes and try again."
I think Google may have changed something as the code that worked last year is not working this year.
The error points at the "submit" line in the code. OR sometimes, the code runs, but still nothing appears in the sheet, or in the "responses" in the form itself.
If I turn off the option to collect e-mail, it runs fine and I see the submission in the Google sheet, just without an e-mail address.
I setup a test form, attached it to a new google sheet for responses, and pasted in my code:
function codeVoteDoVoteByForm()
{
// Get the Yes/No Google form
var myForm = FormApp.openById('File ID Here')
// Get a list of questions on it
var questions = myForm.getItems()
// Get question 0 (only one on this form) and mark it as multiple choice
var qt = questions[0].asMultipleChoiceItem()
// Set the users vote
var qr = qt.createResponse("I am here")
//Create the response
var FormResponse = myForm.createResponse()
var testemail = FormResponse.getRespondentEmail()
// Submit the response
FormResponse.withItemResponse( qr );
var myResponse = FormResponse.submit()
var responseString = myResponse.getTimestamp()
return "Vote recorded at " + responseString
}
My thought is that Google changed something, so now when running a script it's not able to get the users e-mail address for the formresponse, but I can't find any documentation to confirm this.
Any thoughts?
I think that the problem is when you are sending a reponse to a form that have collect email or authenticated user restrictions, without adding an email or authenticating the user. Unfortunely, I think that is not possible to send this sort of information with the API, so in my case:
I have disabled the restrictions, next
I have sent the response to the form, and finally
I enable the restrictions again
//disable restrictions temporaly
form.setLimitOneResponsePerUser(false);
form.setRequireLogin(false);
form.setCollectEmail(false);
var questions = form.getItems();
var formResponse = form.createResponse();
for (var i=0; i<questions.length; i++){
var question = questions[i].asMultipleChoiceItem();
var response = question.createResponse(correctAnswers[i]);
formResponse.withItemResponse(response);
}
formResponse.submit();
form.setLimitOneResponsePerUser(true);
form.setRequireLogin(true);
form.setCollectEmail(true);
This function will first check the question type:
function autoFormResponse_(formId) {
var form = FormApp.openById(formId);
//disable restrictions temporaly
form.setCollectEmail(false);
// answer questions
var questions = form.getItems();
var formResponse = form.createResponse();
var required_list = [];
for (var i=0; i<questions.length; i++){
// release required questions
var question = getQuestionItemAs_(questions[i]);
if (question.isRequired())
{
question.setRequired(false);
required_list.push(question);
}
}
// submit
formResponse.submit();
// restore required questions
form.setCollectEmail(true);
for (var i = 0; i < required_list.length; i++)
{
required_list[i].setRequired(true);
}
// return last response
var responses = form.getResponses();
return responses[responses.length - 1];
}
Helper function:
function getQuestionItemAs_(item)
{
var type = '' + item.getType();
switch (type) {
// https://developers.google.com/apps-script/reference/forms/item-type
case 'CHECKBOX': return item.asCheckboxItem();
case 'CHECKBOX_GRID': return item.asCheckboxGridItem();
case 'DATE': return item.asDateItem();
case 'DATETIME': return item.asDateTimeItem();
case 'DURATION': return item.asDurationItem();
case 'GRID': return item.asGridItem();
case 'IMAGE': return item.asImageItem();
case 'LIST': return item.asListItem();
case 'MULTIPLE_CHOICE': return item.asMultipleChoiceItem();
case 'PAGE_BREAK': return item.asPageBreakItem();
case 'PARAGRAPH_TEXT': return item.asParagraphTextItem();
case 'SCALE': return item.asScaleItem();
case 'SECTION_HEADER': return item.asSectionHeaderItem();
case 'TEXT': return item.asTextItem();
case 'TIME': return item.asTimeItem();
case 'VIDEO': return item.asVideoItem();
default: return false;
}
}

Checking If GmailApp.sendEmail() Is Running

I'm trying to run a script to send automated emails to a list of people (I needed to edit out a bit of information).
function sendEmail(){
for (var key in emailBank){
var email = getEmail(key);
var bodyText = emailBank[key]['body'];
var commitmentType = emailBank[key]['type'];
GmailApp.sendEmail(key,"Subject Line", bodyText {htmlBody:bodyText});
}
}
I'm using an array (emailBank) to store information from a spreadsheet before sending it out. The function should loop through and send each person an email.
On occasion, I'm getting the following error: "We're sorry, a server error occurred. Please wait a bit and try again." for the line including GmailApp.
Can you think of any to verify if an email is sent or not? My concern is that half of the emails will be sent and half will not, so I wouldn't know who actually received the email and at which point the loop stopped.
Any ideas are appreciated here!
Ok, so I think I found a solution to this after trying out a few methods:
// Variables for error checking later
var emailRecipients = "";
var trueRecipients = "";
//The sendEmail function to send the email as expected
//It will also increment the emailRecipients variable
//only after the email has been sent
function sendEmail(){
for (var key in emailBank){
var email = getEmail(key);
var bodyText = emailBank[key]['body'];
var commitmentType = emailBank[key]['type'];
GmailApp.sendEmail(key,"Subject Line", bodyText {htmlBody:bodyText});
emailRecipients += key + "<br>";
}
}
//This function will only run if there was an error
//It will check increment all of the email addresses
//that should have been sent a message and then send me an
function errorEmail(){
for (var key in emailBank){
trueRecipients += key + "<br>";
}
var errorBodyText = "Emails sent to:<br><br>" + emailRecipients + "<br><br>Number of emails that should have sent:<br><br>" + trueRecipients;
GmailApp.sendEmail("example#gmail.com","Email Errors", errorBodyText,{htmlBody:errorBodyText});
}
function reminderEmail(){
try{
sendEmail();
}
catch(e){
errorEmail();
}
}
As a temporary solution, you could check the last sent email after calling sendEmail() method.
/* the search() method returns an array of GmailThread objects.
Pop() returns the GmailThread */
var threads = GmailApp.search("label: sent", 0, 1).pop(); // returns the most recent thread in 'Sent Mail'
var msg = threads.getMessages().pop(); //returns the most recent message
Logger.log(msg.getId()); //returns unique id for the message
Logger.log(msg.getTo()); //returns comma-separated list of recipients
One option would be to store the message id and check if it changes on each run of the loop. You may also directly compare email properties, e.g. the recipient's email, against the properties of the message you sent.