commit
58dea7c7f6
3 changed files with 288 additions and 0 deletions
@ -0,0 +1,123 @@ |
|||
ntnoe_credentials |
|||
|
|||
|
|||
# Created by https://www.gitignore.io/api/vim,python |
|||
|
|||
### Python ### |
|||
# Byte-compiled / optimized / DLL files |
|||
__pycache__/ |
|||
*.py[cod] |
|||
*$py.class |
|||
|
|||
# C extensions |
|||
*.so |
|||
|
|||
# Distribution / packaging |
|||
.Python |
|||
build/ |
|||
develop-eggs/ |
|||
dist/ |
|||
downloads/ |
|||
eggs/ |
|||
.eggs/ |
|||
lib/ |
|||
lib64/ |
|||
parts/ |
|||
sdist/ |
|||
var/ |
|||
wheels/ |
|||
*.egg-info/ |
|||
.installed.cfg |
|||
*.egg |
|||
|
|||
# PyInstaller |
|||
# Usually these files are written by a python script from a template |
|||
# before PyInstaller builds the exe, so as to inject date/other infos into it. |
|||
*.manifest |
|||
*.spec |
|||
|
|||
# Installer logs |
|||
pip-log.txt |
|||
pip-delete-this-directory.txt |
|||
|
|||
# Unit test / coverage reports |
|||
htmlcov/ |
|||
.tox/ |
|||
.coverage |
|||
.coverage.* |
|||
.cache |
|||
nosetests.xml |
|||
coverage.xml |
|||
*.cover |
|||
.hypothesis/ |
|||
|
|||
# Translations |
|||
*.mo |
|||
*.pot |
|||
|
|||
# Django stuff: |
|||
*.log |
|||
local_settings.py |
|||
|
|||
# Flask stuff: |
|||
instance/ |
|||
.webassets-cache |
|||
|
|||
# Scrapy stuff: |
|||
.scrapy |
|||
|
|||
# Sphinx documentation |
|||
docs/_build/ |
|||
|
|||
# PyBuilder |
|||
target/ |
|||
|
|||
# Jupyter Notebook |
|||
.ipynb_checkpoints |
|||
|
|||
# pyenv |
|||
.python-version |
|||
|
|||
# celery beat schedule file |
|||
celerybeat-schedule |
|||
|
|||
# SageMath parsed files |
|||
*.sage.py |
|||
|
|||
# Environments |
|||
.env |
|||
.venv |
|||
env/ |
|||
venv/ |
|||
ENV/ |
|||
env.bak/ |
|||
venv.bak/ |
|||
|
|||
# Spyder project settings |
|||
.spyderproject |
|||
.spyproject |
|||
|
|||
# Rope project settings |
|||
.ropeproject |
|||
|
|||
# mkdocs documentation |
|||
/site |
|||
|
|||
# mypy |
|||
.mypy_cache/ |
|||
|
|||
### Vim ### |
|||
# swap |
|||
[._]*.s[a-v][a-z] |
|||
[._]*.sw[a-p] |
|||
[._]s[a-v][a-z] |
|||
[._]sw[a-p] |
|||
# session |
|||
Session.vim |
|||
# temporary |
|||
.netrwhist |
|||
*~ |
|||
# auto-generated tag files |
|||
tags |
|||
|
|||
# End of https://www.gitignore.io/api/vim,python |
|||
@ -0,0 +1,163 @@ |
|||
import datetime |
|||
import httplib2 |
|||
import urllib |
|||
import os |
|||
|
|||
from apiclient import discovery |
|||
from oauth2client import client |
|||
from oauth2client import tools |
|||
from oauth2client.file import Storage |
|||
|
|||
import icalendar |
|||
|
|||
|
|||
TIMEDELTA_SYNCHRO = datetime.timedelta(days=4) # 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: |
|||
# ColorId corresponding to course code |
|||
EVENT_COLOR = { |
|||
'9' : '9', # Amphi |
|||
'11' : '10', # TL |
|||
'10' : '6', # TD |
|||
'13' : '5', # Autre |
|||
'12' : '3', # Exam |
|||
|
|||
} |
|||
|
|||
def __init__(self, e): |
|||
""" Initialize an event from a `icalendar.cal.Event`.""" |
|||
self.summary = e.decoded('SUMMARY').decode('utf-8') |
|||
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') |
|||
|
|||
def __str__(self): |
|||
return str(self.as_google()) |
|||
|
|||
def as_google(self): |
|||
return { |
|||
'summary' : self.summary, |
|||
'location' : self.location, |
|||
'start' : { |
|||
'dateTime' : self.start.isoformat(), |
|||
'timeZone' : 'Europe/Paris', |
|||
}, |
|||
'end' : { |
|||
'dateTime' : self.end.isoformat(), |
|||
'timeZone' : 'Europe/Paris', |
|||
}, |
|||
'colorId' : self.colorid, |
|||
'reminders': { |
|||
'useDefault': False, |
|||
'overrides': [], |
|||
}, |
|||
|
|||
} |
|||
|
|||
|
|||
def get_credentials(): |
|||
"""Gets valid user credentials from storage. |
|||
|
|||
If nothing has been stored, or if the stored credentials are invalid, |
|||
the OAuth2 flow is completed to obtain the new credentials. |
|||
|
|||
Returns: |
|||
Credentials, the obtained credential. |
|||
""" |
|||
home_dir = os.path.expanduser('~') |
|||
credential_dir = os.path.join(home_dir, '.credentials') |
|||
if not os.path.exists(credential_dir): |
|||
os.makedirs(credential_dir) |
|||
credential_path = os.path.join(credential_dir, 'ntnoe.json') |
|||
|
|||
store = Storage(credential_path) |
|||
credentials = store.get() |
|||
if not credentials or credentials.invalid: |
|||
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES) |
|||
flow.user_agent = APPLICATION_NAME |
|||
print('Storing credentials to ' + credential_path) |
|||
credentials = tools.run_flow(flow, store) |
|||
|
|||
return credentials |
|||
|
|||
|
|||
def get_ntnoe(): |
|||
url = "http://ntnoe.metz.supelec.fr/ical/EdTcustom/Eleves/edt_{}.ics" |
|||
url = url.format(NTNOE_ID) |
|||
|
|||
h = httplib2.Http() |
|||
h.add_credentials(NTNOE_ID,NTNOE_PASS) |
|||
data = {'envoyer':'Utf8_All','submit':'G%E9n%E9rer'} |
|||
|
|||
h.request( |
|||
"https://ntnoe.metz.supelec.fr/ical/index.php", |
|||
body=urllib.parse.urlencode(data), |
|||
method='POST', |
|||
) |
|||
# resp,content = h.request( |
|||
# "https://ntnoe.metz.supelec.fr/ical/EdTcustom/Eleves/edt_{id}.ics".format(id=NTNOE_ID), |
|||
# ) |
|||
# print(resp,content) |
|||
# TODO : download from ntnoe |
|||
|
|||
|
|||
|
|||
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()) |
|||
|
|||
now = datetime.datetime.now() |
|||
then = now + TIMEDELTA_SYNCHRO |
|||
response = service.events().list( |
|||
calendarId='primary', |
|||
timeMin=now.isoformat()+'Z', |
|||
timeMax=then.isoformat()+'Z', |
|||
).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'): |
|||
event = Event(e) |
|||
t = ( |
|||
event.summary, |
|||
event.start.isoformat(), |
|||
event.end.isoformat(), |
|||
event.location |
|||
) |
|||
if now >= event.end or event.start >= then: |
|||
continue |
|||
|
|||
if existing_events.intersection({event.summary}): |
|||
continue |
|||
else: |
|||
print(event.summary) |
|||
|
|||
event = service.events().insert( |
|||
calendarId='primary', |
|||
body=event.as_google() |
|||
).execute() |
|||
print("Added event : {}".format(event.get('htmlLink'))) |
|||
|
|||
if __name__ == '__main__': |
|||
main() |
|||
|
|||
@ -0,0 +1,2 @@ |
|||
nom_pre |
|||
ThisIsASecretPassword |
|||
Loading…
Reference in new issue