import bcrypt from flask import Blueprint, render_template, redirect, url_for, flash, request from flask_login import login_user, logout_user, login_required, current_user from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired, Email, Length, EqualTo, ValidationError from models import db, User auth_bp = Blueprint("auth", __name__, url_prefix="/auth") class RegisterForm(FlaskForm): username = StringField("Username", validators=[DataRequired(), Length(3, 64)]) email = StringField("Email", validators=[DataRequired(), Email(), Length(max=120)]) password = PasswordField("Password", validators=[DataRequired(), Length(min=8)]) confirm = PasswordField("Confirm Password", validators=[DataRequired(), EqualTo("password")]) submit = SubmitField("Register") def validate_username(self, field): if User.query.filter_by(username=field.data).first(): raise ValidationError("Username already taken.") def validate_email(self, field): if User.query.filter_by(email=field.data).first(): raise ValidationError("Email already registered.") class LoginForm(FlaskForm): email = StringField("Email", validators=[DataRequired(), Email()]) password = PasswordField("Password", validators=[DataRequired()]) submit = SubmitField("Login") @auth_bp.route("/register", methods=["GET", "POST"]) def register(): if current_user.is_authenticated: return redirect(url_for("main.index")) form = RegisterForm() if form.validate_on_submit(): pw_hash = bcrypt.hashpw(form.password.data.encode(), bcrypt.gensalt()).decode() user = User(username=form.username.data, email=form.email.data, password_hash=pw_hash) db.session.add(user) db.session.commit() flash("Account created. Please log in.", "success") return redirect(url_for("auth.login")) return render_template("register.html", form=form) @auth_bp.route("/login", methods=["GET", "POST"]) def login(): if current_user.is_authenticated: return redirect(url_for("main.index")) form = LoginForm() if form.validate_on_submit(): user = User.query.filter_by(email=form.email.data).first() if user and bcrypt.checkpw(form.password.data.encode(), user.password_hash.encode()): login_user(user) next_page = request.args.get("next") return redirect(next_page or url_for("main.index")) flash("Invalid email or password.", "danger") return render_template("login.html", form=form) @auth_bp.route("/logout") @login_required def logout(): logout_user() return redirect(url_for("auth.login"))