|
from datetime import date, datetime
|
|
from typing import Union, Iterator, Iterable, Callable
|
|
|
|
from beautiful_date import BeautifulDate
|
|
from dateutil.relativedelta import relativedelta
|
|
from tzlocal import get_localzone_name
|
|
|
|
from gcsa._services.base_service import BaseService
|
|
from gcsa.event import Event
|
|
from gcsa.serializers.event_serializer import EventSerializer
|
|
from gcsa.util.date_time_util import to_localized_iso
|
|
|
|
|
|
class SendUpdatesMode:
|
|
"""Possible values of the mode for sending updates or invitations to attendees.
|
|
|
|
* ALL - Send updates to all participants. This is the default value.
|
|
* EXTERNAL_ONLY - Send updates only to attendees not using google calendar.
|
|
* NONE - Do not send updates.
|
|
"""
|
|
|
|
ALL = "all"
|
|
EXTERNAL_ONLY = "externalOnly"
|
|
NONE = "none"
|
|
|
|
|
|
class EventsService(BaseService):
|
|
"""Event management methods of the `GoogleCalendar`"""
|
|
|
|
def _list_events(
|
|
self,
|
|
request_method: Callable,
|
|
time_min: Union[date, datetime, BeautifulDate],
|
|
time_max: Union[date, datetime, BeautifulDate],
|
|
timezone: str,
|
|
calendar_id: str,
|
|
**kwargs
|
|
) -> Iterable[Event]:
|
|
"""Lists paginated events received from request_method."""
|
|
|
|
time_min = time_min or datetime.now()
|
|
time_max = time_max or time_min + relativedelta(years=1)
|
|
|
|
time_min = to_localized_iso(time_min, timezone)
|
|
time_max = to_localized_iso(time_max, timezone)
|
|
|
|
yield from self._list_paginated(
|
|
request_method,
|
|
serializer_cls=EventSerializer,
|
|
calendarId=calendar_id,
|
|
timeMin=time_min,
|
|
timeMax=time_max,
|
|
**kwargs
|
|
)
|
|
|
|
def get_events(
|
|
self,
|
|
time_min: Union[date, datetime, BeautifulDate] = None,
|
|
time_max: Union[date, datetime, BeautifulDate] = None,
|
|
order_by: str = None,
|
|
timezone: str = get_localzone_name(),
|
|
single_events: bool = False,
|
|
query: str = None,
|
|
calendar_id: str = None,
|
|
**kwargs
|
|
) -> Iterable[Event]:
|
|
"""Lists events.
|
|
|
|
:param time_min:
|
|
Staring date/datetime
|
|
:param time_max:
|
|
Ending date/datetime
|
|
:param order_by:
|
|
Order of the events. Possible values: "startTime", "updated". Default is unspecified stable order.
|
|
:param timezone:
|
|
Timezone formatted as an IANA Time Zone Database name, e.g. "Europe/Zurich". By default,
|
|
the computers local timezone is used if it is configured. UTC is used otherwise.
|
|
:param single_events:
|
|
Whether to expand recurring events into instances and only return single one-off events and
|
|
instances of recurring events, but not the underlying recurring events themselves.
|
|
:param query:
|
|
Free text search terms to find events that match these terms in any field, except for
|
|
extended properties.
|
|
:param calendar_id:
|
|
Calendar identifier. Default is `default_calendar` specified in `GoogleCalendar`.
|
|
To retrieve calendar IDs call the :py:meth:`~gcsa.google_calendar.GoogleCalendar.get_calendar_list`.
|
|
If you want to access the primary calendar of the currently logged-in user, use the "primary" keyword.
|
|
:param kwargs:
|
|
Additional API parameters.
|
|
See https://developers.google.com/calendar/v3/reference/events/list#optional-parameters
|
|
|
|
:return:
|
|
Iterable of `Event` objects
|
|
"""
|
|
calendar_id = calendar_id or self.default_calendar
|
|
if not single_events and order_by == 'startTime':
|
|
raise ValueError(
|
|
'"startTime" ordering is only available when querying single events, i.e. single_events=True'
|
|
)
|
|
yield from self._list_events(
|
|
self.service.events().list,
|
|
time_min=time_min,
|
|
time_max=time_max,
|
|
timezone=timezone,
|
|
calendar_id=calendar_id,
|
|
**{
|
|
'singleEvents': single_events,
|
|
'orderBy': order_by,
|
|
'q': query,
|
|
**kwargs
|
|
}
|
|
)
|
|
|
|
def get_instances(
|
|
self,
|
|
recurring_event: Union[Event, str],
|
|
time_min: Union[date, datetime, BeautifulDate] = None,
|
|
time_max: Union[date, datetime, BeautifulDate] = None,
|
|
timezone: str = get_localzone_name(),
|
|
calendar_id: str = None,
|
|
**kwargs
|
|
) -> Iterable[Event]:
|
|
"""Lists instances of recurring event
|
|
|
|
:param recurring_event:
|
|
Recurring event or instance of recurring event (`Event` object) or id of the recurring event
|
|
:param time_min:
|
|
Staring date/datetime
|
|
:param time_max:
|
|
Ending date/datetime
|
|
:param timezone:
|
|
Timezone formatted as an IANA Time Zone Database name, e.g. "Europe/Zurich". By default,
|
|
the computers local timezone is used if it is configured. UTC is used otherwise.
|
|
:param calendar_id:
|
|
Calendar identifier. Default is `default_calendar` specified in `GoogleCalendar`.
|
|
To retrieve calendar IDs call the :py:meth:`~gcsa.google_calendar.GoogleCalendar.get_calendar_list`.
|
|
If you want to access the primary calendar of the currently logged-in user, use the "primary" keyword.
|
|
:param kwargs:
|
|
Additional API parameters.
|
|
See https://developers.google.com/calendar/v3/reference/events/instances#optional-parameters
|
|
|
|
:return:
|
|
Iterable of event objects
|
|
"""
|
|
calendar_id = calendar_id or self.default_calendar
|
|
try:
|
|
event_id = self._get_resource_id(recurring_event)
|
|
except ValueError:
|
|
raise ValueError("Recurring event has to have id to retrieve its instances.")
|
|
|
|
yield from self._list_events(
|
|
self.service.events().instances,
|
|
time_min=time_min,
|
|
time_max=time_max,
|
|
timezone=timezone,
|
|
calendar_id=calendar_id,
|
|
**{
|
|
'eventId': event_id,
|
|
**kwargs
|
|
}
|
|
)
|
|
|
|
def __iter__(self) -> Iterator[Event]:
|
|
return iter(self.get_events())
|
|
|
|
def __getitem__(self, r):
|
|
if isinstance(r, slice):
|
|
time_min, time_max, order_by = r.start or None, r.stop or None, r.step or None
|
|
elif isinstance(r, (date, datetime)):
|
|
time_min, time_max, order_by = r, None, None
|
|
else:
|
|
raise NotImplementedError
|
|
|
|
if (
|
|
(time_min and not isinstance(time_min, (date, datetime)))
|
|
or (time_max and not isinstance(time_max, (date, datetime)))
|
|
or (order_by and (not isinstance(order_by, str) or order_by not in self._LIST_ORDERS))
|
|
):
|
|
raise ValueError('Calendar indexing is in the following format: time_min[:time_max[:order_by]],'
|
|
' where time_min and time_max are date/datetime objects'
|
|
' and order_by is None or one of "startTime" or "updated" strings.')
|
|
|
|
return self.get_events(time_min, time_max, order_by=order_by, single_events=(order_by == "startTime"))
|
|
|
|
def get_event(
|
|
self,
|
|
event_id: str,
|
|
calendar_id: str = None,
|
|
**kwargs
|
|
) -> Event:
|
|
"""Returns the event with the corresponding event_id.
|
|
|
|
:param event_id:
|
|
The unique event ID.
|
|
:param kwargs:
|
|
Additional API parameters.
|
|
See https://developers.google.com/calendar/v3/reference/events/get#optional-parameters
|
|
:param calendar_id:
|
|
Calendar identifier. Default is `default_calendar` specified in `GoogleCalendar`.
|
|
To retrieve calendar IDs call the :py:meth:`~gcsa.google_calendar.GoogleCalendar.get_calendar_list`.
|
|
If you want to access the primary calendar of the currently logged-in user, use the "primary" keyword.
|
|
|
|
:return:
|
|
The corresponding event object.
|
|
"""
|
|
calendar_id = calendar_id or self.default_calendar
|
|
event_resource = self.service.events().get(
|
|
calendarId=calendar_id,
|
|
eventId=event_id,
|
|
**kwargs
|
|
).execute()
|
|
return EventSerializer.to_object(event_resource)
|
|
|
|
def add_event(
|
|
self,
|
|
event: Event,
|
|
send_updates: str = SendUpdatesMode.NONE,
|
|
calendar_id: str = None,
|
|
**kwargs
|
|
) -> Event:
|
|
"""Creates event in the calendar
|
|
|
|
:param event:
|
|
Event object.
|
|
:param send_updates:
|
|
Whether and how to send updates to attendees. See :py:class:`~gcsa.google_calendar.SendUpdatesMode`
|
|
Default is "NONE".
|
|
:param calendar_id:
|
|
Calendar identifier. Default is `default_calendar` specified in `GoogleCalendar`.
|
|
To retrieve calendar IDs call the :py:meth:`~gcsa.google_calendar.GoogleCalendar.get_calendar_list`.
|
|
If you want to access the primary calendar of the currently logged-in user, use the "primary" keyword.
|
|
:param kwargs:
|
|
Additional API parameters.
|
|
See https://developers.google.com/calendar/v3/reference/events/insert#optional-parameters
|
|
|
|
:return:
|
|
Created event object with id.
|
|
"""
|
|
calendar_id = calendar_id or self.default_calendar
|
|
body = EventSerializer.to_json(event)
|
|
event_json = self.service.events().insert(
|
|
calendarId=calendar_id,
|
|
body=body,
|
|
conferenceDataVersion=1,
|
|
sendUpdates=send_updates,
|
|
**kwargs
|
|
).execute()
|
|
return EventSerializer.to_object(event_json)
|
|
|
|
def add_quick_event(
|
|
self,
|
|
event_string: str,
|
|
send_updates: str = SendUpdatesMode.NONE,
|
|
calendar_id: str = None,
|
|
**kwargs
|
|
) -> Event:
|
|
"""Creates event in the calendar by string description.
|
|
|
|
Example:
|
|
Appointment at Somewhere on June 3rd 10am-10:25am
|
|
|
|
:param event_string:
|
|
String that describes an event
|
|
:param send_updates:
|
|
Whether and how to send updates to attendees. See :py:class:`~gcsa.google_calendar.SendUpdatesMode`
|
|
Default is "NONE".
|
|
:param calendar_id:
|
|
Calendar identifier. Default is `default_calendar` specified in `GoogleCalendar`.
|
|
To retrieve calendar IDs call the :py:meth:`~gcsa.google_calendar.GoogleCalendar.get_calendar_list`.
|
|
If you want to access the primary calendar of the currently logged-in user, use the "primary" keyword.
|
|
:param kwargs:
|
|
Additional API parameters.
|
|
See https://developers.google.com/calendar/v3/reference/events/quickAdd#optional-parameters
|
|
|
|
:return:
|
|
Created event object with id.
|
|
"""
|
|
calendar_id = calendar_id or self.default_calendar
|
|
event_json = self.service.events().quickAdd(
|
|
calendarId=calendar_id,
|
|
text=event_string,
|
|
sendUpdates=send_updates,
|
|
**kwargs
|
|
).execute()
|
|
return EventSerializer.to_object(event_json)
|
|
|
|
def update_event(
|
|
self,
|
|
event: Event,
|
|
send_updates: str = SendUpdatesMode.NONE,
|
|
calendar_id: str = None,
|
|
**kwargs
|
|
) -> Event:
|
|
"""Updates existing event in the calendar
|
|
|
|
:param event:
|
|
Event object with set `event_id`.
|
|
:param send_updates:
|
|
Whether and how to send updates to attendees. See :py:class:`~gcsa.google_calendar.SendUpdatesMode`
|
|
Default is "NONE".
|
|
:param calendar_id:
|
|
Calendar identifier. Default is `default_calendar` specified in `GoogleCalendar`.
|
|
To retrieve calendar IDs call the :py:meth:`~gcsa.google_calendar.GoogleCalendar.get_calendar_list`.
|
|
If you want to access the primary calendar of the currently logged-in user, use the "primary" keyword.
|
|
:param kwargs:
|
|
Additional API parameters.
|
|
See https://developers.google.com/calendar/v3/reference/events/update#optional-parameters
|
|
|
|
:return:
|
|
Updated event object.
|
|
"""
|
|
calendar_id = calendar_id or self.default_calendar
|
|
event_id = self._get_resource_id(event)
|
|
body = EventSerializer.to_json(event)
|
|
event_json = self.service.events().update(
|
|
calendarId=calendar_id,
|
|
eventId=event_id,
|
|
body=body,
|
|
conferenceDataVersion=1,
|
|
sendUpdates=send_updates,
|
|
**kwargs
|
|
).execute()
|
|
return EventSerializer.to_object(event_json)
|
|
|
|
def import_event(
|
|
self,
|
|
event: Event,
|
|
calendar_id: str = None,
|
|
**kwargs
|
|
) -> Event:
|
|
"""Imports an event in the calendar
|
|
|
|
This operation is used to add a private copy of an existing event to a calendar.
|
|
|
|
:param event:
|
|
Event object.
|
|
:param calendar_id:
|
|
Calendar identifier. Default is `default_calendar` specified in `GoogleCalendar`.
|
|
To retrieve calendar IDs call the :py:meth:`~gcsa.google_calendar.GoogleCalendar.get_calendar_list`.
|
|
If you want to access the primary calendar of the currently logged-in user, use the "primary" keyword.
|
|
:param kwargs:
|
|
Additional API parameters.
|
|
See https://developers.google.com/calendar/v3/reference/events/import#optional-parameters
|
|
|
|
:return:
|
|
Created event object with id.
|
|
"""
|
|
calendar_id = calendar_id or self.default_calendar
|
|
body = EventSerializer.to_json(event)
|
|
event_json = self.service.events().import_(
|
|
calendarId=calendar_id,
|
|
body=body,
|
|
conferenceDataVersion=1,
|
|
**kwargs
|
|
).execute()
|
|
return EventSerializer.to_object(event_json)
|
|
|
|
def move_event(
|
|
self,
|
|
event: Event,
|
|
destination_calendar_id: str,
|
|
send_updates: str = SendUpdatesMode.NONE,
|
|
source_calendar_id: str = None,
|
|
**kwargs
|
|
) -> Event:
|
|
"""Moves existing event from calendar to another calendar
|
|
|
|
:param event:
|
|
Event object with set event_id.
|
|
:param destination_calendar_id:
|
|
ID of the destination calendar.
|
|
:param send_updates:
|
|
Whether and how to send updates to attendees. See :py:class:`~gcsa.google_calendar.SendUpdatesMode`
|
|
Default is "NONE".
|
|
:param source_calendar_id:
|
|
Calendar identifier. Default is `default_calendar` specified in `GoogleCalendar`.
|
|
To retrieve calendar IDs call the :py:meth:`~gcsa.google_calendar.GoogleCalendar.get_calendar_list`.
|
|
If you want to access the primary calendar of the currently logged-in user, use the "primary" keyword.
|
|
:param kwargs:
|
|
Additional API parameters.
|
|
See https://developers.google.com/calendar/v3/reference/events/move#optional-parameters
|
|
|
|
:return:
|
|
Moved event object.
|
|
"""
|
|
source_calendar_id = source_calendar_id or self.default_calendar
|
|
event_id = self._get_resource_id(event)
|
|
moved_event_json = self.service.events().move(
|
|
calendarId=source_calendar_id,
|
|
eventId=event_id,
|
|
destination=destination_calendar_id,
|
|
sendUpdates=send_updates,
|
|
**kwargs
|
|
).execute()
|
|
return EventSerializer.to_object(moved_event_json)
|
|
|
|
def delete_event(
|
|
self,
|
|
event: Union[Event, str],
|
|
send_updates: str = SendUpdatesMode.NONE,
|
|
calendar_id: str = None,
|
|
**kwargs
|
|
):
|
|
"""Deletes an event.
|
|
|
|
:param event:
|
|
Event's ID or `Event` object with set `event_id`.
|
|
:param send_updates:
|
|
Whether and how to send updates to attendees. See :py:class:`~gcsa.google_calendar.SendUpdatesMode`
|
|
Default is "NONE".
|
|
:param calendar_id:
|
|
Calendar identifier. Default is `default_calendar` specified in `GoogleCalendar`.
|
|
To retrieve calendar IDs call the :py:meth:`~gcsa.google_calendar.GoogleCalendar.get_calendar_list`.
|
|
If you want to access the primary calendar of the currently logged-in user, use the "primary" keyword.
|
|
:param kwargs:
|
|
Additional API parameters.
|
|
See https://developers.google.com/calendar/v3/reference/events/delete#optional-parameters
|
|
"""
|
|
calendar_id = calendar_id or self.default_calendar
|
|
event_id = self._get_resource_id(event)
|
|
|
|
self.service.events().delete(
|
|
calendarId=calendar_id,
|
|
eventId=event_id,
|
|
sendUpdates=send_updates,
|
|
**kwargs
|
|
).execute()
|
|
|