from functools import total_ordering from typing import List, Union from beautiful_date import BeautifulDate from tzlocal import get_localzone_name from datetime import datetime, date, timedelta, time from ._resource import Resource from .attachment import Attachment from .attendee import Attendee from .conference import ConferenceSolution, ConferenceSolutionCreateRequest from .person import Person from .reminders import PopupReminder, EmailReminder, Reminder from .util.date_time_util import ensure_localisation class Visibility: """Possible values of the event visibility. * `DEFAULT` - Uses the default visibility for events on the calendar. This is the default value. * `PUBLIC` - The event is public and event details are visible to all readers of the calendar. * `PRIVATE` - The event is private and only event attendees may view event details. """ DEFAULT = "default" PUBLIC = "public" PRIVATE = "private" class Transparency: """Possible values of the event transparency. * `OPAQUE` - Default value. The event does block time on the calendar. This is equivalent to setting 'Show me as' to 'Busy' in the Calendar UI. * `TRANSPARENT` - The event does not block time on the calendar. This is equivalent to setting 'Show me as' to 'Available' in the Calendar UI. """ OPAQUE = 'opaque' TRANSPARENT = 'transparent' @total_ordering class Event(Resource): def __init__( self, summary: str, start: Union[date, datetime, BeautifulDate], end: Union[date, datetime, BeautifulDate] = None, *, timezone: str = get_localzone_name(), event_id: str = None, description: str = None, location: str = None, recurrence: Union[str, List[str]] = None, color_id: str = None, visibility: str = Visibility.DEFAULT, attendees: Union[Attendee, str, List[Attendee], List[str]] = None, attachments: Union[Attachment, List[Attachment]] = None, conference_solution: Union[ConferenceSolution, ConferenceSolutionCreateRequest] = None, reminders: Union[Reminder, List[Reminder]] = None, default_reminders: bool = False, minutes_before_popup_reminder: int = None, minutes_before_email_reminder: int = None, guests_can_invite_others: bool = True, guests_can_modify: bool = False, guests_can_see_other_guests: bool = True, transparency: str = None, _creator: Person = None, _organizer: Person = None, _created: datetime = None, _updated: datetime = None, _recurring_event_id: str = None, **other ): """ :param summary: Title of the event. :param start: Starting date/datetime. :param end: Ending date/datetime. If 'end' is not specified, event is considered as a 1-day or 1-hour event if 'start' is date or datetime respectively. :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 event_id: Opaque identifier of the event. By default, it is generated by the server. You can specify id as a 5-1024 long string of characters used in base32hex ([a-vA-V0-9]). The ID must be unique per calendar. :param description: Description of the event. Can contain HTML. :param location: Geographic location of the event as free-form text. :param recurrence: RRULE/RDATE/EXRULE/EXDATE string or list of such strings. See :py:mod:`~gcsa.recurrence` :param color_id: Color id referring to an entry from colors endpoint. See :py:meth:`~gcsa.google_calendar.GoogleCalendar.list_event_colors` :param visibility: Visibility of the event. Default is default visibility for events on the calendar. See :py:class:`~gcsa.event.Visibility` :param attendees: Attendee or list of attendees. See :py:class:`~gcsa.attendee.Attendee`. Each attendee may be given as email string or :py:class:`~gcsa.attendee.Attendee` object. :param attachments: Attachment or list of attachments. See :py:class:`~gcsa.attachment.Attachment` :param conference_solution: :py:class:`~gcsa.conference.ConferenceSolutionCreateRequest` object to create a new conference or :py:class:`~gcsa.conference.ConferenceSolution` object for existing conference. :param reminders: Reminder or list of reminder objects. See :py:mod:`~gcsa.reminders` :param default_reminders: Whether the default reminders of the calendar apply to the event. :param minutes_before_popup_reminder: Minutes before popup reminder or None if reminder is not needed. :param minutes_before_email_reminder: Minutes before email reminder or None if reminder is not needed. :param guests_can_invite_others: Whether attendees other than the organizer can invite others to the event. :param guests_can_modify: Whether attendees other than the organizer can modify the event. :param guests_can_see_other_guests: Whether attendees other than the organizer can see who the event's attendees are. :param transparency: Whether the event blocks time on the calendar. See :py:class:`~gcsa.event.Transparency` :param _creator: The creator of the event. See :py:class:`~gcsa.person.Person` :param _organizer: The organizer of the event. See :py:class:`~gcsa.person.Person`. If the organizer is also an attendee, this is indicated with a separate entry in attendees with the organizer field set to True. To change the organizer, use the move operation see :py:meth:`~gcsa.google_calendar.GoogleCalendar.move_event` :param _created: Creation time of the event. Read-only. :param _updated: Last modification time of the event. Read-only. :param _recurring_event_id: For an instance of a recurring event, this is the id of the recurring event to which this instance belongs. Read-only. :param other: Other fields that should be included in request json. Will be included as they are. See more in https://developers.google.com/calendar/v3/reference/events """ def ensure_list(obj): return [] if obj is None else obj if isinstance(obj, list) else [obj] self.timezone = timezone self.start = start if end or start is None: self.end = end elif isinstance(start, datetime): self.end = start + timedelta(hours=1) elif isinstance(start, date): self.end = start + timedelta(days=1) if isinstance(self.start, datetime) and isinstance(self.end, datetime): self.start = ensure_localisation(self.start, timezone) self.end = ensure_localisation(self.end, timezone) elif isinstance(self.start, datetime) or isinstance(self.end, datetime): raise TypeError('Start and end must either both be date or both be datetime.') def ensure_date(d): """Converts d to date if it is of type BeautifulDate.""" if isinstance(d, BeautifulDate): return date(year=d.year, month=d.month, day=d.day) else: return d self.start = ensure_date(self.start) self.end = ensure_date(self.end) self.created = _created self.updated = _updated attendees = [self._ensure_attendee_from_email(a) for a in ensure_list(attendees)] reminders = ensure_list(reminders) if len(reminders) > 5: raise ValueError('The maximum number of override reminders is 5.') if default_reminders and reminders: raise ValueError('Cannot specify both default reminders and overrides at the same time.') self.event_id = event_id self.summary = summary self.description = description self.location = location self.recurrence = ensure_list(recurrence) self.color_id = color_id self.visibility = visibility self.attendees = attendees self.attachments = ensure_list(attachments) self.conference_solution = conference_solution self.reminders = reminders self.default_reminders = default_reminders self.recurring_event_id = _recurring_event_id self.guests_can_invite_others = guests_can_invite_others self.guests_can_modify = guests_can_modify self.guests_can_see_other_guests = guests_can_see_other_guests self.transparency = transparency self.creator = _creator self.organizer = _organizer self.other = other if minutes_before_popup_reminder is not None: self.add_popup_reminder(minutes_before_popup_reminder) if minutes_before_email_reminder is not None: self.add_email_reminder(minutes_before_email_reminder) @property def id(self): return self.event_id def add_attendee( self, attendee: Union[str, Attendee] ): """Adds attendee to an event. See :py:class:`~gcsa.attendee.Attendee`. Attendee may be given as email string or :py:class:`~gcsa.attendee.Attendee` object.""" self.attendees.append(self._ensure_attendee_from_email(attendee)) def add_attendees( self, attendees: List[Union[str, Attendee]] ): """Adds multiple attendees to an event. See :py:class:`~gcsa.attendee.Attendee`. Each attendee may be given as email string or :py:class:`~gcsa.attendee.Attendee` object.""" for a in attendees: self.add_attendee(a) def add_attachment( self, file_url: str, title: str = None, mime_type: str = None ): """Adds attachment to an event. See :py:class:`~gcsa.attachment.Attachment`""" self.attachments.append(Attachment(file_url=file_url, title=title, mime_type=mime_type)) def add_email_reminder( self, minutes_before_start: int = None, days_before: int = None, at: time = None ): """Adds email reminder to an event. See :py:class:`~gcsa.reminders.EmailReminder`""" self.add_reminder(EmailReminder(minutes_before_start, days_before, at)) def add_popup_reminder( self, minutes_before_start: int = None, days_before: int = None, at: time = None ): """Adds popup reminder to an event. See :py:class:`~gcsa.reminders.PopupReminder`""" self.add_reminder(PopupReminder(minutes_before_start, days_before, at)) def add_reminder( self, reminder: Reminder ): """Adds reminder to an event. See :py:mod:`~gcsa.reminders`""" if len(self.reminders) > 4: raise ValueError('The maximum number of override reminders is 5.') self.reminders.append(reminder) @staticmethod def _ensure_attendee_from_email( attendee_or_email: Union[str, Attendee] ): """If attendee_or_email is email string, returns created :py:class:`~gcsa.attendee.Attendee` object with the given email.""" if isinstance(attendee_or_email, str): return Attendee(email=attendee_or_email) else: return attendee_or_email @property def is_recurring_instance(self): return self.recurring_event_id is not None def __str__(self): return '{} - {}'.format(self.start, self.summary) def __repr__(self): return ''.format(self.__str__()) def __lt__(self, other): def ensure_datetime(d, timezone): if type(d) is date: return ensure_localisation(datetime(year=d.year, month=d.month, day=d.day), timezone) else: return d start = ensure_datetime(self.start, self.timezone) end = ensure_datetime(self.end, self.timezone) other_start = ensure_datetime(other.start, other.timezone) other_end = ensure_datetime(other.end, other.timezone) return (start, end) < (other_start, other_end) def __eq__(self, other): return ( isinstance(other, Event) and self.start == other.start and self.end == other.end and self.event_id == other.event_id and self.summary == other.summary and self.description == other.description and self.location == other.location and self.recurrence == other.recurrence and self.color_id == other.color_id and self.visibility == other.visibility and self.attendees == other.attendees and self.attachments == other.attachments and self.reminders == other.reminders and self.default_reminders == other.default_reminders and self.created == other.created and self.updated == other.updated and self.recurring_event_id == other.recurring_event_id and self.guests_can_invite_others == other.guests_can_invite_others and self.guests_can_modify == other.guests_can_modify and self.guests_can_see_other_guests == other.guests_can_see_other_guests and self.other == other.other )