2016-04-07 15:03:22 +02:00
|
|
|
#!/usr/bin/env python
|
2016-03-10 17:15:34 +01:00
|
|
|
from __future__ import print_function
|
2012-10-21 22:18:51 +02:00
|
|
|
import sys
|
|
|
|
import time
|
|
|
|
import datetime
|
|
|
|
import optparse
|
2016-01-24 03:39:44 +01:00
|
|
|
from six.moves import urllib
|
2012-10-21 22:18:51 +02:00
|
|
|
import itertools
|
|
|
|
import traceback
|
2013-10-28 15:54:32 +01:00
|
|
|
import os
|
2012-10-21 22:18:51 +02:00
|
|
|
|
2013-10-28 15:54:32 +01:00
|
|
|
sys.path.append(os.path.join(os.path.dirname(__file__), '../api'))
|
2013-08-07 17:51:03 +02:00
|
|
|
import zulip
|
2016-11-30 05:05:00 +01:00
|
|
|
from typing import List, Set, Tuple, Iterable, Optional
|
2012-10-21 22:18:51 +02:00
|
|
|
|
|
|
|
parser = optparse.OptionParser(r"""
|
|
|
|
|
|
|
|
%prog \
|
2013-07-24 21:27:14 +02:00
|
|
|
--user foo@zulip.com \
|
|
|
|
--calendar http://www.google.com/calendar/feeds/foo%40zulip.com/private-fedcba9876543210fedcba9876543210/basic
|
2012-10-21 22:18:51 +02:00
|
|
|
|
2013-07-24 21:27:14 +02:00
|
|
|
Send yourself reminders on Zulip of Google Calendar events.
|
2012-10-21 22:18:51 +02:00
|
|
|
|
|
|
|
To get the calendar URL:
|
|
|
|
- Load Google Calendar in a web browser
|
|
|
|
- Find your calendar in the "My calendars" list on the left
|
|
|
|
- Click the down-wedge icon that appears on mouseover, and select "Calendar settings"
|
|
|
|
- Copy the link address for the "XML" button under "Private Address"
|
|
|
|
|
|
|
|
Run this on your personal machine. Your API key and calendar URL are revealed to local
|
|
|
|
users through the command line.
|
|
|
|
|
|
|
|
Depends on: python-gdata
|
|
|
|
""")
|
|
|
|
|
|
|
|
parser.add_option('--calendar',
|
|
|
|
dest='calendar',
|
|
|
|
action='store',
|
|
|
|
help='Google Calendar XML "Private Address"',
|
|
|
|
metavar='URL')
|
|
|
|
parser.add_option('--interval',
|
|
|
|
dest='interval',
|
|
|
|
default=10,
|
|
|
|
type=int,
|
|
|
|
action='store',
|
|
|
|
help='Minutes before event for reminder [default: 10]',
|
|
|
|
metavar='MINUTES')
|
2013-08-07 17:51:03 +02:00
|
|
|
parser.add_option_group(zulip.generate_option_group(parser))
|
2012-10-21 22:18:51 +02:00
|
|
|
|
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
|
2014-02-21 20:11:29 +01:00
|
|
|
if not (options.zulip_email and options.calendar):
|
2012-12-03 19:50:24 +01:00
|
|
|
parser.error('You must specify --user and --calendar')
|
2012-10-21 22:18:51 +02:00
|
|
|
|
|
|
|
try:
|
|
|
|
from gdata.calendar.client import CalendarClient
|
|
|
|
except ImportError:
|
|
|
|
parser.error('Install python-gdata')
|
|
|
|
|
|
|
|
def get_calendar_url():
|
2016-11-30 05:05:00 +01:00
|
|
|
# type: () -> str
|
2016-01-24 03:39:44 +01:00
|
|
|
parts = urllib.parse.urlparse(options.calendar)
|
2013-10-28 15:54:32 +01:00
|
|
|
pat = os.path.split(parts.path)
|
2012-10-21 22:18:51 +02:00
|
|
|
if pat[1] != 'basic':
|
|
|
|
parser.error('The --calendar URL should be the XML "Private Address" ' +
|
|
|
|
'from your calendar settings')
|
2016-01-24 03:39:44 +01:00
|
|
|
return urllib.parse.urlunparse((parts.scheme, parts.netloc, pat[0] + '/full',
|
|
|
|
'', 'futureevents=true&orderby=startdate', ''))
|
2012-10-21 22:18:51 +02:00
|
|
|
|
|
|
|
calendar_url = get_calendar_url()
|
|
|
|
|
2013-08-07 17:51:03 +02:00
|
|
|
client = zulip.init_from_options(options)
|
2012-10-21 22:18:51 +02:00
|
|
|
|
|
|
|
def get_events():
|
2016-11-30 05:05:00 +01:00
|
|
|
# type: () -> Iterable[Tuple[int, datetime.datetime, str]]
|
2012-10-21 22:18:51 +02:00
|
|
|
feed = CalendarClient().GetCalendarEventFeed(uri=calendar_url)
|
|
|
|
|
|
|
|
for event in feed.entry:
|
|
|
|
start = event.when[0].start.split('.')[0]
|
2013-01-16 19:51:32 +01:00
|
|
|
# All-day events can have only a date
|
|
|
|
fmt = '%Y-%m-%dT%H:%M:%S' if 'T' in start else '%Y-%m-%d'
|
|
|
|
start = datetime.datetime.strptime(start, fmt)
|
2012-10-21 22:18:51 +02:00
|
|
|
yield (event.uid.value, start, event.title.text)
|
|
|
|
|
|
|
|
# Our cached view of the calendar, updated periodically.
|
2016-11-30 05:05:00 +01:00
|
|
|
events = [] # type: List[Tuple[int, datetime.datetime, str]]
|
2012-10-21 22:18:51 +02:00
|
|
|
|
|
|
|
# Unique keys for events we've already sent, so we don't remind twice.
|
2016-11-30 05:05:00 +01:00
|
|
|
sent = set() # type: Set[Tuple[int, datetime.datetime]]
|
2012-10-21 22:18:51 +02:00
|
|
|
|
|
|
|
def send_reminders():
|
2016-11-30 05:05:00 +01:00
|
|
|
# type: () -> Optional[None]
|
2012-10-21 22:18:51 +02:00
|
|
|
global sent
|
|
|
|
|
|
|
|
messages = []
|
|
|
|
keys = set()
|
|
|
|
now = datetime.datetime.now()
|
|
|
|
|
|
|
|
for uid, start, title in events:
|
|
|
|
dt = start - now
|
|
|
|
if dt.days == 0 and dt.seconds < 60*options.interval:
|
|
|
|
# The unique key includes the start time, because of
|
|
|
|
# repeating events.
|
|
|
|
key = (uid, start)
|
|
|
|
if key not in sent:
|
|
|
|
line = '%s starts at %s' % (title, start.strftime('%H:%M'))
|
2016-03-10 17:15:34 +01:00
|
|
|
print('Sending reminder:', line)
|
2012-10-21 22:18:51 +02:00
|
|
|
messages.append(line)
|
|
|
|
keys.add(key)
|
|
|
|
|
|
|
|
if not messages:
|
|
|
|
return
|
|
|
|
|
|
|
|
if len(messages) == 1:
|
|
|
|
message = 'Reminder: ' + messages[0]
|
|
|
|
else:
|
|
|
|
message = 'Reminder:\n\n' + '\n'.join('* ' + m for m in messages)
|
|
|
|
|
2012-12-03 22:13:00 +01:00
|
|
|
client.send_message(dict(
|
|
|
|
type = 'private',
|
|
|
|
to = options.user,
|
|
|
|
content = message))
|
2012-10-21 22:18:51 +02:00
|
|
|
|
|
|
|
sent |= keys
|
|
|
|
|
|
|
|
# Loop forever
|
|
|
|
for i in itertools.count():
|
|
|
|
try:
|
|
|
|
# We check reminders every minute, but only
|
|
|
|
# download the calendar every 10 minutes.
|
|
|
|
if not i % 10:
|
|
|
|
events = list(get_events())
|
|
|
|
send_reminders()
|
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
|
|
|
time.sleep(60)
|