Files
Code_of_Conquest/public_web/app/views/auth_views.py

194 lines
5.7 KiB
Python

"""
Auth Views Blueprint
This module provides web UI routes for authentication:
- Login page
- Registration page
- Password reset pages
- Email verification
All forms use HTMX to submit to the API endpoints.
"""
from flask import Blueprint, render_template, redirect, url_for, request, session
from app.utils.auth import get_current_user, clear_user_session
from app.utils.logging import get_logger
from app.utils.api_client import get_api_client, APIError
# Initialize logger
logger = get_logger(__file__)
# Create blueprint
auth_bp = Blueprint('auth_views', __name__)
@auth_bp.route('/')
def index():
"""
Landing page / home page.
If user is authenticated, redirect to character list.
Otherwise, redirect to login page.
"""
user = get_current_user()
if user:
logger.info("Authenticated user accessing home, redirecting to characters", user_id=user.get('id'))
return redirect(url_for('character_views.list_characters'))
logger.info("Unauthenticated user accessing home, redirecting to login")
return redirect(url_for('auth_views.login'))
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
"""
Display login page and handle login.
GET: If user is already authenticated, redirect to character list.
POST: Authenticate via API and set session.
"""
user = get_current_user()
if user:
logger.info("User already authenticated, redirecting to characters", user_id=user.get('id'))
return redirect(url_for('character_views.list_characters'))
if request.method == 'POST':
# Get form data
email = request.form.get('email', '').strip()
password = request.form.get('password', '')
if not email or not password:
return render_template('auth/login.html', error="Email and password are required")
# Call API to authenticate
try:
api_client = get_api_client()
response = api_client.post("/api/v1/auth/login", data={
'email': email,
'password': password
})
# Store user in session
if response.get('result') and response['result'].get('user'):
session['user'] = response['result']['user']
logger.info("User logged in successfully", user_id=response['result']['user'].get('id'))
# Redirect to next page or character list
next_url = session.pop('next', None)
if next_url:
return redirect(next_url)
return redirect(url_for('character_views.list_characters'))
except APIError as e:
logger.warning("Login failed", error=str(e))
return render_template('auth/login.html', error=e.message)
logger.info("Rendering login page")
return render_template('auth/login.html')
@auth_bp.route('/register')
def register():
"""
Display registration page.
If user is already authenticated, redirect to character list.
"""
user = get_current_user()
if user:
logger.info("User already authenticated, redirecting to characters", user_id=user.get('id'))
return redirect(url_for('character_views.list_characters'))
logger.info("Rendering registration page")
return render_template('auth/register.html')
@auth_bp.route('/forgot-password')
def forgot_password():
"""
Display forgot password page.
Allows users to request a password reset email.
"""
logger.info("Rendering forgot password page")
return render_template('auth/forgot_password.html')
@auth_bp.route('/reset-password')
def reset_password():
"""
Display password reset page.
This page is accessed via a link in the password reset email.
The reset token should be in the query parameters.
"""
# Get reset token from query parameters
token = request.args.get('token')
user_id = request.args.get('userId')
secret = request.args.get('secret')
if not all([token, user_id, secret]):
logger.warning("Reset password accessed without required parameters")
# Could redirect to forgot-password with an error message
return redirect(url_for('auth_views.forgot_password'))
logger.info("Rendering password reset page", user_id=user_id)
return render_template(
'auth/reset_password.html',
token=token,
user_id=user_id,
secret=secret
)
@auth_bp.route('/verify-email')
def verify_email():
"""
Display email verification page.
This page is accessed via a link in the verification email.
The verification token should be in the query parameters.
"""
# Get verification token from query parameters
token = request.args.get('token')
user_id = request.args.get('userId')
secret = request.args.get('secret')
if not all([token, user_id, secret]):
logger.warning("Email verification accessed without required parameters")
return redirect(url_for('auth_views.login'))
logger.info("Rendering email verification page", user_id=user_id)
return render_template(
'auth/verify_email.html',
token=token,
user_id=user_id,
secret=secret
)
@auth_bp.route('/logout', methods=['POST'])
def logout():
"""
Handle logout by calling API and clearing session.
This is a convenience route for non-HTMX logout forms.
"""
logger.info("Logout initiated via web form")
# Call API to logout (this will invalidate session cookie)
try:
api_client = get_api_client()
api_client.post("/api/v1/auth/logout")
except APIError as e:
logger.error("Failed to call logout API", error=str(e))
# Clear local session
clear_user_session()
return redirect(url_for('auth_views.login'))