Restructure the app folder
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
from flask import Blueprint, render_template, redirect, url_for, request, flash, current_app
|
||||
from flask_login import login_user, logout_user, login_required, current_user
|
||||
from app.forms import LoginForm, RegistrationForm, RequestPasswordResetForm, ResetPasswordForm
|
||||
from app import create_app, db
|
||||
from app import limiter
|
||||
from datetime import datetime, timezone
|
||||
from app.config import ALLOWED_EMAILS
|
||||
import logging
|
||||
from flask_mail import Message
|
||||
from app import mail
|
||||
from app.models import User
|
||||
|
||||
bp = Blueprint('auth', __name__)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@bp.route('/login', methods=['GET', 'POST'])
|
||||
@limiter.limit("5 per minute")
|
||||
def login():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('main.calculator'))
|
||||
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
email = form.email.data.strip().lower()
|
||||
password = form.password.data
|
||||
|
||||
# Log the login attempt
|
||||
current_app.logger.info(f'Login attempt for email: {email}')
|
||||
|
||||
user = User.authenticate(email, password)
|
||||
if user:
|
||||
login_user(user, remember=form.remember_me.data)
|
||||
user.last_login = datetime.now(timezone.utc)
|
||||
db.session.commit()
|
||||
current_app.logger.info(f'User {user.email} logged in successfully')
|
||||
next_page = request.args.get('next') or url_for('main.calculator')
|
||||
return redirect(next_page)
|
||||
else:
|
||||
current_app.logger.warning(f'Failed login attempt for email: {email}')
|
||||
flash('Invalid email or password', 'danger')
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'Login error: {str(e)}', exc_info=True)
|
||||
flash('An error occurred during login. Please try again.', 'danger')
|
||||
|
||||
return render_template('auth/login.html', form=form)
|
||||
|
||||
@bp.route('/register', methods=['GET', 'POST'])
|
||||
@limiter.limit(lambda: None if current_app.config.get('DEBUG', False) else "10 per hour")
|
||||
def register():
|
||||
try:
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('main.home'))
|
||||
|
||||
form = RegistrationForm()
|
||||
logger.info('Registration form initialized')
|
||||
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
email = form.email.data.strip().lower()
|
||||
username = form.username.data.strip().lower()
|
||||
company = form.company.data.strip().upper()
|
||||
logger.info(f'Processing registration for email: {email}, username: {username}, company: {company}')
|
||||
|
||||
# Check if email is in allowed list or has adidas.com domain
|
||||
if email not in ALLOWED_EMAILS and not email.endswith('@adidas.com'):
|
||||
logger.warning(f'Registration attempt with non-allowed email: {email}')
|
||||
flash('Registration is not allowed for this email domain', 'danger')
|
||||
return render_template('auth/register.html', form=form)
|
||||
|
||||
try:
|
||||
logger.info('Creating new user...')
|
||||
user = User.create(
|
||||
username=username,
|
||||
email=email,
|
||||
company=company,
|
||||
password=form.password.data
|
||||
)
|
||||
logger.info('User created, committing to database...')
|
||||
db.session.commit()
|
||||
logger.info(f'New user registered successfully: {user.email}')
|
||||
flash('Registration successful! Please login', 'success')
|
||||
return redirect(url_for('auth.login'))
|
||||
except ValueError as e:
|
||||
logger.warning(f'Registration validation error: {str(e)}')
|
||||
flash(str(e), 'danger')
|
||||
except Exception as e:
|
||||
db.session.rollback()
|
||||
logger.error(f'Registration error: {str(e)}', exc_info=True)
|
||||
flash('An error occurred during registration', 'danger')
|
||||
except Exception as e:
|
||||
logger.error(f'Unexpected error during registration: {str(e)}', exc_info=True)
|
||||
flash('An unexpected error occurred', 'danger')
|
||||
elif form.errors:
|
||||
logger.warning(f'Form validation errors: {form.errors}')
|
||||
for field, errors in form.errors.items():
|
||||
for error in errors:
|
||||
flash(f'{field}: {error}', 'danger')
|
||||
logger.warning(f'Field {field} validation error: {error}')
|
||||
|
||||
logger.info('Rendering registration template')
|
||||
return render_template('auth/register.html', form=form)
|
||||
except Exception as e:
|
||||
logger.error(f'Critical error in registration route: {str(e)}', exc_info=True)
|
||||
flash('A critical error occurred', 'danger')
|
||||
return render_template('auth/register.html', form=form)
|
||||
|
||||
@bp.route('/logout')
|
||||
@login_required
|
||||
def logout():
|
||||
current_app.logger.info(f'User {current_user.email} logged out')
|
||||
logout_user()
|
||||
flash('You have been logged out.', 'info')
|
||||
return redirect(url_for('main.home'))
|
||||
|
||||
@bp.route('/request-reset', methods=['GET', 'POST'])
|
||||
@limiter.limit("3 per hour")
|
||||
def request_reset():
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('main.calculator'))
|
||||
|
||||
form = RequestPasswordResetForm()
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
email = form.email.data.strip().lower()
|
||||
user = User.query.filter_by(email=email).first()
|
||||
|
||||
if user:
|
||||
token = user.generate_reset_token()
|
||||
db.session.commit()
|
||||
|
||||
reset_url = url_for('auth.reset_password', token=token, _external=True)
|
||||
flash(f'Your password reset link is: {reset_url}', 'info')
|
||||
flash('This link will expire in 15 minutes.', 'warning')
|
||||
return redirect(url_for('auth.login'))
|
||||
|
||||
# Always show success message to prevent email enumeration
|
||||
flash('If an account exists with that email, you will receive password reset instructions.', 'info')
|
||||
return redirect(url_for('auth.login'))
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'Error generating reset token: {str(e)}', exc_info=True)
|
||||
flash('An error occurred while processing your request.', 'danger')
|
||||
|
||||
return render_template('auth/request_reset.html', form=form)
|
||||
|
||||
@bp.route('/reset-password/<token>', methods=['GET', 'POST'])
|
||||
@limiter.limit("3 per hour")
|
||||
def reset_password(token):
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('main.calculator'))
|
||||
|
||||
form = ResetPasswordForm()
|
||||
if form.validate_on_submit():
|
||||
try:
|
||||
user = User.query.filter_by(reset_token=token).first()
|
||||
if not user or not user.verify_reset_token(token):
|
||||
flash('The password reset link is invalid or has expired.', 'danger')
|
||||
return redirect(url_for('auth.request_reset'))
|
||||
|
||||
user.set_password(form.password.data)
|
||||
db.session.commit()
|
||||
current_app.logger.info(f'Password reset successful for user {user.email}')
|
||||
flash('Your password has been reset. You can now log in.', 'success')
|
||||
return redirect(url_for('auth.login'))
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.error(f'Error resetting password: {str(e)}', exc_info=True)
|
||||
flash('An error occurred while resetting your password.', 'danger')
|
||||
|
||||
return render_template('auth/reset_password.html', form=form)
|
||||
Reference in New Issue
Block a user