import json
from distutils.util import strtobool
from typing import Any
from flask import Blueprint
from flask import current_app as app
from flask import jsonify, redirect, request, session, url_for
import backend.models as md
import backend.schedules as schd
import views.utils as utl
[docs]class ApiEncoder(json.JSONEncoder):
"""
Subclass of json decoder made for the calendar-specific JSON encodings.
"""
[docs] def default(self, obj: Any) -> Any:
if isinstance(obj, set):
return list(obj)
else:
return json.JSONEncoder.default(self, obj)
[docs]class ApiDecoder(json.JSONDecoder):
"""
Subclass of json decoder made for the calendar-specific JSON decodings.
"""
[docs] def decode(self, obj: Any, w: Any = None) -> str:
decoded = json.JSONDecoder().decode(obj)
for key in decoded:
obj = decoded[key]
if isinstance(obj, list) and isinstance(obj[0], str):
decoded[key] = set(obj)
return decoded
api = Blueprint("api", __name__, static_folder="../static")
api.json_decoder = ApiDecoder
api.json_encoder = ApiEncoder
[docs]@api.before_request
def before_api_request():
utl.init_session()
[docs]@api.route("/events", methods=["GET"])
def get_events():
"""
API endpoint to fetch the schedule matching the various arguments.
The request accepts 3 arguments:
- view: if set to True, shows the schedule in ADE-Scheduler's schedule viewer.
By default, view = False the data is returned in JSON format.
- year: defines the academical year. Accepted format is YYYY-YYYY where the second year is the first + 1.
e.g.: 2020-20201
- code: the various code of the courses to be added to the schedule.
e.g.: LELEC2885, LMECA2170, LEPL1104,...
To specify a list of codes, use the following format:
/schedule?code=CODE_1&code=CODE_2&code=CODE_3 and so on.
- filtered events: the IDs of the events you want to filter.
Say the course which code is "CODE" has two TPs with IDs "TP: CODE-Q1A" and "TP: CODE-Q1B"
and you want to filter out the events of "TP: CODE-Q1A", you can specify such a filter by specifying:
/schedule?code=CODE&CODE=TP: CODE-Q1A&...
/!\\ To make sure to avoid any problems, respect the case-sensitiveness of the codes and event IDs.
Generally, those are uppercase. /!\\
Example:
https://ade-scheduler.info.ucl.ac.be/api/events?year=2020-2021&code=LMECA2170&code=LEPL1104&view=true
or, with filtered events:
https://ade-scheduler.info.ucl.ac.be/api/events?year=2020-2021&code=LEPL1104&LEPL1104=TP: LEPL1104_Q2B-APE&view=true
"""
mng = app.config["MANAGER"]
year = request.args.get("year")
codes = request.args.getlist("code")
view = request.args.get("view")
if view is None:
view = False
else:
view = bool(strtobool(request.args.get("view")))
project_id = mng.get_project_ids(year=year)
if year is None or project_id is None:
project_id = mng.get_default_project_id()
schedule = schd.Schedule(project_id=project_id)
schedule.add_course([code.upper() for code in codes])
for code in codes:
schedule.add_filter(code.upper(), request.args.getlist(code))
if view:
session["current_schedule"] = schedule
return redirect(url_for("calendar.index"))
return (jsonify({"events": schedule.get_events(json=True)}), 200)
[docs]@api.route("/shield/user", methods=["GET"])
def user_shield():
"""API route for badges on the GitHub Repository, per shields.io"""
return jsonify(
{
"schemaVersion": 1,
"label": "Users",
"message": f"{md.User.query.count()}",
"color": "blue",
}
)
[docs]@api.route("/shield/schedule", methods=["GET"])
def schedule_shield():
"""API route for badges on the GitHub Repository, per shields.io"""
return jsonify(
{
"schemaVersion": 1,
"label": "Schedules",
"message": f"{md.Schedule.query.count()}",
"color": "blue",
}
)