haldis/app/views/general.py

219 lines
6.1 KiB
Python
Raw Normal View History

2019-09-10 02:50:22 +02:00
"Script to generate the general views of Haldis"
import os
from datetime import datetime, timedelta
2019-12-06 16:12:05 +01:00
import yaml
2020-03-04 21:04:16 +01:00
from typing import Optional
2019-12-06 16:12:05 +01:00
from flask import Flask, render_template, make_response
from flask import request, jsonify
from flask import Blueprint, abort
from flask import current_app as app
from flask import send_from_directory, url_for
from flask_login import login_required
from utils import first
from hlds.definitions import location_definitions
from hlds.models import Location
from models import Order
2020-07-17 11:40:15 +02:00
# import views
from views.order import get_orders
2020-03-04 21:04:16 +01:00
import json
from flask import jsonify
2019-09-05 03:33:29 +02:00
general_bp = Blueprint("general_bp", __name__)
2020-07-17 13:17:53 +02:00
with open(os.path.join(os.path.dirname(__file__), "themes.yml"), "r") as _stream:
_theme_data = yaml.safe_load(_stream)
THEME_OPTIONS = _theme_data["options"]
THEMES = _theme_data["themes"]
2019-09-05 03:33:29 +02:00
@general_bp.route("/")
2019-09-08 01:34:16 +02:00
def home() -> str:
2019-09-10 02:50:22 +02:00
"Generate the home view"
prev_day = datetime.now() - timedelta(days=1)
recently_closed = get_orders(
2019-09-05 03:33:29 +02:00
((Order.stoptime > prev_day) & (Order.stoptime < datetime.now()))
)
return render_template(
"home.html", orders=get_orders(), recently_closed=recently_closed
)
2020-07-17 13:17:53 +02:00
def is_theme_active(theme, now):
theme_type = theme["type"]
2020-07-17 13:17:53 +02:00
if theme_type == "static":
return True
2020-07-17 13:17:53 +02:00
if theme_type == "seasonal":
start_day, start_month = map(int, theme["start"].split("/"))
start_datetime = datetime(year=now.year, day=start_day, month=start_month)
2020-07-17 13:17:53 +02:00
end_day, end_month = map(int, theme["end"].split("/"))
end_year = now.year + (1 if start_month > end_month else 0)
end_datetime = datetime(year=end_year, day=end_day, month=end_month)
2020-07-17 13:17:53 +02:00
return start_datetime <= now <= end_datetime
2020-07-17 13:17:53 +02:00
raise Exception("Unknown theme type {}".format(theme_type))
2020-07-17 13:17:53 +02:00
def get_theme_css(theme, options):
# Build filename
# Each option's chosen value is appended, to get something like mytheme_darkmode_heavy.css
filename = theme["file"]
for option in theme.get("options", []):
theme_name = theme["name"]
assert option in THEME_OPTIONS, f"Theme `{theme_name}` uses undefined option `{option}`"
chosen_value = options[option]
possible_values = list(THEME_OPTIONS[option].keys())
value = chosen_value if chosen_value in possible_values \
else THEME_OPTIONS[option]["_default"]
filename += "_" + value
filename += ".css"
theme_css_dir = "static/css/themes/"
return os.path.join(app.root_path, theme_css_dir, filename)
2019-12-06 16:12:05 +01:00
2020-07-17 13:17:53 +02:00
def get_active_themes():
now = datetime.now()
return [theme for theme in THEMES if is_theme_active(theme, now)]
@general_bp.route("/theme.css")
def theme_css():
"Send appropriate CSS for current theme"
themes = get_active_themes()
theme_name = request.cookies.get("theme", None)
theme = first((t for t in themes if t["file"] == theme_name), default=themes[-1])
options = {
name: request.cookies.get("theme_" + name, None)
for name in ["atmosphere", "performance"]
}
path = get_theme_css(theme, options)
with open(path) as f:
response = make_response(f.read())
2020-07-17 11:40:15 +02:00
response.headers["Content-Type"] = "text/css"
2020-07-17 13:17:53 +02:00
return response
@general_bp.route("/current_theme.js")
def current_theme_js():
themes = get_active_themes()
selected_theme_name = request.cookies.get("theme", None)
matching_theme = first((t for t in themes if t["file"] == selected_theme_name))
cur_theme = matching_theme or themes[-1]
response = make_response(rf'''
var currentTheme = {json.dumps(cur_theme['file'])};
var currentThemeOptions = {json.dumps(cur_theme.get('options', []))};
2020-07-17 13:17:53 +02:00
''')
response.headers["Content-Type"] = "text/javascript"
# Theme name that is not valid at this moment: delete cookie
if matching_theme is None:
response.delete_cookie("theme", path="/")
return response
2019-09-10 02:50:22 +02:00
@general_bp.route("/map")
def map_view() -> str:
"Generate the map view"
return render_template("maps.html", locations=location_definitions)
2019-09-05 03:33:29 +02:00
@general_bp.route("/location")
2019-09-08 01:34:16 +02:00
def locations() -> str:
2019-09-10 02:50:22 +02:00
"Generate the location view"
return render_template("locations.html", locations=location_definitions)
@general_bp.route("/location/<location_id>")
2019-09-10 02:50:22 +02:00
def location(location_id) -> str:
"Generate the location view given an id"
loc = first(filter(lambda l: l.id == location_id, location_definitions))
if loc is None:
abort(404)
2019-09-05 03:33:29 +02:00
return render_template("location.html", location=loc, title=loc.name)
2020-03-04 21:04:16 +01:00
@general_bp.route("/location/<location_id>/<dish_id>")
def location_dish(location_id, dish_id) -> str:
2020-07-17 11:40:15 +02:00
loc: Optional[Location] = first(
filter(lambda l: l.id == location_id, location_definitions)
)
2020-03-04 21:04:16 +01:00
if loc is None:
abort(404)
dish = loc.dish_by_id(dish_id)
if dish is None:
abort(404)
return jsonify([
{
"type": c[0],
"id": c[1].id,
"name": c[1].name,
"description": c[1].description,
"options": [
{
"id": o.id,
"name": o.name,
"description": o.description,
"price": o.price,
2020-07-17 11:40:15 +02:00
"tags": o.tags,
2020-03-04 21:04:16 +01:00
}
for o in c[1].options
2020-07-17 11:40:15 +02:00
],
2020-03-04 21:04:16 +01:00
}
for c in dish.choices
])
2019-09-05 03:33:29 +02:00
@general_bp.route("/about/")
2019-09-08 01:34:16 +02:00
def about() -> str:
2019-09-10 02:50:22 +02:00
"Generate the about view"
2019-09-05 03:33:29 +02:00
return render_template("about.html")
2019-09-05 03:33:29 +02:00
@general_bp.route("/profile/")
@login_required
2019-09-08 01:34:16 +02:00
def profile() -> str:
2019-09-10 02:50:22 +02:00
"Generate the profile view"
2020-07-17 13:17:53 +02:00
return render_template("profile.html", themes_list=get_active_themes())
2019-09-05 03:33:29 +02:00
@general_bp.route("/favicon.ico")
2019-09-08 01:34:16 +02:00
def favicon() -> str:
2019-09-10 02:50:22 +02:00
"Generate the favicon"
# pylint: disable=R1705
if not get_orders((Order.stoptime > datetime.now())):
2019-09-05 03:33:29 +02:00
return send_from_directory(
2019-12-06 15:34:39 +01:00
os.path.join(app.root_path, "static"),
2019-09-05 03:33:29 +02:00
"favicon.ico",
mimetype="image/x-icon",
)
else:
2019-09-05 03:33:29 +02:00
return send_from_directory(
2019-12-06 15:34:39 +01:00
os.path.join(app.root_path, "static"),
2019-09-05 03:33:29 +02:00
"favicon_orange.ico",
mimetype="image/x-icon",
)