Browse Source

Redid some of this module's structure. drive_api still needs work

master
Raphael Roberts 6 years ago
parent
commit
0b63b6bd44
  1. 14
      gapi/__init__.py
  2. 0
      gapi/apis/__init__.py
  3. 6
      gapi/apis/base_api.py
  4. 5
      gapi/apis/calendar_api/__init__.py
  5. 98
      gapi/apis/calendar_api/calendar_api.py
  6. 136
      gapi/apis/calendar_api/models.py
  7. 22
      gapi/apis/calendar_api/utils.py
  8. 0
      gapi/apis/drive_api/__init__.py
  9. 0
      gapi/apis/drive_api/drive_api.py
  10. 279
      gapi/calendar_api.py
  11. 14
      gapi/config.py
  12. 46
      tests/event_class.py

14
gapi/__init__.py

@ -0,0 +1,14 @@
import os
import appdirs
app_dirs = appdirs.AppDirs("gapi")
config_dir = app_dirs.user_config_dir
cache_dir = app_dirs.user_cache_dir
log_dir = app_dirs.user_log_dir
state_dir = app_dirs.user_state_dir
for dir in (config_dir, cache_dir, log_dir, state_dir):
if not os.path.exists(dir):
os.makedirs(dir)

0
gapi/apis/__init__.py

gapi/api.py → gapi/apis/base_api.py

5
gapi/apis/calendar_api/__init__.py

@ -0,0 +1,5 @@
import os
from .models import Event
from .calendar_api import calendar_api

98
gapi/apis/calendar_api/calendar_api.py

@ -0,0 +1,98 @@
import os
from googleapiclient.errors import HttpError
import gapi
from gapi.apis.base_api import API
APPLICATION_NAME = "Google Calendar API Python"
class calendar_api(API):
def __init__(
self,
app_name,
client_secret_file=os.path.join(gapi.state_dir, "client_secret.json"),
credentials_dir=gapi.state_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()

136
gapi/apis/calendar_api/models.py

@ -0,0 +1,136 @@
from enum import IntEnum
import datetime
import re
from dateutil import rrule
from .calendar_api import calendar_api
from .utils import to_dateTime, from_dateTime
class weekdays(IntEnum):
SUN = 6
MON = 0
TUE = 1
WED = 2
THU = 3
FRI = 4
SAT = 5
class Calendar:
"""Model for representing a Google calendar"""
pass
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=weekdays.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())
self.id = event_id
return event_id
def delete(self, api: calendar_api):
pass

22
gapi/apis/calendar_api/utils.py

@ -0,0 +1,22 @@
import datetime
import tzlocal
from dateutil import tz
from dateutil.parser import parse as date_parse
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

0
gapi/apis/drive_api/__init__.py

gapi/drive_api.py → gapi/apis/drive_api/drive_api.py

279
gapi/calendar_api.py

@ -1,279 +0,0 @@
import os
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, config
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=os.path.join(config.state_dir, "client_secret.json"),
credentials_dir=config.state_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)

14
gapi/config.py

@ -1,14 +0,0 @@
import os
import appdirs
app_dirs = appdirs.AppDirs("gapi")
config_dir = app_dirs.user_config_dir
cache_dir = app_dirs.user_cache_dir
log_dir = app_dirs.user_log_dir
state_dir = app_dirs.user_state_dir
for dir in (config_dir, cache_dir, log_dir, state_dir):
if not os.path.exists(dir):
os.makedirs(dir)

46
tests/event_class.py

@ -0,0 +1,46 @@
from dateutil.parser import parse as date_parse
from gapi.apis.calendar_api.models import weekdays, Event
from gapi.apis.calendar_api import calendar_api
import datetime
if __name__ == "__main__":
MY_API = calendar_api("fuck google")
# ~~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",
)
CAL_ID = "raphael.roberts48@gmail.com"
event = Event.from_json(example)
id = event.upload(MY_API, CAL_ID)
print(id)
e2 = Event.from_id(MY_API, CAL_ID, id)
until = datetime.datetime.today() + datetime.timedelta(days=20)
e2.add_weekly_recurrence(until, weekdays.MON, weekdays.TUE)
e2.upload(MY_API, CAL_ID)
Loading…
Cancel
Save