File size: 17,898 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
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
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()