Why does the script run 2 times? - google-apps-script

I need to know the holidays of a team. For this, everyone receives by mail a form with 4 questions:
- Mail address
- Name
- Beginning of the leave period
- End of the leave period
Typically, responses are sent in a spreadsheet.
The idea is to fill a calendar shared with the whole team so that everyone knows the periods of leave.
For this, here is the script to link to this worksheet:
function AjouteConge() {
var fichier = SpreadsheetApp.getActiveSpreadsheet();
var feuille = fichier.getActiveSheet();
var Ligne = fichier.getLastRow();
var RefCellule = "B"+Ligne+":E"+Ligne;
var Datas = fichier.getRange(RefCellule).getValues();
var Agenda = CalendarApp.getCalendarById('abcdefghijklmnopqrstuvwxyz123456789#group.calendar.google.com').createAllDayEvent(Datas[0][0], new Date(Datas[0][1]),new Date(Datas[0][2]));
}
I notice that my script runs 2 times when the form is completed.
So, I have 2 identical events in the agenda.
This is not (necessarily) the case when testing the script from the editor (not always anyway).
An idea ? Why is this script run 2 times?
Thank you for your clarifications

Can you check if multiple users have the same submit trigger set up on the Google Form? If yes, then you should delete the trigger from other accounts and leave only one.

Related

google apps script: Create a spreadsheet where newly created doc IDs appear

Be gently, very noob at this. So I've just replaced a guy who got a promotion and I am a primary teacher who has only really vaguely dabbled with this. I have successfully created a script that will do a lot of the things I need (so now looking to finish the job). My app script creates planner for teachers on a large cale so that they can have them labelled and the week goes in and changes the info.
Voila:
var fichier = DriveApp.getFileById('IDGOESHERE');
var newFichier=fichier.makeCopy("YOURGRADE LITERACY PLANNER TERM 1 WEEK 1");
var num=newFichier.getId();
var doc=DocumentApp.openById(num);
var body = doc.getBody();
doc.replaceText("abc123","TERM 1 WEEK 1");
It now works fairly well but I didn't know how to repeat it and then add one to the text, so I just copied it out heaps of times (one per each school week, not the end of the world). Any feedback here is welcome.
My real question though is this: I now need to go into each documents (there will be hundreds if not thousands) and link every document to our school website. My predecessor had the links in a sheet and just slipped them on to our website. Is there anyway of expanding the script so that it can publish the web address or even google doc ID of each newly created document into a spreadsheet (or text / doc).
This may not be possible, but if it were that would be amazing, would save me having to manually link all of the files week by week, one for each teacher over the year.
THANKS!
Yes, there is. After you create the doc there are 3 very useful methods you could call:
var name = doc.getName(); //returns the name in a string
var id = doc.getId(); //returns the id in a string
var url = doc.getUrl(); //returns a url to the document as a string
In the drive app, you will probably want to set the sharing permissions.
file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
You will then want to open a spreadsheet and append a new row for the data
sheet.appendRow([name, id, url]);

Google Apps Script to count number of emails received yesterday, that has certain label, then save # daily to spreadsheet

Basically what the title says, but I want to:
1) Automatically count the number of emails received to my gmail account, that has a certain label on it
2) Count once everyday, even if zero
3) And report daily to a Google Spreasheet
4) So I can make a monthly report like such:
Date / #
Date / #
Date / #
.
.
.
Total for October / #
Average per day / #
I'm sure this is piece of cake using Google Script for script gurus, but I have no clue. Please teach me!
Open a new Untitled spreadsheet and go to Tools -> open Script editor and paste the code given below.
function CountEmail()
{
var label = GmailApp.getUserLabelByName("LabelName");
var labelname = label.getName();
var mails = label.getThreads();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var date = new Date();
sheet.appendRow([labelname,date,mails.length]);
}
To run the script daily you will need to set a project trigger in the app script.For that follow the steps given below:
Resources -> Current Project's Trigger -> Add trigger -> Time driven -> Hour timer -> select the time when you want the script to run.
The total number of emails and the average emails/day can be calculated in the spreadsheet itself by just using the Sum() function.
Referencing the code Suyash Gandhi has posted (citing it here in case it gets removed so there is no confusion).
NOTE: not my code!!! Credit to Suyash Gandhi
function CountEmail()
{
var label = GmailApp.getUserLabelByName("LabelName");
var labelname = label.getName();
var mails = label.getThreads();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var date = new Date();
sheet.appendRow([labelname,date,mails.length]);
}
NOTE: not my code!!! Credit to Suyash Gandhi
See the picture below
What you see here are 2 threads, 1 email in the bottom one, 3 emails in the top one and 1 draft in the top one. That given code will return a 2 here. If you wish to count all 4 (or 5 if you want the draft) you will need to use Gmail API (see reference here).
I have a script that gets all emails (every message) for a specific time period and outputs the receive date, sender, recipient and title to a spreadsheet. This is the code that actually fetches the emails. The rest of the code is mostly creating files, generating the query string and reset the script if it runs too close to 6 minutes.
queriedMessages =
Gmail.Users.Messages.list(userInfo.mail,
{
'q': queryString,
'pageToken': execProperties.nextPageId
});
userInfo.mail is the email address you are fetching the emails from. This is simply written like this because the script can be run with any account
queryString is a string that is used to search for emails and is exactly the same as you use in the gmail search box. So you would have label:labelname
pageToken is a code of the page of the search (basically what is needed when you click the next page button in gmail). It is returned as part of this function so you would be able to access it from queriedMessages.nextPageToken. So if you get more than 1 page, then you will need it to access the rest of the messages.
Also, keep in mind that you are getting all the messages fitting the query, so if you do this daily, you may want to include a trigger. Also, keep in mind that functions firing from triggers ignore your timezone (known bug), but you can figure out how to create a query that works for only 1 day fairly easily. Personally I just grab +1 day on the beginning and the end and just filter those messages out.

Google Script to force new spreadsheet entries to start at Row 2 after running script to clear the range

I'm an elementary teacher with limited coding experience but I enjoy trying to figure things out if it simplifies my life. :)
I created a Google Form for my students to make their daily lunch choice.
I set up a script that has a trigger to clear the form between midnight and 1 am each night, and it looks like this:
function clearRange() {
//replace 'Sheet1' with your actual sheet name
var sheet = SpreadsheetApp.getActive().getSheetByName('Lunch');
sheet.getRange('A2:G25').clearContent();}
The script itself works - however, now, whenever new entries are added, they are added to the spreadsheet row right below where the old entries were cleared. Thus, if I have twenty students responding on Monday, the spreadsheet has rows 2-21 filled out, which get cleared sometime overnight Monday/Tuesday AM, and the next day, the responses fill rows 22-42, etc. etc.
How can I edit or add something to my script that forces it to put all new entries, after the old ones are cleared, on Row 2 of my spreadsheet?
If this question has already been answered, please point me in that direction as well.
Thank you!
Instead of clearing content from cells, you need to delete rows containing form submission.
Here is the modified code which should work for you. Also, make sure you do not have any frozen row/s.
function clearRange() {
//replace 'Sheet1' with your actual sheet name
var sheet = SpreadsheetApp.getActive().getSheetByName('Lunch');
//get last row, this will be used to count how many rows to delete
var lr = sheet.getLastRow();
//delete row from 2 to last row
sheet.deleteRows(2, lr-1);
}
You're using the .clearContent() method and Google Forms keeps track of the responses based on the row in your spreadsheet, you need to delete the row completely using deleteRows(rowPosition, howMany), like this:
function clearRange() {
//replace 'Sheet1' with your actual sheet name
var sheet = SpreadsheetApp.getActive().getSheetByName('Lunch');
sheet.deleteRows(2, 25);
}
Note: This will not restart the counter you see in the Google Forms user interface:
In order to do that, you will need to use the deleteAllResponses() using the FormApp Class

How to show in Google Form value from Google Spreadsheet

I have connected Google Spreadsheet with Google Form but I don't know, how can I include values from Spreadsheet to Form and display them (which will be in my scenario free left space for course registration).
explanation picture: https://drive.google.com/file/d/0B4HOotJEv18lLTNiY3ZmcGl3T3M/view?usp=sharing
Expected outcome: course has 30 free seats for students and I want to show in my Google Form, how many free seats lefts for course registration.
Many thanks for your help, also script example will be very welcome.
You can create the form in AppScript with Forms Service and set the questions and choices in the script. Within the script you can also reference a Spreadsheet, so you should be able to read the data from a spreadsheet and put it onto a form that way.
Haven't actually tried it, but it'd probably look something like:
var form = FormApp.create('New Form');
var item = form.addCheckboxItem();
var ss = SpreadsheetApp.openById("<ID>");
var val = ss.getRange(<RANGE>).getValue();
item.setTitle('Question ' + val + ' Question');
item.setChoices([
item.createChoice('ONE'),
item.createChoice('TWO'),
item.createChoice('THREE')
]);
You can also check out this Quickstart and Video.

google script reject spreadsheet submit

I have a function in a spreadsheet based script that is triggered when a submission is made with the spreadsheet form :
function onEntry(e){
Logger.log(e);
MailApp.sendEmail("scriptadmin#uniben.edu", "New Mail Request", "Someone submited data");
}
How can I reject the entry, say if it's a duplicate entry ?
Using the documentation on events you will have to choose what data you want check (user name, specific field...) and compare that to data already in the spreadsheet.
You should do these iterations on an array level since it will be far more efficient and fast, you can get data in an array using something like
var data = SpreadsheetApp.openById(key).getDataRange().getValues();
You could also use javascript function like indexOf() that will return -1 if no match if found or item position in the array if a match is found.
Actually there are many ways to do that but your question is too vague to know what will be the best...
EDIT : following your comment, I'd suggest you let the duplicate form data come into the sheet and then use a script to remove duplicates. You could run this script on a on form submit trigger or on a timer to let it run daily or hourly, and send the email only if the last entry was a new one (no duplicates found)... depending on your use case.
There is a script in the gallery that does the job pretty well, it was written by Romain Vialard, a GAS TC that has contributed a lot. (the link above goes to the script description but you can get it also in the public gallery, just search for 'remove duplicates' you'll see that other scripts do that, all the scripts in the gallery have been checked by the GAS team)
4 months late, but better late than never. I believe this function does almost what was originally requested. i.e. "How do I prevent the entry from entering the spreadsheet if I decide that it's a duplicate." It is not precisely what was requested, but very close.
This code checks one column against that same column in another sheet, for all rows in that sheet. Lets say you have a list of companies or clients on a sheet. That list includes name, phone, address, etc. etc. Lets say you want to check against the phone number - if the phone number you are currently entering is already on your client sheet, then don't allow entry - or more precisely clear it out immediately upon entering it.
I'm sure the more experienced members will be able to point out flaws, but it works for me.
I believe it will also work for the case where a phone number in the middle of the sheet is changed - so it's not just last line that gets checked, it's the line that gets edited that gets checked - I've not tested this particlar scenario. Also, I made some changes to variable names to protect the innocent...hopefully I didn't mess anything up while doing that.
I call this function from within another function that is triggered by onEdit. Theoretically it should be able to be installed as an onEdit trigger itself. I hope someone finds it useful.
function checkNewEntryForDuplicate(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var entrySheet = SpreadsheetApp.getActiveSheet();
var clientSheet = ss.getSheetByName("Clients");
var r = entrySheet.getActiveCell();
var lastCol = entrySheet.getLastColumn();
// If this had any consistency, we'd be able to get the row from entrySheet the same
// as we get column. But there is no getRow() method at the sheet level.
var rowNum = r.getRow();
var clientData=clientSheet.getDataRange().getValues();
var phoneColumnOffset=getPhoneColumnOffset(); // You'll need to get the offset elsewhere. I have a function that does that.
var columnNum=e.range.getColumn(); // column that is currently being edited
if (columnNum != phoneColumnOffset+1) // no point in doing anything else if it's not the column we're interested in.
return 0;
var entryRow=entrySheet.getRange(rowNum, 1, 1, lastCol);
var phoneNum = e.range.getValue();
// iterate over each row in the clientData 2-dimensional array.
for(i in clientData){
var row = clientData[i];
var duplicate = false;
// For each row this conditional statement will find duplicates
if(row[phoneColumnOffset] == phoneNum){
duplicate = true;
var msg="Duplicate Detected. Please do not enter. Deleting it..."
Browser.msgBox(msg);
entryRow.clearContent();
entryRow.clearComment();
return duplicate;
}
}
return duplicate;
}
I am doing the same things but having no scripts at all and just by spreadsheet functions. That kind of things are just like SQL for me and very interest to do.
For your question, this link will help: http://www.labnol.org/software/find-remove-duplicate-records-google-docs/5169/