2016-09-17 12:54:44 +02:00
|
|
|
from flask import Flask, request
|
2016-09-17 00:02:27 +02:00
|
|
|
import os
|
2016-09-16 23:58:26 +02:00
|
|
|
import urllib.request
|
|
|
|
from icalendar.cal import Calendar, Component
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
2016-09-17 13:40:30 +02:00
|
|
|
PORT = int(os.environ.get('PORT', 5000))
|
|
|
|
|
|
|
|
BASE_URL = os.environ.get('BASE_URL', None)
|
|
|
|
|
2016-09-17 12:54:44 +02:00
|
|
|
EXCLUDED_COURSES = os.environ.get('COURSES', '').split(',')
|
|
|
|
EXCLUDED_TYPES = os.environ.get('TYPES', '').split(',')
|
2016-09-17 13:27:46 +02:00
|
|
|
|
2016-09-17 12:37:00 +02:00
|
|
|
YEAR = os.environ.get('YEAR', '4')
|
|
|
|
GROUP = os.environ.get('GROUP', '1')
|
2016-09-17 12:54:44 +02:00
|
|
|
ALLOWED_YEARS = os.environ.get('ALLOWED_YEARS', '3,4,5').split(',')
|
|
|
|
ALLOWED_GROUPS = os.environ.get('ALLOWED_GROUPS', '1,2,3').split(',')
|
|
|
|
|
2016-09-16 23:58:26 +02:00
|
|
|
|
|
|
|
@app.route("/")
|
|
|
|
def hello():
|
2016-09-17 13:38:40 +02:00
|
|
|
url = BASE_URL
|
2016-09-17 00:12:32 +02:00
|
|
|
if url is None:
|
|
|
|
return ""
|
2016-09-17 00:23:31 +02:00
|
|
|
|
2016-09-17 12:54:44 +02:00
|
|
|
year = request.args.get('year', '')
|
|
|
|
group = request.args.get('group', '')
|
|
|
|
|
2016-09-19 00:37:39 +02:00
|
|
|
year = validate(year, ALLOWED_YEARS, YEAR)
|
|
|
|
group = validate(group, ALLOWED_GROUPS, GROUP)
|
2016-09-17 12:54:44 +02:00
|
|
|
|
|
|
|
url += "&promo={year}&groupe={group}".format(year=year, group=group)
|
2016-09-17 00:12:32 +02:00
|
|
|
cal_str = urllib.request.urlopen(url).read()
|
2016-09-16 23:58:26 +02:00
|
|
|
|
|
|
|
cal = Component.from_ical(cal_str)
|
|
|
|
other = Calendar()
|
|
|
|
|
|
|
|
# Copy all properties of calendar
|
|
|
|
for k, v in cal.items():
|
|
|
|
other.add(k, v)
|
|
|
|
|
2016-09-19 00:38:04 +02:00
|
|
|
# Copy VTIMEZONE components
|
|
|
|
for ev in cal.walk('VTIMEZONE'):
|
|
|
|
other.add_component(ev)
|
2016-09-16 23:58:26 +02:00
|
|
|
|
|
|
|
# Filter and copy VEVENTs
|
|
|
|
for ev in cal.walk('VEVENT'):
|
2016-09-17 12:22:15 +02:00
|
|
|
if should_add(ev):
|
2016-09-16 23:58:26 +02:00
|
|
|
other.add_component(ev)
|
|
|
|
|
|
|
|
return other.to_ical().replace(b'\r\n', b'\n').strip()
|
|
|
|
|
2016-09-17 12:22:15 +02:00
|
|
|
|
|
|
|
def should_add(event):
|
2016-09-17 13:27:46 +02:00
|
|
|
"""
|
|
|
|
Determines whether an event should be added to the returned calendar or not.
|
|
|
|
|
|
|
|
:param event: The event to determine if should be added or not.
|
|
|
|
:type event: Component
|
|
|
|
:return: True if the event should be added, False otherwise.
|
|
|
|
:rtype: bool
|
|
|
|
"""
|
2016-09-17 12:22:15 +02:00
|
|
|
course_code = event['SUMMARY'].split('-')[1].split('/')[0]
|
|
|
|
course_type = event['SUMMARY'].split('/')[1].split('_')[1]
|
|
|
|
|
2016-09-17 13:27:46 +02:00
|
|
|
# Get user specified excluded courses/types if exist
|
|
|
|
excluded_courses = request.args.get('excluded_courses', '')
|
|
|
|
excluded_types = request.args.get('excluded_types', '')
|
|
|
|
|
|
|
|
if excluded_courses == '':
|
|
|
|
excluded_courses = EXCLUDED_COURSES
|
|
|
|
else:
|
|
|
|
excluded_courses = excluded_courses.split(',')
|
|
|
|
|
|
|
|
if excluded_types == '':
|
|
|
|
excluded_types = EXCLUDED_TYPES
|
|
|
|
else:
|
|
|
|
excluded_types = excluded_types.split(',')
|
|
|
|
|
|
|
|
# Filter against courses and types
|
2016-09-17 12:22:15 +02:00
|
|
|
return \
|
2016-09-17 13:27:46 +02:00
|
|
|
course_code not in excluded_courses \
|
|
|
|
and course_type not in excluded_types
|
2016-09-17 12:22:15 +02:00
|
|
|
|
2016-09-19 00:37:39 +02:00
|
|
|
|
|
|
|
def validate(item, validation_list, default):
|
|
|
|
"""
|
|
|
|
Validates an item from user input against a list of possible values.
|
|
|
|
|
|
|
|
:param item: The item to validate.
|
|
|
|
:type item: object
|
|
|
|
:param validation_list: The list of possible values.
|
|
|
|
:type item: list(object)
|
|
|
|
:param default: The default value to fallback on if item is not in list.
|
|
|
|
:type default: object
|
|
|
|
:return: The item if it is valid (in the list), or default
|
|
|
|
:rtype: object
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
int(item)
|
|
|
|
if item not in validation_list:
|
|
|
|
raise ValueError(item.__name__ + ' not allowed')
|
|
|
|
except ValueError:
|
|
|
|
return default
|
|
|
|
return item
|
|
|
|
|
2016-09-16 23:58:26 +02:00
|
|
|
if __name__ == "__main__":
|
2016-09-17 13:40:30 +02:00
|
|
|
app.run('0.0.0.0', PORT)
|