47ba13d985
The error should not be swallowed and it should be instead propagated up to calendar.get_upcoming_events, if it's called from that context. And calendar.get_upcoming_events should be in charge of handling the exceptions and make sure that failing to retrieve the events for one calendar doesn't make the whole method fail.
130 lines
3.9 KiB
Python
130 lines
3.9 KiB
Python
"""
|
|
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
|
"""
|
|
|
|
import dateutil.parser
|
|
import importlib
|
|
|
|
from abc import ABCMeta, abstractmethod
|
|
|
|
from platypush.plugins import Plugin, action
|
|
|
|
|
|
class CalendarInterface:
|
|
__metaclass__ = ABCMeta
|
|
|
|
@abstractmethod
|
|
def get_upcoming_events(self, max_results=10):
|
|
raise NotImplementedError()
|
|
|
|
|
|
class CalendarPlugin(Plugin, CalendarInterface):
|
|
"""
|
|
The CalendarPlugin allows you to keep track of multiple calendars (Google or
|
|
iCal URLs) and get joined events from all of them.
|
|
|
|
Requires:
|
|
* **dateutil** (``pip install python-dateutil``)
|
|
"""
|
|
|
|
def __init__(self, calendars=None, *args, **kwargs):
|
|
"""
|
|
:param calendars: List of calendars to be queried. Supported types so far: Google Calendar and iCal URLs.
|
|
:type calendars: list
|
|
|
|
Example format::
|
|
|
|
calendars = [
|
|
{
|
|
"type": "platypush.plugins.google.calendar.GoogleCalendarPlugin"
|
|
},
|
|
|
|
{
|
|
"type": "platypush.plugins.calendar.ical.IcalCalendarPlugin",
|
|
"url": "https://www.facebook.com/ical/u.php?uid=USER_ID&key=FB_KEY"
|
|
},
|
|
|
|
...
|
|
]
|
|
"""
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if calendars is None:
|
|
calendars = []
|
|
self.calendars = []
|
|
|
|
for calendar in calendars:
|
|
if 'type' not in calendar:
|
|
self.logger.warning("Invalid calendar with no type specified: {}".format(calendar))
|
|
continue
|
|
|
|
cal_type = calendar.pop('type')
|
|
module_name = '.'.join(cal_type.split('.')[:-1])
|
|
class_name = cal_type.split('.')[-1]
|
|
module = importlib.import_module(module_name)
|
|
self.calendars.append(getattr(module, class_name)(**calendar))
|
|
|
|
|
|
@action
|
|
def get_upcoming_events(self, max_results=10):
|
|
"""
|
|
Get a list of upcoming events merging all the available calendars.
|
|
|
|
:param max_results: Maximum number of results to be returned (default: 10)
|
|
:type max_results: int
|
|
|
|
:returns: platypush.message.Response -- Response object with the list of events in the Google calendar API format.
|
|
|
|
Example::
|
|
|
|
output = [
|
|
{
|
|
"id": "123456abcdef",
|
|
"kind": "calendar#event",
|
|
"status": "confirmed",
|
|
"htmlLink": "...",
|
|
"created": "2018-06-01T01:23:45.000Z",
|
|
"updated": "2018-06-01T01:23:45.000Z",
|
|
"creator": {
|
|
"email": "...",
|
|
"displayName": "...",
|
|
"self": true
|
|
},
|
|
"organizer" {
|
|
"email": "...",
|
|
"displayName": "...",
|
|
"self": true
|
|
},
|
|
"start": {
|
|
"dateTime": "2018-06-02T10:00:00.000Z",
|
|
},
|
|
"end": {
|
|
"dateTime": "2018-06-02T12:00:00.000Z",
|
|
},
|
|
},
|
|
...
|
|
]
|
|
"""
|
|
|
|
events = []
|
|
|
|
for calendar in self.calendars:
|
|
try:
|
|
cal_events = calendar.get_upcoming_events().output or []
|
|
events.extend(cal_events)
|
|
except Exception as e:
|
|
self.logger.warning('Could not retrieve events: {}'.format(str(e)))
|
|
|
|
events = sorted(events, key=lambda event:
|
|
dateutil.parser.parse(
|
|
event['start']['dateTime']
|
|
if 'dateTime' in event['start']
|
|
else event['start']['date'] + 'T00:00:00+00:00'
|
|
))[:max_results]
|
|
|
|
return events
|
|
|
|
|
|
# vim:sw=4:ts=4:et:
|
|
|