You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
8.5 KiB

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
else:
from gapi.api import API
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
APPLICATION_NAME = "Google Calendar API Python"
SUN = 6
MON = 0
TUE = 1
WED = 2
THU = 3
FRI = 4
SAT = 5
def to_dateTime(datetime: datetime.datetime):
"""converts a datetime into json format for rest api"""
if not datetime.tzinfo:
datetime = datetime.astimezone()
zone = tzlocal.get_localzone().zone
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"])
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
)
self.calendars = self.get_calendars()
self.ids = dict(
(calendar["summary"].lower(), calendar["id"]) for calendar in self.calendars
)
def create_event(self, calendar_id, body):
try:
calendar_id = self.ids[calendar_id]
except KeyError:
pass
service = self.service
event_service = service.events()
event = event_service.insert(calendarId=calendar_id, body=body).execute()
return event["id"]
def update_event(self, calendar_id, event_id, body):
try:
calendar_id = self.ids[calendar_id]
except KeyError:
pass
service = self.service
event_service = service.events()
try:
event = event_service.get(
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()
)
return updated_event["id"]
def get_calendars(self):
page_token = None
cl = []
first = True
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")
return cl
def get_events(self, cal_id):
service = self.service
try:
cal_id = self.ids[cal_id]
except KeyError:
pass
page_token = None
ret = []
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")
if not page_token:
break
return ret
def get_event_by_id(self, cal_id, event_id):
"""Retrieves event from cal_id and event_id"""
service = self.service
event_service = service.events()
return event_service.get(calendarId=cal_id, eventId=event_id).execute()
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,
):
self.start = start
self.attendees = attendees
self.end = end
self.name = name
self.description = description
self.location = location
self.recurrence = recurrence
self.id = id
if reminders is None:
self.reminders = {"useDefault": True}
else:
self.reminders = reminders
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
if isinstance(until, datetime.timedelta):
minutes_until = until.days * 24 * 60
minutes_until += until.seconds // 60
else:
minutes_until = 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)
if self.recurrence is None:
self.recurrence = []
self.recurrence.append(ret_str)
def to_json(self):
keys = ("attendees", "description", "location", "recurrence", "reminders")
ret = {
"summary": self.name,
"start": to_dateTime(self.start),
"end": to_dateTime(self.end),
}
for key in keys:
try:
value = self.__getattribute__(key)
if value:
ret[key] = value
except AttributeError:
pass
return ret
def add_attendees(self):
pass
@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")
for key in keys:
try:
args[key] = body[key]
except KeyError:
pass
instance = cls(**args)
return instance
@classmethod
def from_id(cls, api: calendar_api, calendar_id, event_id):
"""creates an event model from specified calendar and event_id"""
event = api.get_event_by_id(calendar_id, event_id)
return cls.from_json(event)
def upload(self, api: calendar_api, calendar_id):
"""Upload an event to calendar.
Either modifies an event in place or creates a new event."""
if self.id is not None:
event_id = api.update_event(calendar_id, self.id, self.to_json())
else:
event_id = api.create_event(calendar_id, self.to_json())
return event_id
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\
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",
}
e = Event(
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")
until = datetime.datetime.today() + datetime.timedelta(days=20)
e2.add_weekly_recurrence(until, MON, TUE)
# e2.upload(my_api, cal_id)