Add last drink info and move drink types
All checks were successful
Test FastAPI Startup / fastapi-up (push) Successful in 19s
All checks were successful
Test FastAPI Startup / fastapi-up (push) Successful in 19s
This commit is contained in:
48
db/models.py
48
db/models.py
@@ -632,7 +632,47 @@ def del_user_prepaid(user_id: int):
|
||||
connection.commit()
|
||||
return result.rowcount
|
||||
|
||||
def get_last_drink(user_id: int, user_is_postpaid: bool, max_since_seconds: int = 60):
|
||||
def get_last_drink(user_id: int, user_is_postpaid: bool, max_since_seconds: int = 3*30*24*60*60):
|
||||
"""
|
||||
Retrieve the most recent drink entry for a user within a specified time window.
|
||||
|
||||
Args:
|
||||
user_id (int): The ID of the user whose last drink is to be retrieved.
|
||||
user_is_postpaid (bool): True if the user is postpaid, False if prepaid.
|
||||
max_since_seconds (int, optional): Max seconds since last drink. Defaults to 3 months.
|
||||
|
||||
Returns:
|
||||
dict or None: Dict with 'id', 'timestamp', 'drink_type' if found within time window,
|
||||
else None.
|
||||
"""
|
||||
if user_is_postpaid:
|
||||
t = text("SELECT id, timestamp, drink_type FROM drinks WHERE postpaid_user_id = :user_id ORDER BY timestamp DESC LIMIT 1")
|
||||
else:
|
||||
t = text("SELECT id, timestamp, drink_type FROM drinks WHERE prepaid_user_id = :user_id ORDER BY timestamp DESC LIMIT 1")
|
||||
|
||||
with engine.connect() as connection:
|
||||
result = connection.execute(t, {"user_id": user_id}).fetchone()
|
||||
if not result:
|
||||
return None
|
||||
drink_id, timestamp, drink_type_id = result
|
||||
|
||||
if timestamp:
|
||||
now = datetime.datetime.now(datetime.timezone.utc)
|
||||
last_drink_time = datetime.datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
|
||||
# Ensure both are offset-aware
|
||||
if last_drink_time.tzinfo is None:
|
||||
last_drink_time = last_drink_time.replace(tzinfo=datetime.timezone.utc)
|
||||
if (now - last_drink_time).total_seconds() > max_since_seconds:
|
||||
return None
|
||||
drink_obj = {"id": drink_id, "timestamp": timestamp, "drink_type_id": drink_type_id}
|
||||
if drink_type_id:
|
||||
drink_type_dict = get_drink_type(drink_type_id)
|
||||
drink_obj["drink_type_name"] = drink_type_dict["drink_name"]
|
||||
drink_obj["drink_type_icon"] = drink_type_dict["icon"]
|
||||
return drink_obj
|
||||
return None
|
||||
|
||||
def get_last_recent_drink(user_id: int, user_is_postpaid: bool, max_since_seconds: int = 60):
|
||||
"""
|
||||
Retrieve the most recent drink entry for a user within a specified time window.
|
||||
|
||||
@@ -666,9 +706,9 @@ def get_last_drink(user_id: int, user_is_postpaid: bool, max_since_seconds: int
|
||||
return None
|
||||
drink_obj = {"id": drink_id, "timestamp": timestamp, "drink_type_id": drink_type_id}
|
||||
if drink_type_id:
|
||||
drink_type_name, drink_type_icon = get_drink_type(drink_type_id)
|
||||
drink_obj["drink_type_name"] = drink_type_name
|
||||
drink_obj["drink_type_icon"] = drink_type_icon
|
||||
drink_type_dict = get_drink_type(drink_type_id)
|
||||
drink_obj["drink_type_name"] = drink_type_dict["drink_name"]
|
||||
drink_obj["drink_type_icon"] = drink_type_dict["icon"]
|
||||
return drink_obj
|
||||
return None
|
||||
|
||||
|
||||
10
main.py
10
main.py
@@ -92,9 +92,12 @@ def home(request: Request):
|
||||
db_user = db.models.get_prepaid_user(user_db_id)
|
||||
|
||||
# get last drink for current user, if not less than 60 seconds ago
|
||||
last_drink = db.models.get_last_drink(user_db_id, user_is_postpaid, 60)
|
||||
last_recent_drink = db.models.get_last_recent_drink(user_db_id, user_is_postpaid, 60)
|
||||
|
||||
most_used_drinks = db.models.get_most_used_drinks(user_db_id, user_is_postpaid, 3)
|
||||
# get last drink for current user, if not less than 3 months ago
|
||||
last_regular_drink = db.models.get_last_drink(user_db_id, user_is_postpaid)
|
||||
|
||||
most_used_drinks = db.models.get_most_used_drinks(user_db_id, user_is_postpaid, 99)
|
||||
most_used_drinks.append({"drink_type_id": 1, "drink_type": "Sonstiges", "count": 0, "icon": "sonstiges.png"}) # ensure "Sonstiges" is in
|
||||
|
||||
return templates.TemplateResponse("index.html", {
|
||||
@@ -105,7 +108,8 @@ def home(request: Request):
|
||||
"db_user": db_user,
|
||||
"db_users_prepaid": db_users_prepaid,
|
||||
"prepaid_users_from_curr_user": prepaid_users_from_curr_user,
|
||||
"last_drink": last_drink,
|
||||
"last_recent_drink": last_recent_drink,
|
||||
"last_regular_drink": last_regular_drink,
|
||||
"avail_drink_types": most_used_drinks,
|
||||
"drink_types": drink_types,
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{% extends "base.html" %} {% block title %}Startseite{% endblock %} {% block
|
||||
{% extends "base.html" %} {% block title %}Getränkeliste{% endblock %} {% block
|
||||
content %}
|
||||
<h2>Willkommen, {{ user.name }}!</h2>
|
||||
<p><strong>Aktueller Kontostand:</strong></p>
|
||||
@@ -29,7 +29,55 @@ content %}
|
||||
Bitte begleiche deinen offenen Betrag!
|
||||
</span>
|
||||
</div>
|
||||
{% endif %} {% if 'Getraenkeliste Postpaid' in user.groups %} {% if db_user.money > -5000 %}
|
||||
{% endif %}
|
||||
{% if last_recent_drink %}
|
||||
<div style="margin: 1em 0; text-align: center;">
|
||||
<strong>Getränk spezialisieren:</strong>
|
||||
<div style="display: flex; flex-wrap: wrap; justify-content: center; gap: 1em; margin-top: 1em;">
|
||||
{% for drink in avail_drink_types %}
|
||||
<form method="post" action="/update_drink_post" style="display: inline-block;">
|
||||
<input type="hidden" name="drink_type" value="{{ drink.drink_type }}">
|
||||
<button type="submit"
|
||||
style="display: flex; flex-direction: column; align-items: center; background-color: var(--goetheblau); color: #fff; border: none; border-radius: 8px; padding: 0.7em 1.2em; cursor: pointer; min-width: 120px;">
|
||||
<img src="/static/drinks/{{ drink.icon }}" alt="{{ drink.drink_type }}" style="width:48px; height:48px; object-fit:contain; margin-bottom:0.5em;">
|
||||
<span>{{ drink.drink_type }}</span>
|
||||
{% if drink.count > 0 %}
|
||||
<span style="font-size:0.9em; color:#eee;">x{{ drink.count }}</span>
|
||||
{% endif %}
|
||||
</button>
|
||||
</form>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 1em 0; text-align: center;">
|
||||
<strong>Letztes Getränk:</strong>
|
||||
<div style="margin: 0.5em 0;">
|
||||
Typ: {{ last_recent_drink.drink_type_name }}<br>
|
||||
Zeit: <span class="local-timestamp" data-utc="{{ last_recent_drink.timestamp }}">{{ last_recent_drink.timestamp }}</span><br>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.querySelectorAll('.local-timestamp').forEach(function(el) {
|
||||
const utc = el.getAttribute('data-utc');
|
||||
if (utc) {
|
||||
const date = new Date(utc);
|
||||
el.textContent = date.toLocaleString();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
ID: {{ last_recent_drink.id }}
|
||||
</div>
|
||||
<form method="post" action="/del_last_drink" style="display: inline;">
|
||||
<input type="hidden" name="drink_id" value="{{ last_recent_drink.drink_id }}">
|
||||
<button type="submit"
|
||||
style="background-color: var(--emorot); color: #fff; border: none; border-radius: 6px; padding: 0.5em 1em; cursor: pointer;">
|
||||
Getränk löschen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if 'Getraenkeliste Postpaid' in user.groups %} {% if db_user.money > -5000 %}
|
||||
<div style="display: flex; justify-content: center; text-align: center">
|
||||
<form method="post" action="/drink">
|
||||
<button
|
||||
@@ -72,53 +120,6 @@ content %}
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if last_drink %}
|
||||
<div style="margin: 1em 0; text-align: center;">
|
||||
<strong>Getränk spezialisieren:</strong>
|
||||
<div style="display: flex; flex-wrap: wrap; justify-content: center; gap: 1em; margin-top: 1em;">
|
||||
{% for drink in avail_drink_types %}
|
||||
<form method="post" action="/update_drink_post" style="display: inline-block;">
|
||||
<input type="hidden" name="drink_type" value="{{ drink.drink_type }}">
|
||||
<button type="submit"
|
||||
style="display: flex; flex-direction: column; align-items: center; background-color: var(--goetheblau); color: #fff; border: none; border-radius: 8px; padding: 0.7em 1.2em; cursor: pointer; min-width: 120px;">
|
||||
<img src="/static/drinks/{{ drink.icon }}" alt="{{ drink.drink_type }}" style="width:48px; height:48px; object-fit:contain; margin-bottom:0.5em;">
|
||||
<span>{{ drink.drink_type }}</span>
|
||||
{% if drink.count > 0 %}
|
||||
<span style="font-size:0.9em; color:#eee;">x{{ drink.count }}</span>
|
||||
{% endif %}
|
||||
</button>
|
||||
</form>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin: 1em 0; text-align: center;">
|
||||
<strong>Letztes Getränk:</strong>
|
||||
<div style="margin: 0.5em 0;">
|
||||
Typ: {{ last_drink.drink_type_name }}<br>
|
||||
Zeit: <span class="local-timestamp" data-utc="{{ last_drink.timestamp }}">{{ last_drink.timestamp }}</span><br>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.querySelectorAll('.local-timestamp').forEach(function(el) {
|
||||
const utc = el.getAttribute('data-utc');
|
||||
if (utc) {
|
||||
const date = new Date(utc);
|
||||
el.textContent = date.toLocaleString();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
ID: {{ last_drink.id }}
|
||||
</div>
|
||||
<form method="post" action="/del_last_drink" style="display: inline;">
|
||||
<input type="hidden" name="drink_id" value="{{ last_drink.drink_id }}">
|
||||
<button type="submit"
|
||||
style="background-color: var(--emorot); color: #fff; border: none; border-radius: 6px; padding: 0.5em 1em; cursor: pointer;">
|
||||
Getränk löschen
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
@@ -156,11 +157,46 @@ content %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if last_regular_drink %}
|
||||
<div style="margin: 1em 0; text-align: center;">
|
||||
<strong>Letztes Getränk:</strong>
|
||||
<div style="margin: 0.5em 0;">
|
||||
Typ: {{ last_regular_drink.drink_type_name }}<br>
|
||||
Zeit: <span class="local-timestamp" data-utc="{{ last_regular_drink.timestamp }}">{{ last_regular_drink.timestamp }}</span><br>
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.querySelectorAll('.local-timestamp').forEach(function(el) {
|
||||
const utc = el.getAttribute('data-utc');
|
||||
if (utc) {
|
||||
const date = new Date(utc);
|
||||
el.textContent = date.toLocaleString();
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="margin: 1em 0; text-align: center;">
|
||||
<strong>Letztes Getränk:</strong>
|
||||
<div style="margin: 0.5em 0;">Kein Getränk in den letzten 3 Monaten.</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if most_used_drinks %}
|
||||
<h3>Meistgenutzte Getränke:</h3>
|
||||
<ul style="list-style-type: none; padding: 0; display: flex; flex-wrap: wrap; gap: 1em; justify-content: center;">
|
||||
{% for drink in most_used_drinks %}
|
||||
<li style="text-align: center;">
|
||||
<img src="/static/drinks/{{ drink.icon }}" alt="{{ drink.drink_type }}" style="width:48px; height:48px; object-fit:contain;"><br>
|
||||
{{ drink.drink_type }} ({{ drink.count }})
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if user %}
|
||||
{% if 'Getraenkeliste Postpaid' in user.groups %}
|
||||
<p>Du bist Teil der Fachschaft Informatik.</p>
|
||||
{% if prepaid_users_from_curr_user %}
|
||||
<p>Liste deiner Prepaid-User:</p>
|
||||
<table>
|
||||
|
||||
Reference in New Issue
Block a user