|
|
|
@ -1,17 +1,19 @@ |
|
|
|
from dateutil import rrule, tz |
|
|
|
from oauth2client import tools |
|
|
|
from googleapiclient.errors import HttpError |
|
|
|
from dateutil.parser import parse as date_parse |
|
|
|
import re |
|
|
|
import tzlocal |
|
|
|
import argparse |
|
|
|
import datetime |
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
from api import API, HttpError |
|
|
|
from api import API |
|
|
|
else: |
|
|
|
from gapi.api import API, HttpError |
|
|
|
from gapi.api import API |
|
|
|
|
|
|
|
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args() |
|
|
|
APPLICATION_NAME = 'Google Calendar API Python' |
|
|
|
APPLICATION_NAME = "Google Calendar API Python" |
|
|
|
|
|
|
|
SUN = 6 |
|
|
|
MON = 0 |
|
|
|
@ -27,35 +29,35 @@ def to_dateTime(datetime: datetime.datetime): |
|
|
|
if not datetime.tzinfo: |
|
|
|
datetime = datetime.astimezone() |
|
|
|
zone = tzlocal.get_localzone().zone |
|
|
|
datetime = datetime.isoformat(timespec='seconds') |
|
|
|
return { |
|
|
|
"timeZone": zone, |
|
|
|
"dateTime": datetime, |
|
|
|
} |
|
|
|
datetime = datetime.isoformat(timespec="seconds") |
|
|
|
return {"timeZone": zone, "dateTime": datetime} |
|
|
|
|
|
|
|
|
|
|
|
def from_dateTime(dateTime): |
|
|
|
"""converts to a datetime from json format returned by rest api""" |
|
|
|
timezone = tz.gettz(dateTime['timeZone']) |
|
|
|
datetime = date_parse(dateTime['dateTime']) |
|
|
|
timezone = tz.gettz(dateTime["timeZone"]) |
|
|
|
datetime = date_parse(dateTime["dateTime"]) |
|
|
|
datetime.replace(tzinfo=timezone) |
|
|
|
return datetime |
|
|
|
|
|
|
|
|
|
|
|
class calendar_api(API): |
|
|
|
def __init__(self, |
|
|
|
app_name, |
|
|
|
client_secret_file, |
|
|
|
credentials_dir, |
|
|
|
scopes='https://www.googleapis.com/auth/calendar', |
|
|
|
version='v3', |
|
|
|
): |
|
|
|
super().__init__('calendar', scopes, app_name, |
|
|
|
client_secret_file, credentials_dir, version) |
|
|
|
def __init__( |
|
|
|
self, |
|
|
|
app_name, |
|
|
|
client_secret_file, |
|
|
|
credentials_dir, |
|
|
|
scopes="https://www.googleapis.com/auth/calendar", |
|
|
|
version="v3", |
|
|
|
): |
|
|
|
super().__init__( |
|
|
|
"calendar", scopes, app_name, client_secret_file, credentials_dir, version |
|
|
|
) |
|
|
|
|
|
|
|
self.calendars = self.get_calendars() |
|
|
|
self.ids = dict((calendar['summary'].lower(), calendar['id']) |
|
|
|
for calendar in self.calendars) |
|
|
|
self.ids = dict( |
|
|
|
(calendar["summary"].lower(), calendar["id"]) for calendar in self.calendars |
|
|
|
) |
|
|
|
|
|
|
|
def create_event(self, calendar_id, body): |
|
|
|
|
|
|
|
@ -65,9 +67,8 @@ class calendar_api(API): |
|
|
|
pass |
|
|
|
service = self.service |
|
|
|
event_service = service.events() |
|
|
|
event = event_service.insert( |
|
|
|
calendarId=calendar_id, body=body).execute() |
|
|
|
return event['id'] |
|
|
|
event = event_service.insert(calendarId=calendar_id, body=body).execute() |
|
|
|
return event["id"] |
|
|
|
|
|
|
|
def update_event(self, calendar_id, event_id, body): |
|
|
|
try: |
|
|
|
@ -79,13 +80,17 @@ class calendar_api(API): |
|
|
|
event_service = service.events() |
|
|
|
try: |
|
|
|
event = event_service.get( |
|
|
|
calendarId=calendar_id, eventId=event_id).execute() |
|
|
|
calendarId=calendar_id, eventId=event_id |
|
|
|
).execute() |
|
|
|
except HttpError as e: |
|
|
|
if e.resp.status == 404: |
|
|
|
return self.create_event(calendar_id, body) |
|
|
|
|
|
|
|
updated_event = service.events().update( |
|
|
|
calendarId=calendar_id, eventId=event['id'], body=body).execute() |
|
|
|
updated_event = ( |
|
|
|
service.events() |
|
|
|
.update(calendarId=calendar_id, eventId=event["id"], body=body) |
|
|
|
.execute() |
|
|
|
) |
|
|
|
return updated_event["id"] |
|
|
|
|
|
|
|
def get_calendars(self): |
|
|
|
@ -95,11 +100,9 @@ class calendar_api(API): |
|
|
|
while page_token or first: |
|
|
|
first = False |
|
|
|
calendar_list_service = self.service.calendarList() |
|
|
|
calendar_list = calendar_list_service.list( |
|
|
|
pageToken=page_token).execute() |
|
|
|
cl += list( |
|
|
|
calendar_entry for calendar_entry in calendar_list['items']) |
|
|
|
page_token = calendar_list.get('nextPageToken') |
|
|
|
calendar_list = calendar_list_service.list(pageToken=page_token).execute() |
|
|
|
cl += list(calendar_entry for calendar_entry in calendar_list["items"]) |
|
|
|
page_token = calendar_list.get("nextPageToken") |
|
|
|
return cl |
|
|
|
|
|
|
|
def get_events(self, cal_id): |
|
|
|
@ -113,9 +116,10 @@ class calendar_api(API): |
|
|
|
while True: |
|
|
|
event_service = service.events() |
|
|
|
events = event_service.list( |
|
|
|
calendarId=cal_id, pageToken=page_token).execute() |
|
|
|
ret += events['items'] |
|
|
|
page_token = events.get('nextPageToken') |
|
|
|
calendarId=cal_id, pageToken=page_token |
|
|
|
).execute() |
|
|
|
ret += events["items"] |
|
|
|
page_token = events.get("nextPageToken") |
|
|
|
if not page_token: |
|
|
|
break |
|
|
|
return ret |
|
|
|
@ -130,17 +134,18 @@ class calendar_api(API): |
|
|
|
class Event: |
|
|
|
"""Model for a calendar event that can be uploaded""" |
|
|
|
|
|
|
|
def __init__(self, |
|
|
|
start, |
|
|
|
end, |
|
|
|
name, |
|
|
|
description=None, |
|
|
|
recurrence=None, |
|
|
|
reminders=None, |
|
|
|
attendees=None, |
|
|
|
location=None, |
|
|
|
id=None |
|
|
|
): |
|
|
|
def __init__( |
|
|
|
self, |
|
|
|
start, |
|
|
|
end, |
|
|
|
name, |
|
|
|
description=None, |
|
|
|
recurrence=None, |
|
|
|
reminders=None, |
|
|
|
attendees=None, |
|
|
|
location=None, |
|
|
|
id=None, |
|
|
|
): |
|
|
|
self.start = start |
|
|
|
self.attendees = attendees |
|
|
|
self.end = end |
|
|
|
@ -150,43 +155,42 @@ class Event: |
|
|
|
self.recurrence = recurrence |
|
|
|
self.id = id |
|
|
|
if reminders is None: |
|
|
|
self.reminders = {'useDefault': True} |
|
|
|
self.reminders = {"useDefault": True} |
|
|
|
else: |
|
|
|
self.reminders = reminders |
|
|
|
|
|
|
|
def add_reminder(self, until, method='popup'): |
|
|
|
def add_reminder(self, until, method="popup"): |
|
|
|
"""Add a reminder minutes before an event. |
|
|
|
Use either a notification (popup) or email""" |
|
|
|
assert method in ("email", "popup") |
|
|
|
self.reminders['useDefault'] = False |
|
|
|
self.reminders["useDefault"] = False |
|
|
|
if isinstance(until, datetime.timedelta): |
|
|
|
minutes_until = until.days * 24 * 60 |
|
|
|
minutes_until += until.seconds//60 |
|
|
|
minutes_until += until.seconds // 60 |
|
|
|
else: |
|
|
|
minutes_until = until |
|
|
|
self.reminders.setdefault('overrides', []).append({ |
|
|
|
'method': method, |
|
|
|
'minutes': minutes_until, |
|
|
|
}) |
|
|
|
self.reminders.setdefault("overrides", []).append( |
|
|
|
{"method": method, "minutes": minutes_until} |
|
|
|
) |
|
|
|
|
|
|
|
def add_weekly_recurrence(self, until: datetime.datetime, *days): |
|
|
|
if not until.tzinfo: |
|
|
|
until = until.astimezone() |
|
|
|
ret = rrule.rrule(freq=rrule.WEEKLY, dtstart=self.start, |
|
|
|
wkst=SUN, until=until, byweekday=days) |
|
|
|
ret_str = str(ret).split('\n')[-1] |
|
|
|
ret_str = re.sub(r'(UNTIL=[^;]+)', r'\1Z', ret_str) |
|
|
|
ret = rrule.rrule( |
|
|
|
freq=rrule.WEEKLY, dtstart=self.start, wkst=SUN, until=until, byweekday=days |
|
|
|
) |
|
|
|
ret_str = str(ret).split("\n")[-1] |
|
|
|
ret_str = re.sub(r"(UNTIL=[^;]+)", r"\1Z", ret_str) |
|
|
|
if self.recurrence is None: |
|
|
|
self.recurrence = [] |
|
|
|
self.recurrence.append(ret_str) |
|
|
|
|
|
|
|
def to_json(self): |
|
|
|
keys = ('attendees', 'description', 'location', |
|
|
|
'recurrence', 'reminders') |
|
|
|
keys = ("attendees", "description", "location", "recurrence", "reminders") |
|
|
|
ret = { |
|
|
|
'summary': self.name, |
|
|
|
'start': to_dateTime(self.start), |
|
|
|
'end': to_dateTime(self.end), |
|
|
|
"summary": self.name, |
|
|
|
"start": to_dateTime(self.start), |
|
|
|
"end": to_dateTime(self.end), |
|
|
|
} |
|
|
|
for key in keys: |
|
|
|
try: |
|
|
|
@ -203,11 +207,10 @@ class Event: |
|
|
|
@classmethod |
|
|
|
def from_json(cls, body): |
|
|
|
args = {} |
|
|
|
args['name'] = body.get('summary', 'unnamed') |
|
|
|
args['start'] = from_dateTime(body['start']) |
|
|
|
args['end'] = from_dateTime(body['end']) |
|
|
|
keys = ('attendees', 'description', 'location', |
|
|
|
'recurrence', 'reminders', 'id') |
|
|
|
args["name"] = body.get("summary", "unnamed") |
|
|
|
args["start"] = from_dateTime(body["start"]) |
|
|
|
args["end"] = from_dateTime(body["end"]) |
|
|
|
keys = ("attendees", "description", "location", "recurrence", "reminders", "id") |
|
|
|
for key in keys: |
|
|
|
try: |
|
|
|
args[key] = body[key] |
|
|
|
@ -234,41 +237,42 @@ class Event: |
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
import os |
|
|
|
|
|
|
|
# ~~BODY EXAMPLE~~##~~BODY EXAMPLE~~ |
|
|
|
example = { |
|
|
|
'attendees': [{'email': 'lpage@example.com'}, |
|
|
|
{'email': 'sbrin@example.com'}], |
|
|
|
'description': "A chance to hear more about Google's\ |
|
|
|
"attendees": [{"email": "lpage@example.com"}, {"email": "sbrin@example.com"}], |
|
|
|
"description": "A chance to hear more about Google's\ |
|
|
|
developer products.", |
|
|
|
'end': {'dateTime': '2015-05-28T17:00:00-07:00', |
|
|
|
'timeZone': 'America/Los_Angeles'}, |
|
|
|
'location': '800 Howard St., San Francisco, CA 94103', |
|
|
|
'recurrence': ['RRULE:FREQ=DAILY;COUNT=2'], |
|
|
|
'reminders': {'overrides': [ |
|
|
|
{ |
|
|
|
'method': 'email', |
|
|
|
'minutes': 1440 |
|
|
|
}, |
|
|
|
{ |
|
|
|
'method': 'popup', |
|
|
|
'minutes': 10 |
|
|
|
} |
|
|
|
], |
|
|
|
'useDefault': False}, |
|
|
|
'start': {'dateTime': '2015-05-28T09:00:00-07:00', |
|
|
|
'timeZone': 'America/Los_Angeles'}, |
|
|
|
'summary': 'Google I/O 2015' |
|
|
|
"end": { |
|
|
|
"dateTime": "2015-05-28T17:00:00-07:00", |
|
|
|
"timeZone": "America/Los_Angeles", |
|
|
|
}, |
|
|
|
"location": "800 Howard St., San Francisco, CA 94103", |
|
|
|
"recurrence": ["RRULE:FREQ=DAILY;COUNT=2"], |
|
|
|
"reminders": { |
|
|
|
"overrides": [ |
|
|
|
{"method": "email", "minutes": 1440}, |
|
|
|
{"method": "popup", "minutes": 10}, |
|
|
|
], |
|
|
|
"useDefault": False, |
|
|
|
}, |
|
|
|
"start": { |
|
|
|
"dateTime": "2015-05-28T09:00:00-07:00", |
|
|
|
"timeZone": "America/Los_Angeles", |
|
|
|
}, |
|
|
|
"summary": "Google I/O 2015", |
|
|
|
} |
|
|
|
e = Event( |
|
|
|
date_parse('march 16, 2019 10:00 am'), |
|
|
|
date_parse('march 16, 2019 3:30 pm'), |
|
|
|
'Hang out with Matt' |
|
|
|
date_parse("march 16, 2019 10:00 am"), |
|
|
|
date_parse("march 16, 2019 3:30 pm"), |
|
|
|
"Hang out with Matt", |
|
|
|
) |
|
|
|
path = r"C:\Users\Raphael\Documents\local_repo\cred" |
|
|
|
my_api = my_api = calendar_api('python', os.path.join( |
|
|
|
path, 'client_secret.json', path), path) |
|
|
|
cal_id = 'raphael.roberts48@gmail.com' |
|
|
|
e2 = Event.from_id(my_api, cal_id, 'qmrsd88ma8ko67ri98d8pbhd7s') |
|
|
|
my_api = my_api = calendar_api( |
|
|
|
"python", os.path.join(path, "client_secret.json", path), path |
|
|
|
) |
|
|
|
cal_id = "raphael.roberts48@gmail.com" |
|
|
|
e2 = Event.from_id(my_api, cal_id, "qmrsd88ma8ko67ri98d8pbhd7s") |
|
|
|
until = datetime.datetime.today() + datetime.timedelta(days=20) |
|
|
|
e2.add_weekly_recurrence(until, MON, TUE) |
|
|
|
# e2.upload(my_api, cal_id) |