Reformat with black

This commit is contained in:
Midgard 2020-07-17 11:40:15 +02:00
parent 588ffdadfb
commit 4f7ffc0e3d
Signed by: midgard
GPG key ID: 511C112F1331BBB4
18 changed files with 204 additions and 131 deletions

View file

@ -92,8 +92,7 @@ def register_plugins(app: Flask) -> Manager:
# Make cookies more secure # Make cookies more secure
app.config.update( app.config.update(
SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SAMESITE="Lax",
SESSION_COOKIE_SAMESITE='Lax',
) )
if not app.debug: if not app.debug:
@ -140,8 +139,9 @@ def add_template_filters(app: Flask) -> None:
"Add functions which can be used in the templates" "Add functions which can be used in the templates"
# pylint: disable=W0612 # pylint: disable=W0612
@app.template_filter("countdown") @app.template_filter("countdown")
def countdown(value, only_positive: bool = True, def countdown(
show_text: bool = True, reload: bool = True) -> str: value, only_positive: bool = True, show_text: bool = True, reload: bool = True
) -> str:
delta = int(value.timestamp() - datetime.now().timestamp()) delta = int(value.timestamp() - datetime.now().timestamp())
if delta < 0 and only_positive: if delta < 0 and only_positive:
text = "closed" text = "closed"
@ -157,8 +157,11 @@ def add_template_filters(app: Flask) -> None:
reload_str = "yes" if reload else "no" reload_str = "yes" if reload else "no"
return Markup(f"<span class='time' data-seconds='{delta}' data-reload='{reload_str}'>" + return Markup(
text + "</span>") f"<span class='time' data-seconds='{delta}' data-reload='{reload_str}'>"
+ text
+ "</span>"
)
@app.template_filter("year") @app.template_filter("year")
def current_year(_value: typing.Any) -> str: def current_year(_value: typing.Any) -> str:

View file

@ -71,7 +71,7 @@ def add_to_current() -> None:
@app_manager.command @app_manager.command
def setup_database(): #type: None def setup_database(): # type: None
"Start the database interaction script" "Start the database interaction script"
print("Database modification script!") print("Database modification script!")
print("=============================\n\n") print("=============================\n\n")

View file

@ -36,9 +36,9 @@ class FatOrder(Order, FatModel):
@classmethod @classmethod
def items_per_order(cls): def items_per_order(cls):
return ( return (
Order.query.join(OrderItem).group_by(Order.id) Order.query.join(OrderItem)
.with_entities(Order.id, .group_by(Order.id)
func.count(OrderItem.user_id).label("total")) .with_entities(Order.id, func.count(OrderItem.user_id).label("total"))
) )

View file

@ -6,8 +6,15 @@ from typing import Optional
from flask import session, request from flask import session, request
from flask_login import current_user from flask_login import current_user
from flask_wtf import FlaskForm as Form from flask_wtf import FlaskForm as Form
from wtforms import (DateTimeField, SelectField, SelectMultipleField, StringField, SubmitField, from wtforms import (
FieldList, validators) DateTimeField,
SelectField,
SelectMultipleField,
StringField,
SubmitField,
FieldList,
validators,
)
from utils import euro_string, price_range_string from utils import euro_string, price_range_string
from hlds.definitions import location_definitions from hlds.definitions import location_definitions
@ -39,9 +46,7 @@ class OrderForm(Form):
(0, None), (0, None),
(current_user.id, current_user.username), (current_user.id, current_user.username),
] ]
self.location_id.choices = [ self.location_id.choices = [(l.id, l.name) for l in location_definitions]
(l.id, l.name) for l in location_definitions
]
if self.stoptime.data is None: if self.stoptime.data is None:
self.stoptime.data = datetime.now() + timedelta(hours=1) self.stoptime.data = datetime.now() + timedelta(hours=1)
@ -67,6 +72,7 @@ class AnonOrderItemForm(OrderItemForm):
Class which defines the form for a new Item in an Order Class which defines the form for a new Item in an Order
For Users who aren't logged in For Users who aren't logged in
""" """
user_name = StringField("Name", validators=[validators.required()]) user_name = StringField("Name", validators=[validators.required()])
def populate(self, location: Location) -> None: def populate(self, location: Location) -> None:

View file

@ -6,11 +6,9 @@ from utils import euro_string, first
def _format_tags(tags: Iterable[str]) -> str: def _format_tags(tags: Iterable[str]) -> str:
return ( return " :: {}".format(" ".join(["{" + tag + "}" for tag in tags])) \
" :: {}".format(" ".join(["{" + tag + "}" for tag in tags])) if tags \
if tags else else ""
""
)
def _format_price(price: int) -> str: def _format_price(price: int) -> str:
@ -35,7 +33,7 @@ class Option:
self, self,
" -- {}".format(self.description) if self.description else "", " -- {}".format(self.description) if self.description else "",
_format_tags(self.tags), _format_tags(self.tags),
_format_price(self.price) _format_price(self.price),
) )
@ -51,7 +49,7 @@ class Choice:
return "{0.id}: {0.name}{1}\n\t\t{2}".format( return "{0.id}: {0.name}{1}\n\t\t{2}".format(
self, self,
" -- {}".format(self.description) if self.description else "", " -- {}".format(self.description) if self.description else "",
"\n\t\t".join(map(str, self.options)) "\n\t\t".join(map(str, self.options)),
) )
def option_by_id(self, option_id: str) -> Optional[Option]: def option_by_id(self, option_id: str) -> Optional[Option]:
@ -75,12 +73,14 @@ class Dish:
" -- {}".format(self.description) if self.description else "", " -- {}".format(self.description) if self.description else "",
_format_tags(self.tags), _format_tags(self.tags),
_format_price(self.price), _format_price(self.price),
"\n\t".join(map(_format_type_and_choice, self.choices)) "\n\t".join(map(_format_type_and_choice, self.choices)),
) )
def price_range(self) -> Tuple[int, int]: def price_range(self) -> Tuple[int, int]:
return (self.price + self._sum_f_option_prices(min), return (
self.price + self._sum_f_option_prices(max)) self.price + self._sum_f_option_prices(min),
self.price + self._sum_f_option_prices(max),
)
def _sum_f_option_prices(self, f): def _sum_f_option_prices(self, f):
return sum( return sum(
@ -91,7 +91,9 @@ class Dish:
class Location: class Location:
def __init__(self, id_, *, name, dishes, osm=None, address=None, telephone=None, website=None): def __init__(
self, id_, *, name, dishes, osm=None, address=None, telephone=None, website=None
):
self.id: str = id_ self.id: str = id_
self.name: str = name self.name: str = name
self.osm: Optional[str] = osm self.osm: Optional[str] = osm
@ -114,11 +116,15 @@ class Location:
"{2}" "{2}"
).format( ).format(
self, self,
"".join("\n\t{} {}".format(k, v) for k, v in ( "".join(
"\n\t{} {}".format(k, v)
for k, v in (
("osm", self.osm), ("osm", self.osm),
("address", self.address), ("address", self.address),
("telephone", self.telephone), ("telephone", self.telephone),
("website", self.website), ("website", self.website),
) if v is not None), )
"\n".join(map(str, self.dishes)) if v is not None
),
"\n".join(map(str, self.dishes)),
) )

View file

@ -24,7 +24,9 @@ def filter_instance(cls, iterable):
# pylint: disable=no-self-use # pylint: disable=no-self-use
class HldsSemanticActions: class HldsSemanticActions:
def location(self, ast) -> Location: def location(self, ast) -> Location:
choices = {choice.id: choice for choice in filter_instance(Choice, ast["items_"])} choices = {
choice.id: choice for choice in filter_instance(Choice, ast["items_"])
}
dishes: Iterable[Dish] = filter_instance(Dish, ast["items_"]) dishes: Iterable[Dish] = filter_instance(Dish, ast["items_"])
for dish in dishes: for dish in dishes:
for i, choice in enumerate(dish.choices): for i, choice in enumerate(dish.choices):
@ -32,7 +34,9 @@ class HldsSemanticActions:
dish.choices[i] = (dish.choices[i][0], deepcopy(choices[choice[1]])) dish.choices[i] = (dish.choices[i][0], deepcopy(choices[choice[1]]))
# Move the base price to the first single_choice if the dish has a fixed price # Move the base price to the first single_choice if the dish has a fixed price
first_single_choice = first(c[1] for c in dish.choices if c[0] == "single_choice") first_single_choice = first(
c[1] for c in dish.choices if c[0] == "single_choice"
)
price_range = dish.price_range() price_range = dish.price_range()
if dish.price and price_range[0] != price_range[1] and first_single_choice: if dish.price and price_range[0] != price_range[1] and first_single_choice:
for option in first_single_choice.options: for option in first_single_choice.options:
@ -41,7 +45,6 @@ class HldsSemanticActions:
attributes = {att["key"]: att["value"] for att in ast["attributes"]} attributes = {att["key"]: att["value"] for att in ast["attributes"]}
return Location( return Location(
ast["id"], ast["id"],
name=ast["name"], name=ast["name"],
@ -64,7 +67,9 @@ class HldsSemanticActions:
def choice_block(self, ast) -> Choice: def choice_block(self, ast) -> Choice:
if ast["price"] or ast["tags"]: if ast["price"] or ast["tags"]:
raise SemanticError("Choice blocks cannot have price or tags, put them on each of its options instead") raise SemanticError(
"Choice blocks cannot have price or tags, put them on each of its options instead"
)
return Choice( return Choice(
ast["id"], ast["id"],
@ -76,8 +81,8 @@ class HldsSemanticActions:
def indent_choice_block(self, ast) -> Tuple[str, Union[Choice, AST]]: def indent_choice_block(self, ast) -> Tuple[str, Union[Choice, AST]]:
return ( return (
(ast["type"], self.choice_block(ast)) (ast["type"], self.choice_block(ast))
if ast["kind"] == "declaration" else if ast["kind"] == "declaration"
(ast["type"], ast["id"]) else (ast["type"], ast["id"])
) )
def indent_choice_entry(self, ast) -> Option: def indent_choice_entry(self, ast) -> Option:
@ -92,18 +97,18 @@ class HldsSemanticActions:
noindent_choice_entry = indent_choice_entry noindent_choice_entry = indent_choice_entry
def price(self, ast) -> int: def price(self, ast) -> int:
return ( return 100 * int(ast["value_unit"]) + (
100 * int(ast["value_unit"]) + 0
( if not ast["value_cents"]
0 if not ast["value_cents"] else else 10 * int(ast["value_cents"])
10 * int(ast["value_cents"]) if len(ast["value_cents"]) == 1 else if len(ast["value_cents"]) == 1
int(ast["value_cents"]) else int(ast["value_cents"])
)
) )
def _default(self, ast): def _default(self, ast):
return ast return ast
SEMANTICS = HldsSemanticActions() SEMANTICS = HldsSemanticActions()

View file

@ -4,6 +4,7 @@ from __future__ import with_statement
from logging.config import fileConfig from logging.config import fileConfig
from alembic import context from alembic import context
# add your model's MetaData object here # add your model's MetaData object here
# for 'autogenerate' support # for 'autogenerate' support
# from myapp import mymodel # from myapp import mymodel

View file

@ -22,7 +22,9 @@ class Order(db.Model):
def __getattr__(self, name): def __getattr__(self, name):
if name == "location": if name == "location":
return first(filter(lambda l: l.id == self.location_id, location_definitions)) return first(
filter(lambda l: l.id == self.location_id, location_definitions)
)
raise AttributeError() raise AttributeError()
def __repr__(self) -> str: def __repr__(self) -> str:
@ -37,7 +39,9 @@ class Order(db.Model):
Update the location name from the HLDS definition. Update the location name from the HLDS definition.
User should commit after running this to make the change persistent. User should commit after running this to make the change persistent.
""" """
assert self.location_id, "location_id must be configured before updating from HLDS" assert (
self.location_id
), "location_id must be configured before updating from HLDS"
self.location_name = self.location.name self.location_name = self.location.name
def group_by_user(self) -> typing.Dict[str, typing.Any]: def group_by_user(self) -> typing.Dict[str, typing.Any]:
@ -46,17 +50,16 @@ class Order(db.Model):
for item in self.items: for item in self.items:
user = group.get(item.get_name(), dict()) user = group.get(item.get_name(), dict())
user["total"] = user.get("total", 0) + item.price user["total"] = user.get("total", 0) + item.price
user["to_pay"] = ( user["to_pay"] = user.get("to_pay", 0) + item.price if not item.paid else 0
user.get("to_pay", 0) +
item.price if not item.paid else 0
)
user["paid"] = user.get("paid", True) and item.paid user["paid"] = user.get("paid", True) and item.paid
user["dishes"] = user.get("dishes", []) + [item.dish_name] user["dishes"] = user.get("dishes", []) + [item.dish_name]
group[str(item.get_name())] = user group[str(item.get_name())] = user
return group return group
def group_by_dish(self, sort_comments=False) -> typing.Dict[str, typing.Dict[str, typing.Any]]: def group_by_dish(
self, sort_comments=False
) -> typing.Dict[str, typing.Dict[str, typing.Any]]:
"Group items of an Order by dish" "Group items of an Order by dish"
group: typing.Dict[str, typing.Dict[str, typing.Any]] = dict() group: typing.Dict[str, typing.Dict[str, typing.Any]] = dict()
for item in self.items: for item in self.items:

View file

@ -17,9 +17,7 @@ class OrderItem(db.Model):
dish_id = db.Column(db.String(64), nullable=True) dish_id = db.Column(db.String(64), nullable=True)
dish_name = db.Column(db.String(120), nullable=True) dish_name = db.Column(db.String(120), nullable=True)
price = db.Column(db.Integer, nullable=True) price = db.Column(db.Integer, nullable=True)
paid = db.Column( paid = db.Column(db.Boolean, default=False, nullable=True)
db.Boolean, default=False, nullable=True
)
comment = db.Column(db.Text(), nullable=True) comment = db.Column(db.Text(), nullable=True)
hlds_data_version = db.Column(db.String(40), nullable=True) hlds_data_version = db.Column(db.String(40), nullable=True)
@ -27,8 +25,12 @@ class OrderItem(db.Model):
def __getattr__(self, name): def __getattr__(self, name):
if name == "dish": if name == "dish":
location_id = Order.query.filter(Order.id == self.order_id).first().location_id location_id = (
location = first(filter(lambda l: l.id == location_id, location_definitions)) Order.query.filter(Order.id == self.order_id).first().location_id
)
location = first(
filter(lambda l: l.id == location_id, location_definitions)
)
if location: if location:
return first(filter(lambda d: d.id == self.dish_id, location.dishes)) return first(filter(lambda d: d.id == self.dish_id, location.dishes))
else: else:

View file

@ -7,7 +7,9 @@ from .orderitem import OrderItem
class OrderItemChoice(db.Model): class OrderItemChoice(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
choice_id = db.Column(db.String(64), nullable=True) choice_id = db.Column(db.String(64), nullable=True)
order_item_id = db.Column(db.Integer, db.ForeignKey("order_item.id"), nullable=False) order_item_id = db.Column(
db.Integer, db.ForeignKey("order_item.id"), nullable=False
)
kind = db.Column(db.String(1), nullable=False) kind = db.Column(db.String(1), nullable=False)
name = db.Column(db.String(120), nullable=True) name = db.Column(db.String(120), nullable=True)
value = db.Column(db.String(120), nullable=True) value = db.Column(db.String(120), nullable=True)

View file

@ -35,8 +35,7 @@ def post_order_to_webhook(order: Order) -> None:
"Function that sends the notification for the order" "Function that sends the notification for the order"
message = webhook_text(order) message = webhook_text(order)
if message: if message:
webhookthread = WebhookSenderThread( webhookthread = WebhookSenderThread(message, app.config["SLACK_WEBHOOK"])
message, app.config["SLACK_WEBHOOK"])
webhookthread.start() webhookthread.start()

View file

@ -24,6 +24,7 @@ def main(filenames):
if __name__ == "__main__": if __name__ == "__main__":
import sys import sys
args = sys.argv[1:] args = sys.argv[1:]
if "-h" in args or "--help" in args: if "-h" in args or "--help" in args:
print(USAGE.format(sys.argv[0]), file=sys.stderr) print(USAGE.format(sys.argv[0]), file=sys.stderr)

View file

@ -10,6 +10,7 @@ if sys.executable != INTERP:
sys.path.append(os.getcwd()) sys.path.append(os.getcwd())
from app import create_app from app import create_app
application = create_app().app application = create_app().app
# For running on the server with passenger etc # For running on the server with passenger etc

View file

@ -9,10 +9,13 @@ def euro_string(value: int) -> str:
""" """
return "{}.{:02}".format(*divmod(value, 100)) return "{}.{:02}".format(*divmod(value, 100))
def price_range_string(price_range, include_upper=False): def price_range_string(price_range, include_upper=False):
if price_range[0] == price_range[1]: if price_range[0] == price_range[1]:
return euro_string(price_range[0]) return euro_string(price_range[0])
return ("{}{}" if include_upper else "from {}").format(*map(euro_string, price_range)) return ("{}{}" if include_upper else "from {}").format(
*map(euro_string, price_range)
)
def first(iterable: Iterable, default=None): def first(iterable: Iterable, default=None):

View file

@ -16,6 +16,7 @@ from utils import first
from hlds.definitions import location_definitions from hlds.definitions import location_definitions
from hlds.models import Location from hlds.models import Location
from models import Order from models import Order
# import views # import views
from views.order import get_orders from views.order import get_orders
@ -43,7 +44,7 @@ def get_css_dict(css_path):
# Open the YAML file with all the themes. # Open the YAML file with all the themes.
path = os.path.join(app.root_path, "views/themes.yml") path = os.path.join(app.root_path, "views/themes.yml")
with open(path, 'r') as stream: with open(path, "r") as stream:
data = yaml.safe_load(stream) data = yaml.safe_load(stream)
# Build a dictionary from the YAML file with all the themes and their attributes. # Build a dictionary from the YAML file with all the themes and their attributes.
themes = {} themes = {}
@ -57,46 +58,46 @@ def get_css_dict(css_path):
# Check each theme in the dictionary and return the first one that is "correct" # Check each theme in the dictionary and return the first one that is "correct"
for key, theme in themes.items(): for key, theme in themes.items():
if theme['type'] == 'static-date': if theme["type"] == "static-date":
start_day, start_month = theme['start'].split('/') start_day, start_month = theme["start"].split("/")
start_date = datetime(year=current_year, day=int( start_date = datetime(year=current_year, day=int(start_day), month=int(start_month))
start_day), month=int(start_month))
end_day, end_month = theme['end'].split('/') end_day, end_month = theme["end"].split("/")
if int(start_month) > int(end_month): if int(start_month) > int(end_month):
current_year += 1 current_year += 1
end_date = datetime( end_date = datetime(year=current_year, day=int(end_day), month=int(end_month))
year=current_year, day=int(end_day), month=int(end_month))
if start_date <= current_date <= end_date: if start_date <= current_date <= end_date:
path = os.path.join(app.root_path, css_path, theme['file']) path = os.path.join(app.root_path, css_path, theme["file"])
themes_dict[key] = path themes_dict[key] = path
themes_dict['darkmode'] = os.path.join( themes_dict["darkmode"] = os.path.join(
app.root_path, "static/css/themes/lowPerformance/darkmode.css") app.root_path, "static/css/themes/lowPerformance/darkmode.css"
themes_dict['lightmode'] = os.path.join( )
app.root_path, "static/css/themes/lowPerformance/lightmode.css") themes_dict["lightmode"] = os.path.join(
app.root_path, "static/css/themes/lowPerformance/lightmode.css"
)
return themes_dict return themes_dict
def css_list(): def css_list():
"Generate the list of names of all the currently available themes" "Generate the list of names of all the currently available themes"
if request.cookies.get('performance', '') == 'highPerformance': if request.cookies.get("performance", "") == "highPerformance":
css_path = 'static/css/themes/highPerformance/' css_path = "static/css/themes/highPerformance/"
else: else:
css_path = 'static/css/themes/lowPerformance/' css_path = "static/css/themes/lowPerformance/"
return list(get_css_dict(css_path).keys()) return list(get_css_dict(css_path).keys())
@general_bp.route("/css") @general_bp.route("/css")
def css(): def css():
"Generate the css" "Generate the css"
if request.cookies.get('performance', '') == 'highPerformance': if request.cookies.get("performance", "") == "highPerformance":
css_path = 'static/css/themes/highPerformance/' css_path = "static/css/themes/highPerformance/"
else: else:
css_path = 'static/css/themes/lowPerformance/' css_path = "static/css/themes/lowPerformance/"
cookie_theme = request.cookies.get('theme', '') cookie_theme = request.cookies.get("theme", "")
themes_dict = get_css_dict(css_path) themes_dict = get_css_dict(css_path)
@ -108,7 +109,7 @@ def css():
f = open(path) f = open(path)
response = make_response(f.read()) response = make_response(f.read())
response.headers['Content-Type'] = 'text/css' response.headers["Content-Type"] = "text/css"
f.close() f.close()
return response return response
@ -136,7 +137,9 @@ def location(location_id) -> str:
@general_bp.route("/location/<location_id>/<dish_id>") @general_bp.route("/location/<location_id>/<dish_id>")
def location_dish(location_id, dish_id) -> str: def location_dish(location_id, dish_id) -> str:
loc: Optional[Location] = first(filter(lambda l: l.id == location_id, location_definitions)) loc: Optional[Location] = first(
filter(lambda l: l.id == location_id, location_definitions)
)
if loc is None: if loc is None:
abort(404) abort(404)
dish = loc.dish_by_id(dish_id) dish = loc.dish_by_id(dish_id)
@ -154,10 +157,10 @@ def location_dish(location_id, dish_id) -> str:
"name": o.name, "name": o.name,
"description": o.description, "description": o.description,
"price": o.price, "price": o.price,
"tags": o.tags "tags": o.tags,
} }
for o in c[1].options for o in c[1].options
] ],
} }
for c in dish.choices for c in dish.choices
]) ])

View file

@ -4,9 +4,19 @@ import typing
from datetime import datetime from datetime import datetime
from werkzeug.wrappers import Response from werkzeug.wrappers import Response
# from flask import current_app as app # from flask import current_app as app
from flask import (Blueprint, abort, flash, redirect, render_template, request, from flask import (
session, url_for, wrappers) Blueprint,
abort,
flash,
redirect,
render_template,
request,
session,
url_for,
wrappers,
)
from flask_login import current_user, login_required from flask_login import current_user, login_required
from forms import AnonOrderItemForm, OrderForm, OrderItemForm from forms import AnonOrderItemForm, OrderForm, OrderItemForm
@ -57,8 +67,7 @@ def order_from_id(order_id: int, form: OrderForm = None, dish_id=None) -> str:
flash("Please login to see this order.", "info") flash("Please login to see this order.", "info")
abort(401) abort(401)
if form is None: if form is None:
form = AnonOrderItemForm() if current_user.is_anonymous() \ form = AnonOrderItemForm() if current_user.is_anonymous() else OrderItemForm()
else OrderItemForm()
if order.location: if order.location:
form.populate(order.location) form.populate(order.location)
if order.is_closed(): if order.is_closed():
@ -68,8 +77,14 @@ def order_from_id(order_id: int, form: OrderForm = None, dish_id=None) -> str:
dish = order.location.dish_by_id(dish_id) if order.location else None dish = order.location.dish_by_id(dish_id) if order.location else None
return render_template("order.html", order=order, form=form, return render_template(
total_price=total_price, debts=debts, dish=dish) "order.html",
order=order,
form=form,
total_price=total_price,
debts=debts,
dish=dish,
)
@order_bp.route("/<order_id>/items") @order_bp.route("/<order_id>/items")
@ -90,8 +105,7 @@ def items_showcase(order_id: int) -> str:
def order_edit(order_id: int) -> typing.Union[str, Response]: def order_edit(order_id: int) -> typing.Union[str, Response]:
"Generate order edit view from id" "Generate order edit view from id"
order = Order.query.filter(Order.id == order_id).first() order = Order.query.filter(Order.id == order_id).first()
if current_user.id is not order.courier_id and \ if current_user.id is not order.courier_id and not current_user.is_admin():
not current_user.is_admin():
abort(401) abort(401)
if order is None: if order is None:
abort(404) abort(404)
@ -102,8 +116,7 @@ def order_edit(order_id: int) -> typing.Union[str, Response]:
order.update_from_hlds() order.update_from_hlds()
db.session.commit() db.session.commit()
return redirect(url_for("order_bp.order_from_id", order_id=order.id)) return redirect(url_for("order_bp.order_from_id", order_id=order.id))
return render_template("order_edit.html", form=orderForm, return render_template("order_edit.html", form=orderForm, order_id=order_id)
order_id=order_id)
@order_bp.route("/<order_id>/create", methods=["GET", "POST"]) @order_bp.route("/<order_id>/create", methods=["GET", "POST"])
@ -123,8 +136,7 @@ def order_item_create(order_id: int) -> typing.Any:
# If location doesn't exist any more, adding items is nonsensical # If location doesn't exist any more, adding items is nonsensical
if not location: if not location:
abort(404) abort(404)
form = AnonOrderItemForm() if current_user.is_anonymous() \ form = AnonOrderItemForm() if current_user.is_anonymous() else OrderItemForm()
else OrderItemForm()
dish_id = form.dish_id.data if form.is_submitted() else request.args.get("dish") dish_id = form.dish_id.data if form.is_submitted() else request.args.get("dish")
if dish_id and not location.dish_by_id(dish_id): if dish_id and not location.dish_by_id(dish_id):
@ -142,8 +154,14 @@ def order_item_create(order_id: int) -> typing.Any:
chosen = [ chosen = [
( (
choice.option_by_id(request.form.get("choice_" + choice.id)) choice.option_by_id(request.form.get("choice_" + choice.id))
if choice_type == "single_choice" else if choice_type == "single_choice"
list(ignore_none(request.form.getlist("choice_" + choice.id, type=choice.option_by_id))) else list(
ignore_none(
request.form.getlist(
"choice_" + choice.id, type=choice.option_by_id
)
)
)
) )
for (choice_type, choice) in choices for (choice_type, choice) in choices
] ]
@ -151,14 +169,22 @@ def order_item_create(order_id: int) -> typing.Any:
if dish_was_changed or not all_choices_present: if dish_was_changed or not all_choices_present:
try: try:
user_name = form.user_name.data if form.user_name.validate(form) else None user_name = (
form.user_name.data if form.user_name.validate(form) else None
)
except AttributeError: except AttributeError:
user_name = None user_name = None
comment = form.comment.data if form.comment.validate(form) else None comment = form.comment.data if form.comment.validate(form) else None
return redirect(url_for("order_bp.order_item_create", return redirect(
order_id=order_id, dish=form.dish_id.data, url_for(
user_name=user_name, comment=comment)) "order_bp.order_item_create",
order_id=order_id,
dish=form.dish_id.data,
user_name=user_name,
comment=comment,
)
)
# If the form was not submitted (GET request) or the form had errors: show form again # If the form was not submitted (GET request) or the form had errors: show form again
if not form.validate_on_submit(): if not form.validate_on_submit():
@ -184,6 +210,7 @@ def order_item_create(order_id: int) -> typing.Any:
return option.name return option.name
except AttributeError: except AttributeError:
return ", ".join(o.name for o in option if no_text_tag not in o.tags) return ", ".join(o.name for o in option if no_text_tag not in o.tags)
comments = list(ignore_none(_name(option) for option in chosen)) comments = list(ignore_none(_name(option) for option in chosen))
if item.comment: if item.comment:
comments.append("Comment: " + item.comment) comments.append("Comment: " + item.comment)
@ -198,6 +225,7 @@ def order_item_create(order_id: int) -> typing.Any:
return option.price or 0 return option.price or 0
except AttributeError: except AttributeError:
return sum(o.price or 0 for o in option) return sum(o.price or 0 for o in option)
item.price += sum(_price(option) for option in chosen) item.price += sum(_price(option) for option in chosen)
db.session.add(item) db.session.add(item)
@ -216,8 +244,7 @@ def item_paid(order_id: int, item_id: int) -> typing.Optional[Response]:
if item.order.courier_id == user_id or current_user.admin: if item.order.courier_id == user_id or current_user.admin:
item.paid = True item.paid = True
db.session.commit() db.session.commit()
flash("Paid %s by %s" % (item.dish_name, item.get_name()), flash("Paid %s by %s" % (item.dish_name, item.get_name()), "success")
"success")
return redirect(url_for("order_bp.order_from_id", order_id=order_id)) return redirect(url_for("order_bp.order_from_id", order_id=order_id))
abort(404) abort(404)
@ -244,8 +271,7 @@ def items_user_paid(order_id: int, user_name: str) -> typing.Optional[Response]:
for item in items: for item in items:
item.paid = True item.paid = True
db.session.commit() db.session.commit()
flash("Paid %d items for %s" % flash("Paid %d items for %s" % (len(items), item.get_name()), "success")
(len(items), item.get_name()), "success")
return redirect(url_for("order_bp.order_from_id", order_id=order_id)) return redirect(url_for("order_bp.order_from_id", order_id=order_id))
abort(404) abort(404)
@ -293,7 +319,9 @@ def close_order(order_id: int) -> typing.Optional[Response]:
order = Order.query.filter(Order.id == order_id).first() order = Order.query.filter(Order.id == order_id).first()
if order is None: if order is None:
abort(404) abort(404)
if (current_user.id == order.courier_id or current_user.is_admin()) and not order.is_closed(): if (
current_user.id == order.courier_id or current_user.is_admin()
) and not order.is_closed():
order.stoptime = datetime.now() order.stoptime = datetime.now()
if order.courier_id == 0 or order.courier_id is None: if order.courier_id == 0 or order.courier_id is None:
courier = select_user(order.items) courier = select_user(order.items)
@ -332,7 +360,8 @@ def get_orders(expression=None) -> typing.List[Order]:
order_list: typing.List[OrderForm] = [] order_list: typing.List[OrderForm] = []
if expression is None: if expression is None:
expression = (datetime.now() > Order.starttime) & ( expression = (datetime.now() > Order.starttime) & (
Order.stoptime > datetime.now() Order.stoptime
> datetime.now()
# pylint: disable=C0121 # pylint: disable=C0121
) | (Order.stoptime == None) ) | (Order.stoptime == None)
if not current_user.is_anonymous(): if not current_user.is_anonymous():
@ -340,5 +369,6 @@ def get_orders(expression=None) -> typing.List[Order]:
else: else:
order_list = Order.query.filter( order_list = Order.query.filter(
# pylint: disable=C0121 # pylint: disable=C0121
(expression & (Order.public == True))).all() (expression & (Order.public == True))
).all()
return order_list return order_list

View file

@ -1,8 +1,7 @@
"Script containing everything specific to ZeusWPI" "Script containing everything specific to ZeusWPI"
import typing import typing
from flask import (Blueprint, current_app, flash, redirect, request, session, from flask import Blueprint, current_app, flash, redirect, request, session, url_for
url_for)
from flask_login import login_user from flask_login import login_user
from flask_oauthlib.client import OAuth, OAuthException from flask_oauthlib.client import OAuth, OAuthException
from werkzeug.wrappers import Response from werkzeug.wrappers import Response

View file

@ -1,15 +1,19 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
print("""============================ print(
"""============================
s5: S5 s5: S5
osm https://www.openstreetmap.org/node/3752879366 osm https://www.openstreetmap.org/node/3752879366
address Krijgslaan 281, 9000 Gent address Krijgslaan 281, 9000 Gent
website https://www.ugent.be/student/nl/meer-dan-studeren/resto/restos/restocampussterre.htm website https://www.ugent.be/student/nl/meer-dan-studeren/resto/restos/restocampussterre.htm
============================""") ============================"""
)
# Paste menu from https://www.ugent.be/student/nl/meer-dan-studeren/resto/broodjes/overzicht.htm # Paste menu from https://www.ugent.be/student/nl/meer-dan-studeren/resto/broodjes/overzicht.htm
# here # here
MENU = [l.split("\t") for l in """ MENU = [
l.split("\t")
for l in """
Spring break Erwten-munt spread, komkommer, radijs, sla, croutons, cocktailsaus 1,50 2,40 Spring break Erwten-munt spread, komkommer, radijs, sla, croutons, cocktailsaus 1,50 2,40
Groentespread Weekelijks wisselende groentespread 1,60 2,60 Groentespread Weekelijks wisselende groentespread 1,60 2,60
Brie Brie, honing, pijnboompitten, sla 1,50 2,50 Brie Brie, honing, pijnboompitten, sla 1,50 2,50
@ -30,40 +34,44 @@ Maison Ham, kaas, augurk, ei, sla, tomaat, cocktailsaus en mayonaise € 1,60
Tropical Ham, kaas, ananas, ei, sla, cocktailsaus 1,60 2,40 Tropical Ham, kaas, ananas, ei, sla, cocktailsaus 1,60 2,40
Toscane Mozzarella, prosciutto ham, sla en tomatensalsa 1,60 2,70 Toscane Mozzarella, prosciutto ham, sla en tomatensalsa 1,60 2,70
Argenteuil Ham, asperge, ei, komkommer, sla, tomaat en mayonaise 1,50 2,40 Argenteuil Ham, asperge, ei, komkommer, sla, tomaat en mayonaise 1,50 2,40
""".strip().split("\n")] """.strip().split(
"\n"
)
]
# Sort by price. This fails if price is not always exactly "€ x,xx" but whatever # Sort by price. This fails if price is not always exactly "€ x,xx" but whatever
MENU.sort(key=lambda dish: dish[2] + dish[3]) MENU.sort(key=lambda dish: dish[2] + dish[3])
SANDWICHES = [ SANDWICHES = [
[ # First price [("small_white", "Klein wit "), ("small_brown", "Klein bruin"),], # First price
("small_white", "Klein wit "),
("small_brown", "Klein bruin"),
],
[ # Second price [ # Second price
("large_white", "Groot wit "), ("large_white", "Groot wit "),
("large_brown", "Groot bruin"), ("large_brown", "Groot bruin"),
("quattro", " Quattro "), ("quattro", " Quattro "),
] ],
] ]
def name_to_id(name): def name_to_id(name):
return "".join(filter( return "".join(
lambda c: ord("a") <= ord(c) <= ord("z"), filter(lambda c: ord("a") <= ord(c) <= ord("z"), name.lower().replace("é", "e"))
name.lower().replace("é", "e") )
))
for dish in MENU: for dish in MENU:
print() print()
name, description = dish[0], dish[1] name, description = dish[0], dish[1]
prices = [p.replace(",", ".") for p in dish[2:]] prices = [p.replace(",", ".") for p in dish[2:]]
print("dish sandwich_{}: Broodje {} -- {}".format(name_to_id(name), name, description)) print(
"dish sandwich_{}: Broodje {} -- {}".format(name_to_id(name), name, description)
)
print("\tsingle_choice sandwich: Broodje") print("\tsingle_choice sandwich: Broodje")
for sandwiches, price in zip(SANDWICHES, prices): for sandwiches, price in zip(SANDWICHES, prices):
for sw_id, sw_name in sandwiches: for sw_id, sw_name in sandwiches:
print("\t\t{}: {} {}".format(sw_id, sw_name, price)) print("\t\t{}: {} {}".format(sw_id, sw_name, price))
print(""" print(
"""
dish yoghurt: Natuuryoghurt 0.4 dish yoghurt: Natuuryoghurt 0.4
dish yofu: Plantaardige yofu 1 dish yofu: Plantaardige yofu 1
dish yoghurt_muesli: Yoghurt met muesli 1 dish yoghurt_muesli: Yoghurt met muesli 1
@ -86,4 +94,5 @@ dish bionade: Bionade € 1.5
dish finley: Finley 1 dish finley: Finley 1
dish iced_coffee: IJskoffie 2 dish iced_coffee: IJskoffie 2
dish iced_tea: IJsthee 2 dish iced_tea: IJsthee 2
dish smoothie: Smoothie 2""") dish smoothie: Smoothie 2"""
)