File size: 14,560 Bytes
550665c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
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 '<Event {}>'.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
        )