Add account deletion, admin user removal, household deletion, grayed-out other-user chips (47 tests)

This commit is contained in:
agentbox
2026-07-31 22:12:13 +00:00
parent 53a1ceab75
commit 188aaf66a0
5 changed files with 272 additions and 8 deletions
+90 -1
View File
@@ -12,7 +12,17 @@ from flask import (
flash,
)
from models import get_dashboard_data, upsert_response, ensure_meal_periods
from werkzeug.security import check_password_hash
from models import (
get_dashboard_data,
upsert_response,
ensure_meal_periods,
get_user_by_id,
delete_user,
delete_household,
count_household_users,
)
meals_bp = Blueprint("meals", __name__)
@@ -64,6 +74,8 @@ def dashboard():
today=date.today(),
prev_date=today - timedelta(days=1),
next_date=today + timedelta(days=1),
current_user_id=session["user_id"],
is_admin=session["is_admin"],
)
@@ -119,5 +131,82 @@ def history():
today=date.today(),
prev_date=target_date - timedelta(days=1),
next_date=target_date + timedelta(days=1),
current_user_id=session["user_id"],
is_admin=session["is_admin"],
history_mode=True,
)
# ── Account / household management ────────────────────────────────────────────
@meals_bp.route("/delete-account", methods=["POST"])
@login_required
def delete_account():
"""Delete the currently logged-in user's own account."""
password = request.form.get("password", "")
user = get_user_by_id(session["user_id"])
if not check_password_hash(user["password_hash"], password):
flash("Incorrect password. Account not deleted.", "error")
return redirect(url_for("meals.dashboard"))
household_id = session["household_id"]
is_admin = session["is_admin"]
user_count = count_household_users(household_id)
# If admin is the last user, delete the household too
if is_admin and user_count == 1:
delete_household(household_id)
flash("Your account and household have been deleted.", "success")
else:
delete_user(session["user_id"])
flash("Your account has been deleted.", "success")
# Clear auth keys but keep the session so flash survives the redirect
for key in ("user_id", "username", "is_admin", "household_id", "household_name"):
session.pop(key, None)
return redirect(url_for("auth.login"))
@meals_bp.route("/admin/remove-user/<int:user_id>", methods=["POST"])
@login_required
def admin_remove_user(user_id):
"""Admin removes a user from the household."""
if not session["is_admin"]:
flash("Only admins can remove users.", "error")
return redirect(url_for("meals.dashboard"))
user = get_user_by_id(user_id)
if user is None or user["household_id"] != session["household_id"]:
flash("User not found in your household.", "error")
return redirect(url_for("meals.dashboard"))
if user["is_admin"]:
flash("Cannot remove the admin. Transfer admin role first or delete the household.", "error")
return redirect(url_for("meals.dashboard"))
delete_user(user_id)
flash(f"User '{user['username']}' has been removed.", "success")
return redirect(url_for("meals.dashboard"))
@meals_bp.route("/admin/delete-household", methods=["POST"])
@login_required
def admin_delete_household():
"""Admin deletes the entire household."""
if not session["is_admin"]:
flash("Only admins can delete the household.", "error")
return redirect(url_for("meals.dashboard"))
password = request.form.get("password", "")
user = get_user_by_id(session["user_id"])
if not check_password_hash(user["password_hash"], password):
flash("Incorrect password. Household not deleted.", "error")
return redirect(url_for("meals.dashboard"))
delete_household(session["household_id"])
flash("Household and all members have been deleted.", "success")
for key in ("user_id", "username", "is_admin", "household_id", "household_name"):
session.pop(key, None)
return redirect(url_for("auth.login"))