Sender information in CalendarApp.CalendarEvent - google-apps-script

I'm a bit baffled! Many of my customers send me GCal invites but the creator shows up as me. I want to extract the actual sender address from the CalendarEvent. See screen shot as an example. Kathryn is the sender but I am listed as the sender.
Sample screen shot showing different sender vs. creator

Issue:
The main name that is displayed in the UI refers to the organizer of the event, which isn't necessarily the same as the event creator (for example, the event creator might call Events: move to move the event to another calendar, changing the event's organizer - see Organizers).
Solution:
You can retrieve the event organizer if you use Calendar API (I don't think that's possible with Apps Script Calendar service, since GuestStatus doesn't seem to return OWNER in all appropriate cases, at least from my experience).
An easy way to use the API in Apps Script is to use the Advanced Calendar Service (in order to use that, you'll have to enable the advance service first).
Then, using the API you could:
Use Events.list to list the events in your desired calendar according to a time range, as you are already doing with CalendarApp.
Retrieve your desired event.
Access the field organizer of your event, which contains the organizer's email address as well as other information about this user.
Code sample:
function getOrganizer() {
const calendarId = "YOUR_CALENDAR_ID";
const optionalArgs = {
"timeMin": "2021-05-17T00:00:00-02:00", // Change accordingly, min end time to filter
"timeMax": "2021-05-19T00:00:00-02:00" // Change accordingly, max start time to filter
};
const events = Calendar.Events.list(calendarId, optionalArgs)["items"];
const event = events[0];
const organizer = event["organizer"];
console.log(organizer);
const organizerEmailAddress = organizer["email"];
console.log(organizerEmailAddress);
}

Related

Query text for organizer email address in calendar events list

I've been struggling with a specific requirement where I need to return all events in a users primary calendar where that user is the organiser of the event to either delete the events or transfer them all to another user.
I can get all events in a users primary calendar regardless of the owner and then loop through them to pick out the events where organizer.email = user#domain.com but this is not the most efficient way of doing it. I would expect the api to be able to return results only where the organizer = user using the query string as per https://developers.google.com/calendar/v3/reference/events/list
var events = Calendar.Events.list(calID, {
maxResults: 250,
pageToken: PageToken,
q: 'email:"user#domain.com"'
});
I have used q: 'email:"user#domain.com"' which returns all events where the email address is the creator, organizer or attendee.
I have tried a few variations like q: 'organizer.email:" etc but it would be great if there were some documentation like there is for other apis that can use query strings.
https://developers.google.com/admin-sdk/directory/v1/guides/search-groups
I'd expect to be able to specify a query along the lines of q: "organizerEmail:user#domain.com" which will only return the events where this user is the organizer.
Does anybody know what the query string would be to achieve this?
I have also asked this on the Google Calendar API Google groups forum.

Use triggers to send emails based on time submitted by user

I have users subscribing to a mail service using google forms and they indicate how often they would like to receive an email, the value is recorded on a cell(ex.: every 1h, 2h ...).
I would like to loop through each user email and send a message based on the time they chose. Is there a way to do it with triggers?
Here is what I got so far:
function sendMail(){
for (i=2;i<=lastEmailRow;i++){
var currEmail = recipients.getRange(i, 2).getValue();
var currentTrigger = recipients.getRange(i, 3).getValue(); //how often
currentTrigger = currentTrigger.split(" ")[1];
MailApp.sendEmail(currEmail, "myEmail#sample.com", "Your Daily Mail",
{ htmlBody: HTML});
}
}
If your script is working fine (I'm not sure as lastEmailRow isn't defined on the question code) you have to make some design decisions, like if you will be using only one function or you will be using multiple functions, one for each frequency.
Depending on the above decision, then you could
create one time-driven trigger that runs very often, let say every hour
create several time-driven triggers, each with it's own settings.
In any case, you should include some conditions to control to whom send the email.

How do I construct a link to a Google Calendar event?

If I have the event ID of a Google Calendar event, for example:
4htgpmm1hmak744r0kbkdcodar#google.com
How can I construct a URL to view the event details in the Google Calendar interface?
For example, if I go to a google calendar event, I see a URL such as this:
https://calendar.google.com/calendar/r/eventedit/NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw
What function/algorithm can I run to go from 4htgpmm1hmak744r0kbkdcodar#google.com to NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw?
Bonus: A bonus would be if there was also a shortcut method that worked on a CalendarEvent via Google Apps Script. For example, if there was a method such as getUrl() just like there is a getId() method.
Since the same event can exist in multiple calendars (e.g. by inviting others to it), the event id is not sufficient information.
To construct a URL you need both the event id (refresher for how find it), AND the Calendar ID (see below for instructions as to how to find it). You'll then need to encode both as base64, and finally you'll you have a valid Google Calendar event link.
For the following instructions, imagine we have an event, Event1, and it exists in both calendars, CalendarA and CalendarB.
In the Google Calendar interface, you would be able to view any of these combinations:
Event1 in CalendarA
Event1 in CalendarB
Let's assign the following IDs:
Event1 ID: 4htgpmm1hmak744r0kbkdcodar#google.com
CalendarA ID: eugu9kan1ddi1pmi6sk3ib56g#group.calendar.google.com
CalendarB ID: afd3zeuguoepmi32s5i56g#group.calendar.google.com
To construct an event URL:
Get the event-id, which is the event id without the #google.com
E.g. for Event1 we have 4htgpmm1hmak744r0kbkdcodar
Get the calendar-id, which is the calendar id with the #group.calendar.google.com replaced with #g
E.g. for CalendarA we have eugu9kan1ddi1pmi6sk3ib56g#g
Join the two values with a space in the middle.
<event-id> <calendar-id>
E.g. for Event1 + CalendarA, we have:
4htgpmm1hmak744r0kbkdcodar eugu9kan1ddi1pmi6sk3ib56g#g
Encode the value as base64 (e.g. on https://www.base64decode.org):
NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw==
Remove the training ==:
NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw
You can now append this value to https://www.google.com/calendar/event?eid= (view event page) or https://calendar.google.com/calendar/r/eventedit/ (edit event page):
https://www.google.com/calendar/event?eid=NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw
or
https://calendar.google.com/calendar/r/eventedit/NGh0Z3BtbTFobWFrNzQ0cjBrYmtkY29kYXIgZXVndTlrYW4xZGRpMXBtaTZzazNpYjWoNmdAZw
You're done! That URL will take you to the calendar event in the Google interface.
How to find the calendar ID
If you need instructions for how to find the calendar id...
To find the calendar ID:
Go to the calendar settings
Scroll down until you find the calendar id field.
This might be a value that ends with #group.calendar.google.com, your email address, or some other value.
If you are having trouble finding the calendar id, another tool that might help is adding the eventdeb=1 parameter to the URL, going to the Troubleshooting info of an event, and then looking for either the organizer or participant values, both of which contain calendar ids.
In Apps Script
var eventUrl = "https://www.google.com/calendar/event?eid=" +
Utilities.base64Encode(event.getId().split('#')[0] +
" " +
event.getOriginalCalendarId())
.replace(/\=/g, '');
#Senseful had was a super helpful answer, and it works!
A few important things to note adding to the above. Firstly, when base64 encoding, you'll end up with a == at the end, remove that
Second, the base calendar URL will not work when the calendar the event belongs to does not belong in the primary account the user is logged in with. For example, if you're logged into 3 accounts, you'll have a different URL for each one e.g.
https://calendar.google.com/calendar/r/...
https://calendar.google.com/calendar/b/2/r/...
https://calendar.google.com/calendar/b/3/r/...
and so on... I don't think there's a solution that'll help with this situation since it's impossible to predict what accounts a specific user is logged into at any time.

CalendarApp Event ID

Using Google Apps Script, I am trying to create an Event in CalendarApp and store a Link to the event in a spreadsheet.
To create a link to the event I need to get the event ID, however using event.getID() in Google Apps Script returns the incorrect event ID.
Format for the link should be:
https://calendar.google.com/calendar/event?eid={eventID}=%7BAmerica/Chicago%7D
Event ID should look something like:
tmFmbHZydmU1aDBDZGhlYmMwaWdqcW1wZGMgdDY1HT6yhuHI5YXJwYW5lMHV2OTYzamtAZw
getID() is returning this:
065cvve58nriutnkuses332fkf#google.com
var event = CalendarApp.getCalendarById(calID).createAllDayEvent(eventName, new Date (eventDate));
var eventID = event.getId();
var eventLink = "https://www.google.com/calendar/event?eid=" + eventID + "&ctz={America/Chicago}";
Logger.log(eventLink);
Why is GAS returning the ID in this format?
According to this documentation,
getId()
Gets the ID of the calendar. The ID for a user's default calendar is
their email address.
You must have a specific id for your event.
You may check this links too:
FormResponse.getId() returns the wrong value right after the response is submitted
The id of a FormResponse when a response is submitted is different when you list all FormResponses
Based from this link, the IDs are not always the same, they are equal, apparently assigned a temporary ID until they are synchronized.
The ID that is returned is an iCalUID and is not interchangeable with the event ID used for specific events. See a related answer on StackExchange by "luc".
The iCalUID ID is used when handling events in multiple calendar systems. For using IDs only within Google Calendar, use luc's recommended method to obtain the event ID via the advanced Calendar services by listing out all events and matching against the iCalUID.
For testing purposes, you can get the event ID by navigating to Google Calendar, clicking on the event, clicking edit, and then copying the part of the URL after "https://calendar.google.com/calendar/r/eventedit/".
The id that is being returned to you is a calendar ID (065cvve58nriutnkuses332fkf#google.com)
If you double check that this matches the id for the calendar you want to create events in - go to settings and sharing for the calendar as shown in the screenshot.
Then you can use this id to call the calendar you want to work with:
calendar = CalendarApp.getCalendarById('065cvve58nriutnkuses332fkf#google.com');
then you can follow up with your original intent...
eventId = calendar.createAllDayEvent(eventName, new Date (eventDate)).getId;

Dynamically edit multiple choice options in live Google Form using Apps Script

I'm a high school teacher in L.A. trying to create a course registration system using Apps Script. I need the Google Form I'm using for this registration to:
Question 1) Update the choices available in subsequent multiple choice questions on new pages based on a student's current response choices.
Question 2) Eliminate choices from the form when a multiple choice option has reached it's "cap".
Question 1 Example)
A student registers for “tie-tying” in workshop 1, and gets taken to a new page. The Script edits the available choices on that new page based on the student’s first choice, and removes “tie-tying” from the list of possible choices on that new page, so “etiquette” is their only remaining option.
Question 2 Example)
Students can either register for “tie-tying” or “etiquette”, both responses are initially available in the Google Form. 30 students take the survey, all 30 register for the “tie-tying” workshop. The Apps Script references the response spreadsheet, realizes the “tie-tying” workshop is full, then removes it from the Google Form's list of possible choices. Student 31 goes to register, and their only option is “etiquette”.
If my question has already been asked and answered (believe me, I did search!) I'd appreciate the redirection.
I believe we can achieve your second objective without too much difficulty and modify the form, based on the current state of response.
The approach is to
Create the form and associate it with a response spreadsheet
In that response spreadsheet, create a script with a function (updateForm for instance)
Bind that function with the onFormSubmit event, see Using Container-Specific Installable Triggers.
Analyse the response in the updateForm function and modify your form using the Form Service
For instance
function updateForm(e) {
if (e.values[1] == 'Yes') {
Logger.log('Yes');
var existingForm = FormApp.openById('1jYHXD0TBYoKoRUI1mhY4j....yLWGE2vAm_Ux7Twk61c');
Logger.log(existingForm);
var item = existingForm.addMultipleChoiceItem();
item.setTitle('Do you prefer cats or dogs?')
.setChoices([
item.createChoice('Cats'),
item.createChoice('Dogs')
])
.showOtherOption(true);
}
}
When it comes to achieving the goal in your first question, its more delicate, as the form will not submit mid way. What is possible is to go to different pages based on different responses to a Multiple Choice question, your use case may fit this method, although its not very dynamic.
Further its possible to use html Service to create completely dynamic experience.
Let me know if you need further information.
You are not able to create this type of dynamic form using the Google Forms Service, because there is no interaction between the service and scripts during form entry, except upon Form Submission. In the case of a multi-page form, a script has no way to know that a student has completed one page and gone on to another.
You could achieve this using the HtmlService or UiService, though. In either case, you'd rely on the client-side form interacting through server-side scripts to get updated lists of course options, then modifying the next 'page'. It will be complex.
The other answer to this question will keep adding a multichoice select each time for the form is submitted. Using similar approach of:
Create the form and associate it with a response spreadsheet
In that response spreadsheet, create a script with a function (updateForm for instance)
Bind that function with the onFormSubmit event, see Using Container-Specific Installable Triggers.
Analyse the response in the updateForm function and modify your form using the Form Service
I've used the following code to modify a list select which could be easiliy modified for a multiple choice.
function updateForm(){
var form = FormApp.openById('YOUR_FORM_ID'); // Base form
// need to read what dates are available and which are taken
var doc = SpreadsheetApp.getActiveSpreadsheet();
var dates = doc.getRange("dates!A1:A10").getValues(); //available options
var taken_dates = doc.getRange("responses!F2:F51").getValues(); //just getting first 50 responses
// joining the taken dates into one string instead of an array to compare easier
var taken_dates_string = taken_dates.join("|");
var choice = [];
// loop through our available dates
for (d in dates){
// test if date still available
if (dates[d][0] != "" && taken_dates_string.indexOf(dates[d][0]) === -1){
choice.push(dates[d][0]); // if so we add to temp array
}
}
var formItems = form.getItems(FormApp.ItemType.LIST); // our form list items
// assumption that first select list is the one you want to change
// and we just rewrite all the options to ones that are free
formItems[0].asListItem().setChoiceValues(choice);
}