-
-
Save natejgreene/99b88ab17296f89e93af to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
#heavy use of https://github.com/oeey/gcalendar Thanks oeey! | |
import httplib2 | |
import sys | |
import time | |
import BaseHTTPServer | |
import urlparse | |
import urllib | |
from apiclient.discovery import build | |
from oauth2client.file import Storage | |
from oauth2client.client import AccessTokenRefreshError | |
from oauth2client.client import OAuth2WebServerFlow | |
from oauth2client.tools import run_flow | |
from oauth2client.client import flow_from_clientsecrets | |
from xml.sax.saxutils import escape | |
HOST_NAME = '192.168.1.114' # !!!REMEMBER TO CHANGE THIS!!! | |
PORT_NUMBER = 80 | |
ACCOUNT_EMAIL_ADDRESS = 'example@gmail.com' | |
ACCOUNT_NAME = 'John Doe' | |
CALENDAR_NAME = 'Our Calendar' | |
CALENDAR_ID = '[id]@group.calendar.google.com' | |
class GoogleCalendarV3ToV2: | |
def get_service(self): | |
scope = 'https://www.googleapis.com/auth/calendar' | |
flow = flow_from_clientsecrets('client_secret.json', scope=scope) | |
storage = Storage('credentials.dat') | |
credentials = storage.get() | |
class fakeargparse(object): # fake argparse.Namespace | |
noauth_local_webserver = True | |
logging_level = "ERROR" | |
flags = fakeargparse() | |
if credentials is None or credentials.invalid: | |
credentials = run_flow(flow, storage, flags) | |
http = httplib2.Http() | |
http = credentials.authorize(http) | |
return build('calendar', 'v3', http=http) | |
def get_calendar(self): | |
response = """<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/' xmlns:gCal='http://schemas.google.com/gCal/2005' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='etagblah'> | |
<id>http://www.google.com/calendar/feeds/default/allcalendars/full</id> | |
<updated>2014-11-18T01:01:59.657Z</updated> | |
<title>{0}</title> | |
<link rel='alternate' type='text/html' href='http://www.google.com/calendar/render' /> | |
<link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full' /> | |
<link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full' /> | |
<link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full' /> | |
<author> | |
<name>{0}</name> | |
<email>{1}</email> | |
</author> | |
<generator version='1.0' uri='http://www.google.com/calendar'>Google Calendar</generator> | |
<openSearch:startIndex>1</openSearch:startIndex>""".format(ACCOUNT_NAME, ACCOUNT_EMAIL_ADDRESS) | |
page_token = None | |
while True: | |
calendar_list = self.get_service().calendarList().list(pageToken=page_token).execute() | |
for calendar_list_entry in calendar_list['items']: | |
if calendar_list_entry['summary'] == CALENDAR_NAME: | |
temp="""<entry gd:etag='{0}'> | |
<id>http://www.google.com/calendar/feeds/default/allcalendars/full/{6}/{5}</id> | |
<published>2014-07-11T22:10:30.257Z</published> | |
<updated>2014-07-11T21:46:35.000Z</updated> | |
<title>{1}</title> | |
<summary type='text'>{2}</summary> | |
<link rel='alternate' type='application/atom+xml' href='http://www.google.com/calendar/feeds/{6}/private/full' /> | |
<link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/{6}/private/full' /> | |
<link rel='http://schemas.google.com/acl/2007#accessControlList' type='application/atom+xml' href='http://www.google.com/calendar/feeds/{6}/acl/full' /> | |
<link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/{6}' /> | |
<link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/{6}' /> | |
<author> | |
<name>{7}</name> | |
<email>{6}</email> | |
</author> | |
<gCal:timezone value='{3}' /> | |
<gCal:hidden value='false' /> | |
<gCal:color value='#42d692' /> | |
<gCal:selected value='true' /> | |
<gCal:accesslevel value='owner' /> | |
<gd:where valueString='{4}' /> | |
</entry>""" | |
response+=temp.format(calendar_list_entry['etag'], | |
calendar_list_entry['summary'], | |
calendar_list_entry['summary'], | |
calendar_list_entry['timeZone'], | |
"Minneapolis", | |
calendar_list_entry['id'], | |
ACCOUNT_EMAIL_ADDRESS, | |
ACCOUNT_NAME) | |
page_token = calendar_list.get('nextPageToken') | |
if not page_token: | |
break | |
response+="</feed>" | |
return response | |
def get_events(self, startmin, endmax, tz): | |
response="""<feed xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='etagblah'> | |
<id>http://www.google.com/calendar/feeds/{2}/private/composite</id> | |
<updated>2014-03-29T07:35:59.000Z</updated> | |
<title type='text'>{0}</title> | |
<subtitle type='text'>This is my main calendar.</subtitle> | |
<link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/{2}/private/composite'></link> | |
<link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/{2}/private/composite'></link> | |
<author> | |
<name>{1}</name> | |
<email>{2}</email> | |
</author> | |
<generator version='1.0' uri='http://www.google.com/calendar/'>CL2</generator> | |
<gd:where valueString='Minnesota'></gd:where>""".format(CALENDAR_NAME, ACCOUNT_NAME, ACCOUNT_EMAIL_ADDRESS) | |
events = self.get_service().events().list(calendarId=CALENDAR_ID, timeZone=tz, timeMin=startmin+'Z', timeMax=endmax+'Z', singleEvents=True).execute() | |
for event in events['items']: | |
temp="""<entry gd:etag='{0}'> | |
<id>urn:id:{1}</id> | |
<published>{8}</published> | |
<updated>{9}</updated> | |
<category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category> | |
<title type='text'>{2}</title> | |
<content type='text'>{3}</content> | |
<link rel='alternate' type='text/html' href='http://www.google.com/calendar/event?eid={1}' title='alternate'></link> | |
<link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/{12}/private/composite/{1}'></link> | |
<link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/{12}/private/composite/{1}'></link> | |
<author> | |
<name>{6}</name> | |
<email>{7}</email> | |
</author> | |
<gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency> | |
<gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus> | |
<gd:comments> | |
<gd:feedLink href='http://www.google.com/calendar/feeds/{12}/private/composite/{1}/comments/'></gd:feedLink> | |
</gd:comments> | |
<gd:when startTime='{4}' endTime='{5}'></gd:when> | |
<gd:where></gd:where> | |
</entry>""" | |
response+=temp.format(event["etag"], | |
event["id"], | |
escape(event["summary"]), | |
escape(event["summary"]), | |
self.d(event["start"]), | |
self.d(event["end"]), | |
event['creator']['displayName'], | |
event['creator']['email'], | |
self.get(event,'updated'), | |
self.get(event,'updated'), | |
escape(self.get(event,'location')), | |
ACCOUNT_NAME, | |
ACCOUNT_EMAIL_ADDRESS) | |
response+="</feed>" | |
return response | |
def d(self, d): | |
if 'dateTime' in d: | |
return d['dateTime'] | |
elif 'date' in d: | |
return d['date'] | |
else: | |
return '' | |
def get(self, hash,key): | |
if key in hash: | |
return hash[key] | |
else: | |
return '' | |
class GoogleServerHandler(BaseHTTPServer.BaseHTTPRequestHandler): | |
def do_HEAD(self): | |
self.send_response(200) | |
self.send_header("Content-type", "text/xml") | |
self.end_headers() | |
def do_POST(self): | |
self.send_response(200) | |
self.end_headers() | |
self.wfile.write("Auth=SomeFuckingToken") | |
def do_GET(self): | |
cal = GoogleCalendarV3ToV2() | |
self.path = self.path.replace('composite&ctz','composite?ctz') #well not sure why the app is sending this. | |
parsed_path = urlparse.urlparse(self.path) | |
self.send_response(200) | |
qs = urlparse.parse_qs(parsed_path.query) | |
if parsed_path.path == '/calendar/feeds/default/allcalendars/full': | |
self.send_header("Content-type", "application/atom+xml") | |
self.end_headers() | |
self.wfile.write(cal.get_calendar()) | |
if parsed_path.path == '/calendar/feeds/' + ACCOUNT_EMAIL_ADDRESS + '/private/composite': | |
self.send_header("Content-type", "application/atom+xml") | |
self.end_headers() | |
self.wfile.write(cal.get_events(qs['start-min'][0], qs['start-max'][0], qs['ctz'][0])) | |
if __name__ == '__main__': | |
server_class = BaseHTTPServer.HTTPServer | |
httpd = server_class((HOST_NAME, PORT_NUMBER), GoogleServerHandler) | |
print time.asctime(), "Server Starts - %s:%s" % (HOST_NAME, PORT_NUMBER) | |
try: | |
httpd.serve_forever() | |
except KeyboardInterrupt: | |
pass | |
httpd.server_close() | |
print time.asctime(), "Server Stops - %s:%s" % (HOST_NAME, PORT_NUMBER) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment