diff --git a/gapi/calendar_api.py b/gapi/calendar_api.py index 3112923..ab101e8 100644 --- a/gapi/calendar_api.py +++ b/gapi/calendar_api.py @@ -1,14 +1,15 @@ +from dateutil import rrule, tz +from oauth2client import tools +from dateutil.parser import parse as date_parse +import re +import tzlocal +import argparse +import datetime if __name__ == "__main__": - from api import API + from api import API, HttpError else: - from gapi.api import API + from gapi.api import API, HttpError -import datetime -import argparse -import tzlocal -from dateutil import rrule,tz -from dateutil.parser import parse as date_parse -from oauth2client import tools flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args() APPLICATION_NAME = 'Google Calendar API Python' @@ -20,107 +21,41 @@ THU = 4 FRI = 5 SAT = 6 + def to_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, - } + "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 -#~~BODY EXAMPLE~~# - -class event: - def __init__(self, - start, - end, - name, - description = None, - recurrence = None, - location = None, - id = None - ): - self.start = start - self.end = end - self.summary = name - self.description = description - self.location = location - self.id = id - self.reminders = {'useDefault':True} - - def add_reminder(self,until,method = 'popup'): - self.recurrence['useDefault'] = False - if isinstance(until,datetime.timedelta): - minutes_until = until.days * 24 * 60 - minutes_until += until.seconds//60 - else: - minutes_until = until - self.recurrence['overrides'] = { - 'method':minutes_until, - 'method':method, - } - - def add_weekly_recurrence(self,until,*days): - 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) - try: - self.recurrence - except AttributeError: - self.recurrence = [] - self.recurrence.append(ret_str) - - def to_json(self): - keys = ('attendees', 'description', 'location', 'recurrence', 'reminders', 'summary') - ret = { - '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','unamed') - args['start'] = from_dateTime(body['start']) - args['end'] = from_dateTime(body['end']) - instance = cls(**args) - keys = ('attendees', 'description', 'location', 'recurrence', 'reminders', 'summary') - for key in keys: - try: - args[key] = body[key] - except KeyError: - pass 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) + 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): @@ -129,23 +64,27 @@ class calendar_api(API): except KeyError: pass service = self.service - event = service.events().insert(calendarId=calendar_id, body=body).execute() + event_service = service.events() + event_service.insert(calendarId=calendar_id, body=body).execute() return event['id'] - def update_event(self,calendar_id, event_id, body): + 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 = service.events().get(calendarId=calendar_id, eventId=event_id).execute() + event = event_service.get( + calendarId=calendar_id, eventId=event_id).execute() except HttpError as e: - if e.resp.status==404: + 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): @@ -154,38 +93,156 @@ class calendar_api(API): first = True while page_token or first: first = False - calendar_list = self.service.calendarList().list(pageToken=page_token).execute() - cl += list(calendar_list_entry for calendar_list_entry in calendar_list['items']) + 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,id): + def get_events(self, cal_id): service = self.service try: - id = self.ids[id] + cal_id = self.ids[cal_id] except KeyError: pass page_token = None ret = [] while True: - events = service.events().list(calendarId=id, pageToken=page_token).execute() + 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(cal_id, event_id).execute() + + +class event: + """Model for a calendar event that can be uploaded""" + + def __init__(self, api, + start, + end, + name, + description=None, + recurrence=None, + location=None, + id=None + ): + self.start = start + self.end = end + self.summary = name + self.description = description + self.location = location + self.id = id + self.reminders = {'useDefault': True} + + def add_reminder(self, until, method='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({ + 'minuutes': minutes_until, + 'method': method, + }) + + def add_weekly_recurrence(self, until: datetime.datetime, *days): + 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) + try: + self.recurrence + except AttributeError: + self.recurrence = [] + self.recurrence.append(ret_str) + + def to_json(self): + keys = ('attendees', 'description', 'location', + 'recurrence', 'reminders', 'summary') + ret = { + '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']) + instance = cls(**args) + keys = ('attendees', 'description', 'location', + 'recurrence', 'reminders', 'summary') + for key in keys: + try: + args[key] = body[key] + except KeyError: + pass + 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: + api.update_event(calendar_id, self.id, self.to_json) + else: + api.create_event(calendar_id, self.to_json) + + if __name__ == "__main__": - 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.from_json(example) \ No newline at end of file + # ~~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.from_json(example)