|
|
|
@ -1,9 +1,38 @@ |
|
|
|
""" |
|
|
|
NTNOE SYNC is a simple script tha allows you to synchronize your NTNOE diary |
|
|
|
with Google Calendar. |
|
|
|
|
|
|
|
It will create a `ntnoe` calendar among your Google calendars and write your |
|
|
|
NTNOE calendar into. NTNOE_SYNC is availabe under the MIT license. |
|
|
|
|
|
|
|
|
|
|
|
MIT License |
|
|
|
|
|
|
|
Copyright (c) 2017 Hugo LEVY-FALK |
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
|
|
of this software and associated documentation files (the "Software"), to deal |
|
|
|
in the Software without restriction, including without limitation the rights |
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
|
|
copies of the Software, and to permit persons to whom the Software is |
|
|
|
furnished to do so, subject to the following conditions: |
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all |
|
|
|
copies or substantial portions of the Software. |
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
|
|
SOFTWARE. |
|
|
|
""" |
|
|
|
|
|
|
|
import datetime |
|
|
|
import httplib2 |
|
|
|
import urllib |
|
|
|
import os |
|
|
|
import requests |
|
|
|
import shutil |
|
|
|
|
|
|
|
from apiclient import discovery |
|
|
|
from oauth2client import client |
|
|
|
@ -13,18 +42,22 @@ from oauth2client.file import Storage |
|
|
|
import icalendar |
|
|
|
|
|
|
|
|
|
|
|
TIMEDELTA_SYNCHRO = datetime.timedelta(days=7) # Number of days to look for |
|
|
|
TIMEDELTA_SYNCHRO = datetime.timedelta(days=15) # Number of days to look for |
|
|
|
# for synchronization |
|
|
|
|
|
|
|
with open('ntnoe_credentials') as f: |
|
|
|
NTNOE_ID, NTNOE_PASS, _ = f.read().split('\n') |
|
|
|
|
|
|
|
|
|
|
|
SCOPES = 'https://www.googleapis.com/auth/calendar' |
|
|
|
CLIENT_SECRET_FILE = 'client_secret.json' |
|
|
|
APPLICATION_NAME = 'Google Calendar API Python Quickstart' |
|
|
|
|
|
|
|
|
|
|
|
class Event: |
|
|
|
""" |
|
|
|
The event class allows a simple convertion between `icalendar.cal.Event` |
|
|
|
and a formatted `dict` for the google API. |
|
|
|
""" |
|
|
|
|
|
|
|
# ColorId corresponding to course code |
|
|
|
EVENT_COLOR = { |
|
|
|
'9': '9', # Amphi |
|
|
|
@ -41,12 +74,14 @@ class Event: |
|
|
|
self.start = e.decoded('DTSTART') |
|
|
|
self.end = e.decoded('DTEND') |
|
|
|
self.location = e.decoded('LOCATION').decode('utf-8') |
|
|
|
self.colorid = self.EVENT_COLOR.get(e.decoded('DESCRIPTION').decode('utf-8'), '1') |
|
|
|
self.colorid = self.EVENT_COLOR.get( |
|
|
|
e.decoded('DESCRIPTION').decode('utf-8'), '1') |
|
|
|
|
|
|
|
def __str__(self): |
|
|
|
return str(self.as_google()) |
|
|
|
|
|
|
|
def as_google(self): |
|
|
|
"""Returns the event as a formatted `dict` for the google API.""" |
|
|
|
return { |
|
|
|
'summary': self.summary, |
|
|
|
'location': self.location, |
|
|
|
@ -63,6 +98,7 @@ class Event: |
|
|
|
'useDefault': False, |
|
|
|
'overrides': [], |
|
|
|
}, |
|
|
|
'description': 'ntnoe_calendar', |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
@ -94,48 +130,58 @@ def get_credentials(): |
|
|
|
|
|
|
|
|
|
|
|
def get_ntnoe(): |
|
|
|
url = "http://ntnoe.metz.supelec.fr/ical/EdTcustom/Eleves/edt_{}.ics" |
|
|
|
url = url.format(NTNOE_ID) |
|
|
|
|
|
|
|
data = {'envoyer':'Utf8_All','submit':'Générer'} |
|
|
|
|
|
|
|
r = requests.get( |
|
|
|
"""Retrieves the calendar on NTNOE.""" |
|
|
|
r = requests.post( |
|
|
|
"https://ntnoe.metz.supelec.fr/ical/index.php", |
|
|
|
data=urllib.parse.urlencode(data), |
|
|
|
data={"envoyer":"Utf8_All","submit":"G%E9n%E9rer"}, |
|
|
|
auth=(NTNOE_ID, NTNOE_PASS), |
|
|
|
) |
|
|
|
url = "https://ntnoe.metz.supelec.fr/ical/EdTcustom/Eleves/edt_{id}.ics".format(id=NTNOE_ID) |
|
|
|
r = requests.get(url, auth=(NTNOE_ID, NTNOE_PASS), stream=True) |
|
|
|
with open("edt_{}.ics".format(NTNOE_ID), 'wb') as f: |
|
|
|
f.write(r.content) |
|
|
|
|
|
|
|
url = "https://ntnoe.metz.supelec.fr/ical/EdTcustom/Eleves/edt_{}.ics" |
|
|
|
url = url.format(NTNOE_ID) |
|
|
|
r = requests.get(url, auth=(NTNOE_ID, NTNOE_PASS)) |
|
|
|
return r.content |
|
|
|
|
|
|
|
def main(): |
|
|
|
"""Get the events on NTNOE the puts them on Google Calendar. |
|
|
|
|
|
|
|
""" |
|
|
|
get_ntnoe() |
|
|
|
credentials = get_credentials() |
|
|
|
http = credentials.authorize(httplib2.Http()) |
|
|
|
service = discovery.build('calendar', 'v3', http=http) |
|
|
|
|
|
|
|
with open("edt_" + NTNOE_ID + ".ics") as f: |
|
|
|
c = icalendar.Calendar.from_ical(f.read()) |
|
|
|
ical = icalendar.Calendar.from_ical(get_ntnoe()) |
|
|
|
|
|
|
|
calendars = service.calendarList().list().execute() |
|
|
|
ntnoe_calendar_id = None |
|
|
|
for c in calendars['items']: |
|
|
|
if c['summary'] == 'ntnoe': |
|
|
|
ntnoe_calendar_id = c['id'] |
|
|
|
|
|
|
|
if not ntnoe_calendar_id: |
|
|
|
print("Creating ntnoe calendar...") |
|
|
|
created = service.calendars().insert(body={ |
|
|
|
'defaultReminders' : [], |
|
|
|
'selected' : True, |
|
|
|
'summary' : 'ntnoe', |
|
|
|
}).execute() |
|
|
|
ntnoe_calendar_id = created['id'] |
|
|
|
|
|
|
|
now = datetime.datetime.now() |
|
|
|
then = now + TIMEDELTA_SYNCHRO |
|
|
|
time_search = datetime.datetime(now.year, now.month, now.day, 1) |
|
|
|
response = service.events().list( |
|
|
|
calendarId='primary', |
|
|
|
timeMin=time_search.isoformat()+'Z', |
|
|
|
timeMax=then.isoformat()+'Z', |
|
|
|
|
|
|
|
former_ones = service.events().list( |
|
|
|
calendarId=ntnoe_calendar_id, |
|
|
|
).execute() |
|
|
|
|
|
|
|
for event in former_ones['items']: |
|
|
|
print('Deleting event : {}'.format(event['id'])) |
|
|
|
service.events().delete( |
|
|
|
calendarId=ntnoe_calendar_id, |
|
|
|
eventId=event['id'] |
|
|
|
).execute() |
|
|
|
|
|
|
|
existing_events = set() |
|
|
|
for e in response['items']: |
|
|
|
if 'summary' in e.keys(): |
|
|
|
existing_events.add(e['summary']) |
|
|
|
for e in c.walk('VEVENT'): |
|
|
|
for e in ical.walk('VEVENT'): |
|
|
|
event = Event(e) |
|
|
|
t = ( |
|
|
|
event.summary, |
|
|
|
@ -146,15 +192,12 @@ def main(): |
|
|
|
if now >= event.end or event.start >= then: |
|
|
|
continue |
|
|
|
|
|
|
|
if existing_events.intersection({event.summary}): |
|
|
|
continue |
|
|
|
|
|
|
|
event = service.events().insert( |
|
|
|
calendarId='primary', |
|
|
|
calendarId=ntnoe_calendar_id, |
|
|
|
body=event.as_google() |
|
|
|
).execute() |
|
|
|
print("Added event : {}".format(event.get('htmlLink'))) |
|
|
|
print("Adding event : {}".format(event['id'])) |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
main() |
|
|
|
|
|
|
|
|