Add Prepaid users and activate button

This commit is contained in:
2025-05-17 12:41:46 +02:00
parent d4e01d5109
commit 1fb1b27480
4 changed files with 335 additions and 4 deletions

View File

@@ -16,6 +16,7 @@ Functions:
- drink_postpaid_user(user_id: int) -> int:
Deducts 100 units from the specified postpaid user's balance and records a drink entry. Raises HTTPException if the user is not found or if the drink entry could not be created. Returns the number of rows affected by the drink entry insertion.
"""
import secrets
from sqlalchemy import create_engine, text
from fastapi import HTTPException
@@ -42,7 +43,7 @@ with engine.connect() as conn:
user_key TEXT NOT NULL UNIQUE,
postpaid_user_id INTEGER NOT NULL,
money INT DEFAULT 0,
activated BOOLEAN DEFAULT 0,
activated BOOLEAN DEFAULT 1,
last_drink TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (postpaid_user_id) REFERENCES users_postpaid(id)
)
@@ -172,6 +173,10 @@ def drink_postpaid_user(user_id: int):
int: The number of rows affected by the drink entry insertion (should be 1 on success).
"""
activated = get_postpaid_user(user_id)["activated"]
if not activated:
raise HTTPException(status_code=403, detail="User not activated")
prev_money = get_postpaid_user(user_id)["money"]
t = text("UPDATE users_postpaid SET money = :money, last_drink = CURRENT_TIMESTAMP WHERE id = :id")
with engine.connect() as connection:
@@ -187,3 +192,82 @@ def drink_postpaid_user(user_id: int):
raise HTTPException(status_code=500, detail="Failed to create drink entry")
connection.commit()
return result.rowcount
def toggle_activate_postpaid_user(user_id: int):
prev_activated = get_postpaid_user(user_id)["activated"]
t = text("UPDATE users_postpaid SET activated = :activated WHERE id = :id")
with engine.connect() as connection:
result = connection.execute(t, {"id": user_id, "activated": not prev_activated})
if result.rowcount == 0:
raise HTTPException(status_code=404, detail="User not found")
connection.commit()
return result.rowcount
def get_prepaid_user(user_id: int):
t = text("SELECT id, username, user_key, postpaid_user_id, money, activated, last_drink FROM users_prepaid WHERE id = :id")
user_db = {}
with engine.connect() as connection:
result = connection.execute(t, {"id": user_id}).fetchone()
if result:
user_db["id"] = result[0]
user_db["username"] = result[1]
user_db["user_key"] = result[2]
user_db["postpaid_user_id"] = result[3]
user_db["money"] = result[4]
user_db["activated"] = result[5]
user_db["last_drink"] = result[6]
else:
raise HTTPException(status_code=404, detail="User not found")
return user_db
def get_prepaid_user_by_username(username: str):
"""
Retrieve a prepaid user from the database by their username.
Args:
username (str): The username of the user to retrieve.
Returns:
dict: A dictionary containing the user's id, username, money, activated status, and last_drink timestamp.
Raises:
HTTPException: If no user with the given username is found, raises a 404 HTTPException.
"""
t = text("SELECT id, username, user_key, postpaid_user_id, money, activated, last_drink FROM users_prepaid WHERE username = :username")
user_db = {}
with engine.connect() as connection:
result = connection.execute(t, {"username": username}).fetchone()
if result:
user_db["id"] = result[0]
user_db["username"] = result[1]
user_db["user_key"] = result[2]
user_db["postpaid_user_id"] = result[3]
user_db["money"] = result[4]
user_db["activated"] = result[5]
user_db["last_drink"] = result[6]
else:
raise HTTPException(status_code=404, detail="User not found")
return user_db
def create_prepaid_user(prepaid_username: str, postpaid_user_id: int, start_money: int = 0):
prepaid_key = secrets.token_urlsafe(6)
t = text("INSERT INTO users_prepaid (username, user_key, postpaid_user_id, money) VALUES (:username, :user_key, :postpaid_user_id, :start_money)")
with engine.connect() as connection:
# Check if user already exists in prepaid
sel = text("SELECT * FROM users_prepaid WHERE username = :username")
if connection.execute(sel, {"username": prepaid_username}).fetchone():
raise HTTPException(status_code=400, detail="User already exists")
result = connection.execute(
t,
{
"username": str(prepaid_username),
"user_key": str(prepaid_key),
"postpaid_user_id": int(postpaid_user_id),
"start_money": int(start_money),
})
if result.rowcount == 0:
raise HTTPException(status_code=500, detail="Failed to create user")
connection.commit()
return result.lastrowid

69
main.py
View File

@@ -12,6 +12,10 @@ from db.models import get_postpaid_user
from db.models import get_postpaid_user_by_username
from db.models import set_postpaid_user_money
from db.models import drink_postpaid_user
from db.models import toggle_activate_postpaid_user
from db.models import get_prepaid_user
from db.models import get_prepaid_user_by_username
from db.models import create_prepaid_user
from auth.session import get_current_user
@@ -41,6 +45,7 @@ def home(request: Request):
if not user_db_id or not user_authentik:
raise HTTPException(status_code=404, detail="User nicht gefunden")
users = None
db_users_prepaid = None
if ADMIN_GROUP in user_authentik["groups"]:
with engine.connect() as conn:
t = text("SELECT id FROM users_postpaid")
@@ -51,8 +56,24 @@ def home(request: Request):
user_db = get_postpaid_user(row[0])
if user_db:
users.append(user_db)
t = text("SELECT id FROM users_prepaid")
result = conn.execute(t).fetchall()
print(f"Result: {result}")
if result:
db_users_prepaid = []
for row in result:
prepaid_user = get_prepaid_user(row[0])
if prepaid_user:
db_users_prepaid.append(prepaid_user)
db_user = get_postpaid_user(user_db_id)
return templates.TemplateResponse("index.html", {"request": request, "user": user_authentik, "users": users, "user_db_id": user_db_id, "db_user": db_user})
print("db_users_prepaid", db_users_prepaid)
return templates.TemplateResponse("index.html", {
"request": request,
"user": user_authentik,
"users": users,
"user_db_id": user_db_id,
"db_user": db_user,
"db_users_prepaid": db_users_prepaid})
@app.get("/login", response_class=HTMLResponse)
def login_form(request: Request):
@@ -145,5 +166,51 @@ def payup(request: Request, username: str = Form(...), money: float = Form(...))
set_postpaid_user_money(current_user_db_id, current_user_money - money*100)
return RedirectResponse(url="/", status_code=303)
@app.post("/toggle_activated_user_postpaid")
def toggle_activated_user_postpaid(request: Request, username: str = Form(...)):
user_auth = request.session.get("user_authentik")
if not user_auth or ADMIN_GROUP not in user_auth["groups"]:
raise HTTPException(status_code=403, detail="Nicht erlaubt")
user_db_id = get_postpaid_user_by_username(username)["id"]
if not user_db_id:
raise HTTPException(status_code=404, detail="User nicht gefunden")
toggle_activate_postpaid_user(user_db_id)
return RedirectResponse(url="/", status_code=303)
@app.post("/add_prepaid_user")
def add_prepaid_user(request: Request, username: str = Form(...), start_money: float = Form(...)):
active_user_auth = request.session.get("user_authentik")
active_user_db_id = request.session.get("user_db_id")
if not active_user_auth or ADMIN_GROUP not in active_user_auth["groups"]:
raise HTTPException(status_code=403, detail="Nicht erlaubt")
if not active_user_db_id:
raise HTTPException(status_code=404, detail="Aktueller User nicht gefunden")
if not username:
raise HTTPException(status_code=400, detail="Username ist leer")
user_exists = False
try:
get_postpaid_user_by_username(username)
user_exists = True
get_prepaid_user_by_username(username)
user_exists = True
except HTTPException:
pass
if user_exists:
raise HTTPException(status_code=400, detail="User existiert bereits")
create_prepaid_user(username, active_user_db_id, int(start_money*100))
prev_money = get_postpaid_user(active_user_db_id)["money"]
set_postpaid_user_money(active_user_db_id, prev_money - int(start_money*100))
return RedirectResponse(url="/", status_code=303)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)

View File

@@ -24,7 +24,75 @@
{% block content %}{% endblock %} {% if user %} {% if 'Fachschaft'
in user.groups %}
<p>Du bist Teil der Fachschaft Informatik.</p>
{% endif %} {% if 'Fachschaft Admins' in user.groups %}
<p>Füge Nutzer zur Prepaid Liste hinzu:</p>
<form
method="post"
action="/add_prepaid_user"
style="
display: flex;
gap: 1em;
align-items: center;
margin-bottom: 1em;
background: var(--hellgrau);
padding: 1em;
border-radius: 8px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
max-width: 600px;
"
>
<label
for="username"
style="margin: 0 0.5em 0 0; font-weight: bold"
>Username:</label
>
<input
id="username"
type="text"
name="username"
placeholder="Username"
required
style="
padding: 0.5em;
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
"
/>
<label
for="start_money"
style="margin: 0 0.5em 0 0; font-weight: bold"
>Start Money (€):</label
>
<input
id="start_money"
type="number"
name="start_money"
placeholder="Start Money"
step="0.01"
required
style="
padding: 0.5em;
border: 1px solid #ccc;
border-radius: 4px;
width: 100px;
"
/>
<button
type="submit"
style="
padding: 0.5em 1em;
background: rgb(0, 97, 143);
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
"
>
Add User
</button>
</form>
{% endif %}
{% if 'Fachschaft Admins' in user.groups %}
<h2>Admin Interface</h2>
<p>Ausgleichszahlung:</p>
<p>
@@ -100,7 +168,8 @@
Pay Up
</button>
</form>
<p>Users in database:</p>
<h3>Postpaid Liste</h3>
<p>Users in postpaid database:</p>
<table>
<thead>
<tr>
@@ -143,6 +212,57 @@
{% endfor %}
</tbody>
</table>
<p>(De-)Activate User</p>
<form
method="post"
action="/toggle_activated_user_postpaid"
style="
display: flex;
gap: 1em;
align-items: center;
margin-bottom: 1em;
background: var(--hellgrau);
padding: 1em;
border-radius: 8px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
max-width: 600px;
"
>
<label
for="activate-username"
style="margin: 0 0.5em 0 0; font-weight: bold"
>Username:</label
>
<select
id="activate-username"
name="username"
required
style="
padding: 0.5em;
border: 1px solid #ccc;
border-radius: 4px;
"
>
{% for db_user in users %}
<option value="{{ db_user.username }}">
{{ db_user.username }}
</option>
{% endfor %}
</select>
<button
type="submit"
style="
padding: 0.5em 1em;
background: rgb(0, 97, 143);
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
"
>
Toggle Activation
</button>
</form>
<p>Set user money:</p>
<form
method="post"
@@ -213,6 +333,66 @@
Set Money
</button>
</form>
<h3>Prepaid Liste</h3>
<p>Users in prepaid database:</p>
<table>
<thread>
<tr>
<th style="padding: 0.5em 1em">ID</th>
<th style="padding: 0.5em 1em">Username</th>
<th style="padding: 0.5em 1em">Key</th>
<th style="padding: 0.5em 1em">Postpaid_User ID</th>
<th style="padding: 0.5em 1em">Money (€)</th>
<th style="padding: 0.5em 1em">Activated</th>
<th style="padding: 0.5em 1em">last drink</th>
</tr>
</thread>
<tbody>
{% if db_users_prepaid %}
{% for prepaid_user_i in db_users_prepaid %}
<tr
{%
if
prepaid_user_i.money
<=0
%}
style="background-color: rgba(179, 6, 44, 0.5)"
{%
endif
%}
>
<td style="padding: 0.5em 1em">
{{ prepaid_user_i.id }}
</td>
<td style="padding: 0.5em 1em">
{{ prepaid_user_i.username }}
</td>
<td style="padding: 0.5em 1em">
{{ prepaid_user_i.user_key }}
</td>
<td style="padding: 0.5em 1em">
{{ prepaid_user_i.postpaid_user_id }}
</td>
<td style="padding: 0.5em 1em">
{{ prepaid_user_i.money / 100 }}
</td>
<td style="padding: 0.5em 1em">
{{ prepaid_user_i.activated }}
</td>
<td style="padding: 0.5em 1em">
{{ prepaid_user_i.last_drink }}
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="7" style="text-align: center">
No users in prepaid database
</td>
</tr>
{% endif %}
</tbody>
</table>
{% endif %} {% endif %}
</main>
</body>

BIN
test.db

Binary file not shown.