"""Authentication blueprint — login, register, logout.""" from flask import Blueprint, request, render_template, redirect, url_for, session, flash from werkzeug.security import generate_password_hash, check_password_hash from models import ( get_user_by_username, create_user, create_household, get_household_by_name, get_household_by_id, get_all_households, count_household_users, ) auth_bp = Blueprint("auth", __name__) @auth_bp.route("/login", methods=["GET", "POST"]) def login(): if request.method == "POST": username = request.form.get("username", "").strip() password = request.form.get("password", "") if not username or not password: flash("Username and password are required.", "error") return render_template("login.html") user = get_user_by_username(username) if user is None or not check_password_hash(user["password_hash"], password): flash("Invalid username or password.", "error") return render_template("login.html") household_id = user["household_id"] household = get_household_by_id(household_id) if household_id else None session.clear() session["user_id"] = user["id"] session["username"] = user["username"] session["is_admin"] = bool(user["is_admin"]) session["household_id"] = household_id session["household_name"] = household["name"] if household else "Unknown" return redirect(url_for("meals.dashboard")) return render_template("login.html") @auth_bp.route("/register", methods=["GET", "POST"]) def register(): households = get_all_households() if request.method == "POST": username = request.form.get("username", "").strip() password = request.form.get("password", "") confirm = request.form.get("confirm", "") household_action = request.form.get("household_action", "join") # "join" or "create" household_id = request.form.get("household_id", "").strip() new_household_name = request.form.get("new_household_name", "").strip() errors = [] if not username or len(username) < 2: errors.append("Username must be at least 2 characters.") if not password or len(password) < 4: errors.append("Password must be at least 4 characters.") if password != confirm: errors.append("Passwords do not match.") if get_user_by_username(username): errors.append("Username already taken.") target_household_id = None if household_action == "create": if not new_household_name: errors.append("Household name is required.") elif get_household_by_name(new_household_name): errors.append("A household with that name already exists.") else: household = create_household(new_household_name) target_household_id = household["id"] is_admin = True # First user in a new household is admin else: if not household_id: errors.append("Please select a household.") else: hh = get_household_by_id(int(household_id)) if hh is None: errors.append("Selected household does not exist.") else: target_household_id = hh["id"] is_admin = False if errors: for e in errors: flash(e, "error") return render_template("register.html", households=households) password_hash = generate_password_hash(password) user = create_user(username, password_hash, target_household_id, is_admin=is_admin) session.clear() session["user_id"] = user["id"] session["username"] = user["username"] session["is_admin"] = bool(user["is_admin"]) session["household_id"] = user["household_id"] session["household_name"] = get_household_by_id(target_household_id)["name"] flash("Account created! Welcome to your household.", "success") return redirect(url_for("meals.dashboard")) return render_template("register.html", households=households) @auth_bp.route("/logout") def logout(): session.clear() return redirect(url_for("auth.login"))