95 lines
No EOL
3.5 KiB
Python
95 lines
No EOL
3.5 KiB
Python
"""
|
|
Forms for authentication and user management.
|
|
"""
|
|
from flask_wtf import FlaskForm
|
|
from wtforms import StringField, PasswordField, BooleanField, SubmitField
|
|
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
|
|
|
|
from app.models.user import User
|
|
|
|
|
|
class LoginForm(FlaskForm):
|
|
"""Form for user login."""
|
|
username = StringField("Username", validators=[DataRequired()])
|
|
password = PasswordField("Password", validators=[DataRequired()])
|
|
remember_me = BooleanField("Remember Me")
|
|
submit = SubmitField("Sign In")
|
|
|
|
|
|
class RegistrationForm(FlaskForm):
|
|
"""Form for user registration."""
|
|
username = StringField("Username", validators=[
|
|
DataRequired(),
|
|
Length(min=3, max=64)
|
|
])
|
|
email = StringField("Email", validators=[
|
|
DataRequired(),
|
|
Email(),
|
|
Length(max=120)
|
|
])
|
|
password = PasswordField("Password", validators=[
|
|
DataRequired(),
|
|
Length(min=8, message="Password must be at least 8 characters long")
|
|
])
|
|
password2 = PasswordField("Confirm Password", validators=[
|
|
DataRequired(),
|
|
EqualTo("password", message="Passwords must match")
|
|
])
|
|
submit = SubmitField("Register")
|
|
|
|
def validate_username(self, username):
|
|
"""Validate that the username is not already taken."""
|
|
user = User.query.filter_by(username=username.data).first()
|
|
if user is not None:
|
|
raise ValidationError("Username already taken. Please choose a different one.")
|
|
|
|
def validate_email(self, email):
|
|
"""Validate that the email is not already registered."""
|
|
user = User.query.filter_by(email=email.data).first()
|
|
if user is not None:
|
|
raise ValidationError("Email already registered. Please use a different email or reset your password.")
|
|
|
|
def validate_password(self, password):
|
|
"""Validate password complexity."""
|
|
pwd = password.data
|
|
|
|
# Check for minimum complexity
|
|
has_upper = any(c.isupper() for c in pwd)
|
|
has_lower = any(c.islower() for c in pwd)
|
|
has_digit = any(c.isdigit() for c in pwd)
|
|
has_special = any(not c.isalnum() for c in pwd)
|
|
|
|
if not (has_upper and has_lower and has_digit):
|
|
raise ValidationError("Password must contain uppercase, lowercase, and digit characters.")
|
|
|
|
|
|
class ResetPasswordRequestForm(FlaskForm):
|
|
"""Form to request a password reset."""
|
|
email = StringField("Email", validators=[DataRequired(), Email()])
|
|
submit = SubmitField("Request Password Reset")
|
|
|
|
|
|
class ResetPasswordForm(FlaskForm):
|
|
"""Form to reset password."""
|
|
password = PasswordField("New Password", validators=[
|
|
DataRequired(),
|
|
Length(min=8, message="Password must be at least 8 characters long")
|
|
])
|
|
password2 = PasswordField("Confirm New Password", validators=[
|
|
DataRequired(),
|
|
EqualTo("password", message="Passwords must match")
|
|
])
|
|
submit = SubmitField("Reset Password")
|
|
|
|
def validate_password(self, password):
|
|
"""Validate password complexity."""
|
|
pwd = password.data
|
|
|
|
# Check for minimum complexity
|
|
has_upper = any(c.isupper() for c in pwd)
|
|
has_lower = any(c.islower() for c in pwd)
|
|
has_digit = any(c.isdigit() for c in pwd)
|
|
has_special = any(not c.isalnum() for c in pwd)
|
|
|
|
if not (has_upper and has_lower and has_digit):
|
|
raise ValidationError("Password must contain uppercase, lowercase, and digit characters.") |