cal-proxy/app.py

110 lines
3.1 KiB
Python

from flask import Flask, request
import os
import urllib.request
from icalendar.cal import Calendar, Component
app = Flask(__name__)
PORT = int(os.environ.get('PORT', 5000))
BASE_URL = os.environ.get('BASE_URL', None)
EXCLUDED_COURSES = os.environ.get('COURSES', '').split(',')
EXCLUDED_TYPES = os.environ.get('TYPES', '').split(',')
YEAR = os.environ.get('YEAR', '4')
GROUP = os.environ.get('GROUP', '1')
ALLOWED_YEARS = os.environ.get('ALLOWED_YEARS', '3,4,5').split(',')
ALLOWED_GROUPS = os.environ.get('ALLOWED_GROUPS', '1,2,3').split(',')
@app.route("/")
def hello():
url = BASE_URL
if url is None:
return ""
year = request.args.get('year', '')
group = request.args.get('group', '')
year = validate(year, ALLOWED_YEARS, YEAR)
group = validate(group, ALLOWED_GROUPS, GROUP)
url += "&promo={year}&groupe={group}".format(year=year, group=group)
cal_str = urllib.request.urlopen(url).read()
cal = Component.from_ical(cal_str)
other = Calendar()
# Copy all properties of calendar
for k, v in cal.items():
other.add(k, v)
# Copy VTIMEZONE components
for ev in cal.walk('VTIMEZONE'):
other.add_component(ev)
# Filter and copy VEVENTs
for ev in cal.walk('VEVENT'):
if should_add(ev):
other.add_component(ev)
return other.to_ical().replace(b'\r\n', b'\n').strip()
def should_add(event):
"""
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
"""
course_code = event['SUMMARY'].split('-')[1].split('/')[0]
course_type = event['SUMMARY'].split('/')[1].split('_')[1]
# 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
return \
course_code not in excluded_courses \
and course_type not in excluded_types
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
if __name__ == "__main__":
app.run('0.0.0.0', PORT)