Compare commits

...

2 Commits

10 changed files with 100 additions and 57 deletions

View File

@ -22,12 +22,7 @@ def create_app():
app.config.from_file("config.json", load=json.load, silent=True)
db.init_app(app)
# This function denies every request until `auth.ACCESS_TOKEN`
# is passed using `?token=` to authenticate the session.
@app.before_request
def before_req_fun():
return auth.before_request()
auth.init_app(app)
@app.context_processor
def utility_processor():

View File

@ -1,7 +1,10 @@
import secrets
import string
from flask import Blueprint, request, redirect, render_template, session
from flask import Blueprint, request, redirect, render_template
from flask_login import current_user, login_user, logout_user, LoginManager
from typing import Any, Dict, List, Optional
bp = Blueprint("auth", __name__, url_prefix="/auth")
@ -15,27 +18,67 @@ ALLOWED_PATHS = [
]
def before_request():
"""
If the correct token query parameter is passed along with any request,
we mark this session authenticated by setting `session["authenticated"]`.
Unless the session is authenticated, all requests result in a 403 FORBIDDEN.
"""
if "token" in request.args:
if request.args["token"] == ACCESS_TOKEN:
session["authenticated"] = ()
# Reload the page without query parameters
return redirect(request.path)
# A poor man's replacement for memory-backed session solution.
# We keep exactly one User (and the corresponding UserData) in
# memory and use that to store session data.
class UserData:
location: Optional[Dict[str, Any]]
orders: List[Dict[str, Any]]
# Don't deny any paths in `ALLOWED_PATHS`
if request.path in ALLOWED_PATHS:
return
def __init__(self):
self.location = None
self.orders = []
if not "authenticated" in session:
return render_template("auth/denied.html"), 403
class User:
is_authenticated: bool
is_active: bool
is_anonymous: bool
data: UserData
def __init__(self):
self.is_authenticated = True
self.is_active = True
self.is_anonymous = False
self.data = UserData()
def get_id(self) -> str:
return ""
def init_app(app):
login_manager = LoginManager(app)
the_one_and_only_user = User()
@login_manager.user_loader
def load_user(user_id: str) -> User:
assert user_id == ""
return the_one_and_only_user
# This function denies every request until `auth.ACCESS_TOKEN`
# is passed using `?token=` to authenticate the user.
# We use this instead of @login_required because otherwise we'd have
# to add that annotation to all routes.
# See also: https://flask-login.readthedocs.io/en/latest/#flask_login.login_required
@app.before_request
def before_request():
if "token" in request.args:
if request.args["token"] == ACCESS_TOKEN:
login_user(the_one_and_only_user)
# Reload the page without query parameters
return redirect(request.path)
# Never deny any paths in `ALLOWED_PATHS`
if request.path in ALLOWED_PATHS:
return
if not current_user.is_authenticated:
return render_template("auth/denied.html"), 403
@bp.get("/logout")
def logout():
session.pop("authenticated", None)
logout_user()
return redirect("/")

View File

@ -1,5 +1,5 @@
from flask import Blueprint, flash, redirect, render_template, request, session
from flask import Blueprint, flash, redirect, render_template, request
from flask_login import current_user
from . import db
@ -9,22 +9,18 @@ bp = Blueprint("entry", __name__, url_prefix="/entry")
@bp.route("/", methods=["GET", "POST"])
def index():
cart = session.get("cart", default=[])
return render_template(
"entry/index.html",
cart=cart
"entry/index.html"
)
@bp.post("/add-new-items")
def add_new_entries():
print(session)
i_know_what_im_doing = "i-know-what-im-doing" in request.form
if not i_know_what_im_doing:
return "Du weißt nicht was du tust", 400
orders = session.get("cart", default=[])
orders = current_user.data.orders
if not orders:
return "Keine Aufträge", 404
@ -36,7 +32,7 @@ def add_new_entries():
db.get_db().commit()
# Reset the cart
session["cart"] = []
current_user.data.orders = []
return redirect(request.referrer)
@ -48,9 +44,7 @@ def delete_order():
except:
return "Incomplete or mistyped form", 400
cart = session.get("cart", default=[])
del cart[order_index]
session["cart"] = cart
del current_user.data.orders[order_index]
return redirect(request.referrer)
@ -76,9 +70,7 @@ def new_order():
except:
return f"Incomplete or mistyped form", 400
cart = session.get("cart", default=[])
print(cart)
cart.append({
current_user.data.orders.append({
"barcode": barcode,
"name": name,
"sales_units": sales_units,
@ -91,7 +83,6 @@ def new_order():
"net_unit_price": net_unit_price,
"gross_unit_price": gross_unit_price
})
session["cart"] = cart
return redirect("/entry")
with db.run_query("entry/get_groups.sql") as cursor:
@ -122,10 +113,9 @@ def api_search_items():
except:
return {"error": "Missing query parameter `search-term`"}, 400
location = session.get("location", None)
location = current_user.data.location
with db.run_query("search_items.sql", {
"location_id": None if location is None else location["location_id"],
"location_id": location["location_id"] if location else None,
"search_term": search_term
}) as cursor:
items = cursor.fetchall()

View File

@ -1,4 +1,5 @@
from flask import Blueprint, redirect, render_template, request, session
from flask import Blueprint, redirect, render_template, request
from flask_login import current_user
from . import db
@ -8,7 +9,7 @@ bp = Blueprint("inventory", __name__, url_prefix="/inventory")
@bp.get("/")
def index():
location = session.get("location", None)
location = current_user.data.location
items = db.run_query("get_inventory_overview.sql", {
"location_id": None if location is None else location["location_id"]
}).fetchall()
@ -20,7 +21,7 @@ def index():
@bp.get("/report")
def read_report():
location = session.get("location", None)
location = current_user.data.location
items = db.run_query("get_inventory_report.sql", {
"location_id": None if location is None else location["location_id"]
}).fetchall()

View File

@ -1,4 +1,5 @@
from flask import Blueprint, render_template, request, session
from flask import Blueprint, render_template, request
from flask_login import current_user
from . import db
@ -11,13 +12,12 @@ def index():
if request.method == "POST":
location_id = request.form.get("location_id", "")
if location_id == "":
session.pop("location", None)
current_user.data.location = None
else:
location = db.run_query("get_location_by_id.sql", {
"location_id": location_id}
).fetchone()
session["location"] = location
"location_id": location_id
}).fetchone()
current_user.data.location = location
locations = db.run_query("get_locations.sql").fetchall()

View File

@ -71,3 +71,6 @@ th {
display: block;
width: 8em;
}
details {
font-size: 0.8em;
}

View File

@ -15,10 +15,10 @@
<li{{ " class=current-page" if request.path.startswith("/entry") else "" }}><a href="/entry">Eintragen</a></li>
<li{{ " class=current-page" if request.path.startswith("/location") else "" }}>
<a href="/location">
{% if "location" not in session %}
{% if not current_user.data.location %}
Raum wählen
{% else %}
Raum: {{ session.location.location_name }}
Raum: {{ current_user.data.location.location_name }}
{% endif %}
</a>
</li>
@ -30,6 +30,16 @@
<details>
<summary><code>config</code></summary>
<pre>{% for key, value in config.items() %}{{ key }} = {{ value }}
{% endfor %}</pre>
</details>
<details>
<summary><code>session</code></summary>
<pre>{% for key, value in session.items() %}{{ key }} = {{ value }}
{% endfor %}</pre>
</details>
<details>
<summary><code>current_user.data</code></summary>
<pre>{% for key, value in current_user.data.__dict__.items() %}{{ key }} = {{ value }}
{% endfor %}</pre>
</details>
{% endif %}

View File

@ -15,7 +15,7 @@
<th>VK-Preis (Brutto)</th>
<th>Aktionen</th>
</tr>
{% for cart_item in cart %}
{% for cart_item in current_user.data.orders %}
<tr>
<td><code>{{ cart_item.barcode }}</code></td>
<td>{{ cart_item.name }}</td>

View File

@ -3,9 +3,9 @@
{% block content %}
<form method="POST">
<select name="location_id">
<option value="" {{ "selected" if "location" not in session else ""}}>-</option>
<option value="" {{ "selected" if not current_user.data.location else ""}}>-</option>
{% for location in locations %}
<option value="{{ location.location_id }}" {{ "selected" if "location" in session and session.location.location_id == location.location_id else "" }}>{{ location.location_name }}</option>
<option value="{{ location.location_id }}" {{ "selected" if current_user.data.location.location_id == location.location_id else "" }}>{{ location.location_name }}</option>
{% endfor %}
</select>

View File

@ -1,6 +1,7 @@
blinker==1.6.2
click==8.1.3
Flask==2.3.2
Flask-Login==0.6.2
itsdangerous==2.1.2
Jinja2==3.1.2
MarkupSafe==2.1.2