diff --git a/app/notification.py b/app/notification.py index db13610..622f920 100644 --- a/app/notification.py +++ b/app/notification.py @@ -11,7 +11,7 @@ def post_order_to_webhook(order_item) -> None: message = "" if order_item.courrier is not None: message = " {3} is going to {1}, order <{0}|here>! Deadline in {2} minutes!".format( - url_for("order_bp.order", id=order_item.id, _external=True), + url_for("order_bp.order_from_id", order_id=order_item.id, _external=True), order_item.location.name, remaining_minutes(order_item.stoptime), order_item.courrier.username.title(), @@ -20,7 +20,7 @@ def post_order_to_webhook(order_item) -> None: message = " New order for {}. Deadline in {} minutes. <{}|Open here.>".format( order_item.location.name, remaining_minutes(order_item.stoptime), - url_for("order_bp.order", id=order_item.id, _external=True), + url_for("order_bp.order_from_id", order_id=order_item.id, _external=True), ) webhookthread = WebhookSenderThread(message, app.config["SLACK_WEBHOOK"]) webhookthread.start() diff --git a/app/templates/layout.html b/app/templates/layout.html index e2af745..0072652 100644 --- a/app/templates/layout.html +++ b/app/templates/layout.html @@ -5,7 +5,7 @@ ('general_bp.home', 'Home'), ('order_bp.orders', 'Orders'), ('general_bp.locations', 'Locations'), - ('general_bp.map', 'Map'), + ('general_bp.map_view', 'Map'), ('general_bp.about', 'About'), ('stats_blueprint.stats', 'Stats'), ] -%} diff --git a/app/templates/locations.html b/app/templates/locations.html index b174404..c8b3b99 100644 --- a/app/templates/locations.html +++ b/app/templates/locations.html @@ -14,7 +14,7 @@ {% for loc in locations -%} - {{ loc.name }} + {{ loc.name }} {{ loc.address }} diff --git a/app/templates/maps.html b/app/templates/maps.html index 1aced1d..508a2e2 100644 --- a/app/templates/maps.html +++ b/app/templates/maps.html @@ -28,7 +28,7 @@ loc = { "address": "{{loc.address}}", "name": "{{loc.name}}", - "url": "{{ url_for('general_bp.location', id=loc.id) }}" + "url": "{{ url_for('general_bp.location', location_id=loc.id) }}" }; locations.push(loc); diff --git a/app/templates/order.html b/app/templates/order.html index 4096df4..50edf6b 100644 --- a/app/templates/order.html +++ b/app/templates/order.html @@ -11,16 +11,16 @@

Order {{ order.id }}
{% if order.can_close(current_user.id) -%} -
+
{% endif %}{% if courier_or_admin %} - Edit + Edit {%- endif %}

courier: {{ order.courrier.username }} {% if order.courrier == None and not current_user.is_anonymous() %} -
+
{% endif %} @@ -38,7 +38,7 @@ {% if form -%}

Order:

-
+ Choose for me @@ -99,7 +99,7 @@

Ordered products: {{ order.items.count() }}

- + {% for key, value in order.group_by_product().items() -%}
{{ key }}: {{ value["count"] }} diff --git a/app/templates/order_edit.html b/app/templates/order_edit.html index db8c6ac..b70faf9 100644 --- a/app/templates/order_edit.html +++ b/app/templates/order_edit.html @@ -11,7 +11,7 @@

Edit order:

- + {{ form.csrf_token }}
{{ form.courrier_id.label(class='control-label') }}
diff --git a/app/templates/utils.html b/app/templates/utils.html index 6e116ff..4abfa7c 100644 --- a/app/templates/utils.html +++ b/app/templates/utils.html @@ -9,7 +9,7 @@ Orders: {{ order.items.count() }}

{%- endmacro %} diff --git a/app/views/debug.py b/app/views/debug.py index 96177e7..aed320d 100644 --- a/app/views/debug.py +++ b/app/views/debug.py @@ -1,3 +1,4 @@ +"View used for debugging Haldis" from flask import Blueprint from flask import current_app as app from flask import url_for @@ -9,6 +10,7 @@ debug_bp = Blueprint("debug_bp", __name__) @debug_bp.route("/routes") @login_required def list_routes() -> str: + "List all routes of the application" import urllib output = [] diff --git a/app/views/general.py b/app/views/general.py index 9617ec9..d8423b4 100644 --- a/app/views/general.py +++ b/app/views/general.py @@ -1,3 +1,4 @@ +"Script to generate the general views of Haldis" import os from datetime import datetime, timedelta @@ -15,6 +16,7 @@ general_bp = Blueprint("general_bp", __name__) @general_bp.route("/") def home() -> str: + "Generate the home view" prev_day = datetime.now() - timedelta(days=1) recently_closed = get_orders( ((Order.stoptime > prev_day) & (Order.stoptime < datetime.now())) @@ -24,22 +26,24 @@ def home() -> str: ) -@general_bp.route("/map", defaults={"id": None}) -@general_bp.route("/map/") -def map(id) -> str: +@general_bp.route("/map") +def map_view() -> str: + "Generate the map view" locs = Location.query.order_by("name") return render_template("maps.html", locations=locs) @general_bp.route("/location") def locations() -> str: + "Generate the location view" locs = Location.query.order_by("name") return render_template("locations.html", locations=locs) -@general_bp.route("/location/") -def location(id) -> str: - loc = Location.query.filter(Location.id == id).first() +@general_bp.route("/location/") +def location(location_id) -> str: + "Generate the location view given an id" + loc = Location.query.filter(Location.id == location_id).first() if loc is None: abort(404) return render_template("location.html", location=loc, title=loc.name) @@ -47,18 +51,22 @@ def location(id) -> str: @general_bp.route("/about/") def about() -> str: + "Generate the about view" return render_template("about.html") @general_bp.route("/profile/") @login_required def profile() -> str: + "Generate the profile view" return render_template("profile.html") @general_bp.route("/favicon.ico") def favicon() -> str: - if len(get_orders((Order.stoptime > datetime.now()))) == 0: + "Generate the favicon" + # pylint: disable=R1705 + if not get_orders((Order.stoptime > datetime.now())): return send_from_directory( os.path.join(str(app.root_path), "static"), "favicon.ico", diff --git a/app/views/order.py b/app/views/order.py index b9d4b16..ad0cae9 100644 --- a/app/views/order.py +++ b/app/views/order.py @@ -1,13 +1,13 @@ +"Script to generate the order related views of Haldis" import random import typing from datetime import datetime -import werkzeug +from werkzeug.wrappers import Response # from flask import current_app as app from flask import (Blueprint, abort, flash, redirect, render_template, request, session, url_for, wrappers) from flask_login import current_user, login_required -from werkzeug.wrappers import Response from forms import AnonOrderItemForm, OrderForm, OrderItemForm from models import Order, OrderItem, User, db @@ -18,6 +18,7 @@ order_bp = Blueprint("order_bp", "order") @order_bp.route("/") def orders(form: OrderForm = None) -> str: + "Generate general order view" if form is None and not current_user.is_anonymous(): form = OrderForm() location_id = request.args.get("location_id") @@ -30,6 +31,7 @@ def orders(form: OrderForm = None) -> str: @order_bp.route("/create", methods=["POST"]) @login_required def order_create() -> typing.Union[str, Response]: + "Generate order create view" orderForm = OrderForm() orderForm.populate() if orderForm.validate_on_submit(): @@ -38,33 +40,35 @@ def order_create() -> typing.Union[str, Response]: db.session.add(order) db.session.commit() post_order_to_webhook(order) - return redirect(url_for("order_bp.order", id=order.id)) + return redirect(url_for("order_bp.order_from_id", order_id=order.id)) return orders(form=orderForm) -@order_bp.route("/") -def order(id: int, form: OrderForm = None) -> str: - order = Order.query.filter(Order.id == id).first() +@order_bp.route("/") +def order_from_id(order_id: int, form: OrderForm = None) -> str: + "Generate order view from id" + order = Order.query.filter(Order.id == order_id).first() if order is None: abort(404) if current_user.is_anonymous() and not order.public: flash("Please login to see this order.", "info") abort(401) if form is None: - form = AnonOrderItemForm() if current_user.is_anonymous() else OrderItemForm() + form = AnonOrderItemForm() if current_user.is_anonymous() \ + else OrderItemForm() form.populate(order.location) if order.stoptime and order.stoptime < datetime.now(): form = None total_price = sum([o.product.price for o in order.items]) debts = sum([o.product.price for o in order.items if not o.paid]) - return render_template( - "order.html", order=order, form=form, total_price=total_price, debts=debts - ) + return render_template("order.html", order=order, form=form, + total_price=total_price, debts=debts) -@order_bp.route("//items") -def items_showcase(id: int, form: OrderForm = None) -> str: - order = Order.query.filter(Order.id == id).first() +@order_bp.route("//items") +def items_showcase(order_id: int) -> str: + "Generate order items view from id" + order = Order.query.filter(Order.id == order_id).first() if order is None: abort(404) if current_user.is_anonymous() and not order.public: @@ -73,11 +77,13 @@ def items_showcase(id: int, form: OrderForm = None) -> str: return render_template("order_items.html", order=order) -@order_bp.route("//edit", methods=["GET", "POST"]) +@order_bp.route("//edit", methods=["GET", "POST"]) @login_required -def order_edit(id: int) -> typing.Union[str, Response]: - order = Order.query.filter(Order.id == id).first() - if current_user.id is not order.courrier_id and not current_user.is_admin(): +def order_edit(order_id: int) -> typing.Union[str, Response]: + "Generate order edit view from id" + order = Order.query.filter(Order.id == order_id).first() + if current_user.id is not order.courrier_id and \ + not current_user.is_admin(): abort(401) if order is None: abort(404) @@ -86,15 +92,17 @@ def order_edit(id: int) -> typing.Union[str, Response]: if orderForm.validate_on_submit(): orderForm.populate_obj(order) db.session.commit() - return redirect(url_for("order_bp.order", id=order.id)) - return render_template("order_edit.html", form=orderForm, order_id=id) + return redirect(url_for("order_bp.order_from_id", order_id=order.id)) + return render_template("order_edit.html", form=orderForm, + order_id=order_id) -@order_bp.route("//create", methods=["POST"]) -def order_item_create(id: int) -> typing.Any: +@order_bp.route("//create", methods=["POST"]) +def order_item_create(order_id: int) -> typing.Any: # type is 'typing.Union[str, Response]', but this errors due to # https://github.com/python/mypy/issues/7187 - current_order = Order.query.filter(Order.id == id).first() + "Add item to order from id" + current_order = Order.query.filter(Order.id == order_id).first() if current_order is None: abort(404) if current_order.stoptime and current_order.stoptime < datetime.now(): @@ -102,12 +110,13 @@ def order_item_create(id: int) -> typing.Any: if current_user.is_anonymous() and not current_order.public: flash("Please login to see this order.", "info") abort(401) - form = AnonOrderItemForm() if current_user.is_anonymous() else OrderItemForm() + form = AnonOrderItemForm() if current_user.is_anonymous() \ + else OrderItemForm() form.populate(current_order.location) if form.validate_on_submit(): item = OrderItem() form.populate_obj(item) - item.order_id = id + item.order_id = order_id if not current_user.is_anonymous(): item.user_id = current_user.id else: @@ -115,26 +124,31 @@ def order_item_create(id: int) -> typing.Any: db.session.add(item) db.session.commit() flash("Ordered %s" % (item.product.name), "success") - return redirect(url_for("order_bp.order", id=id)) - return order(id, form=form) + return redirect(url_for("order_bp.order_from_id", order_id=order_id)) + return order_from_id(order_id, form=form) @order_bp.route("///paid", methods=["POST"]) @login_required +# pylint: disable=R1710 def item_paid(order_id: int, item_id: int) -> typing.Optional[Response]: + "Indicate payment status for an item in an order" item = OrderItem.query.filter(OrderItem.id == item_id).first() - id = current_user.id - if item.order.courrier_id == id or current_user.admin: + user_id = current_user.id + if item.order.courrier_id == user_id or current_user.admin: item.paid = True db.session.commit() - flash("Paid %s by %s" % (item.product.name, item.get_name()), "success") - return redirect(url_for("order_bp.order", id=order_id)) + flash("Paid %s by %s" % (item.product.name, item.get_name()), + "success") + return redirect(url_for("order_bp.order_from_id", order_id=order_id)) abort(404) @order_bp.route("///user_paid", methods=["POST"]) @login_required -def items_user_paid(order_id: int, user_name: str) -> typing.Optional[Response]: +# pylint: disable=R1710 +def items_user_paid(order_id: int, user_name: str) -> typing.Optional[Response]: # pylint:disable=C0301 + "Indicate payment status for a user in an order" user = User.query.filter(User.username == user_name).first() items: typing.List[OrderItem] = [] if user: @@ -152,33 +166,37 @@ def items_user_paid(order_id: int, user_name: str) -> typing.Optional[Response]: for item in items: item.paid = True db.session.commit() - flash("Paid %d items for %s" % (len(items), item.get_name()), "success") - return redirect(url_for("order_bp.order", id=order_id)) + flash("Paid %d items for %s" % + (len(items), item.get_name()), "success") + return redirect(url_for("order_bp.order_from_id", order_id=order_id)) abort(404) @order_bp.route("///delete", methods=["POST"]) +# pylint: disable=R1710 def delete_item(order_id: int, item_id: int) -> typing.Any: # type is 'typing.Optional[Response]', but this errors due to # https://github.com/python/mypy/issues/7187 + "Delete an item from an order" item = OrderItem.query.filter(OrderItem.id == item_id).first() - id = None + user_id = None if not current_user.is_anonymous(): print("%s tries to delete orders" % (current_user.username)) - id = current_user.id - if item.can_delete(order_id, id, session.get("anon_name", "")): + user_id = current_user.id + if item.can_delete(order_id, user_id, session.get("anon_name", "")): product_name = item.product.name db.session.delete(item) db.session.commit() flash("Deleted %s" % (product_name), "success") - return redirect(url_for("order_bp.order", id=order_id)) + return redirect(url_for("order_bp.order_from_id", order_id=order_id)) abort(404) -@order_bp.route("//volunteer", methods=["POST"]) +@order_bp.route("//volunteer", methods=["POST"]) @login_required -def volunteer(id: int) -> Response: - order = Order.query.filter(Order.id == id).first() +def volunteer(order_id: int) -> Response: + "Add a volunteer to an order" + order = Order.query.filter(Order.id == order_id).first() if order is None: abort(404) if order.courrier_id is None or order.courrier_id == 0: @@ -187,18 +205,18 @@ def volunteer(id: int) -> Response: flash("Thank you for volunteering!") else: flash("Volunteering not possible!") - return redirect(url_for("order_bp.order", id=id)) + return redirect(url_for("order_bp.order_from_id", order_id=order_id)) -@order_bp.route("//close", methods=["POST"]) +@order_bp.route("//close", methods=["POST"]) @login_required -def close_order(id: int) -> typing.Optional[Response]: - order = Order.query.filter(Order.id == id).first() +def close_order(order_id: int) -> typing.Optional[Response]: + "Close an order" + order = Order.query.filter(Order.id == order_id).first() if order is None: abort(404) if (current_user.id == order.courrier_id or current_user.is_admin()) and ( - order.stoptime is None or (order.stoptime > datetime.now()) - ): + order.stoptime is None or (order.stoptime > datetime.now())): order.stoptime = datetime.now() if order.courrier_id == 0 or order.courrier_id is None: courrier = select_user(order.items) @@ -206,7 +224,7 @@ def close_order(id: int) -> typing.Optional[Response]: if courrier is not None: order.courrier_id = courrier.id db.session.commit() - return redirect(url_for("order_bp.order", id=id)) + return redirect(url_for("order_bp.order_from_id", order_id=order_id)) # The line below is to make sure mypy doesn't say # "Missing return statement" # https://github.com/python/mypy/issues/4223 @@ -214,11 +232,12 @@ def close_order(id: int) -> typing.Optional[Response]: def select_user(items) -> typing.Optional[User]: + "Select a random user from those who are signed up for the order" user = None # remove non users items = [i for i in items if i.user_id] - if len(items) <= 0: + if not items: return None while user is None: @@ -232,13 +251,17 @@ def select_user(items) -> typing.Optional[User]: def get_orders(expression=None) -> typing.List[Order]: - orders: typing.List[OrderForm] = [] + "Give the list of all currently open and public Orders" + order_list: typing.List[OrderForm] = [] if expression is None: expression = (datetime.now() > Order.starttime) & ( Order.stoptime > datetime.now() + # pylint: disable=C0121 ) | (Order.stoptime == None) if not current_user.is_anonymous(): - orders = Order.query.filter(expression).all() + order_list = Order.query.filter(expression).all() else: - orders = Order.query.filter((expression & (Order.public == True))).all() - return orders + order_list = Order.query.filter( + # pylint: disable=C0121 + (expression & (Order.public == True))).all() + return order_list diff --git a/app/views/stats.py b/app/views/stats.py index 73ad1b1..02771a2 100644 --- a/app/views/stats.py +++ b/app/views/stats.py @@ -1,3 +1,4 @@ +"Script to generate the stats related views of Haldis" from flask import Blueprint from flask import current_app as app from flask import render_template @@ -9,6 +10,7 @@ stats_blueprint = Blueprint("stats_blueprint", __name__) @stats_blueprint.route("/") def stats() -> str: + "Generate Haldis data in a pretty format" data = { "amount": { "orders": FatOrder.amount(),