180 lines
7.0 KiB
Python
180 lines
7.0 KiB
Python
from flask import Blueprint, render_template, request, redirect, url_for, flash, session
|
||
from flask_login import login_user, logout_user, login_required, current_user
|
||
from werkzeug.security import check_password_hash, generate_password_hash
|
||
from app.models import db, User, Student
|
||
from app.utils.database import safe_commit
|
||
from datetime import datetime
|
||
import re
|
||
|
||
auth_bp = Blueprint('auth', __name__)
|
||
|
||
|
||
@auth_bp.route('/login', methods=['GET', 'POST'])
|
||
def login():
|
||
if current_user.is_authenticated:
|
||
if current_user.is_admin():
|
||
return redirect(url_for('admin.dashboard'))
|
||
else:
|
||
return redirect(url_for('student.dashboard'))
|
||
|
||
if request.method == 'POST':
|
||
student_number = request.form.get('student_number', '').strip()
|
||
password = request.form.get('password', '')
|
||
remember = request.form.get('remember', False)
|
||
|
||
if not student_number or not password:
|
||
flash('请输入学号和密码', 'error')
|
||
return render_template('auth/login.html')
|
||
|
||
# 查找用户
|
||
user = User.query.filter_by(student_number=student_number).first()
|
||
|
||
if user and user.check_password(password):
|
||
if not user.is_active:
|
||
flash('账户已被禁用,请联系管理员', 'error')
|
||
return render_template('auth/login.html')
|
||
|
||
# 更新最后登录时间
|
||
user.last_login = datetime.utcnow()
|
||
success, error = safe_commit()
|
||
|
||
if not success:
|
||
flash('系统错误,请稍后重试', 'error')
|
||
return render_template('auth/login.html')
|
||
|
||
login_user(user, remember=remember)
|
||
|
||
# 获取重定向地址
|
||
next_page = request.args.get('next')
|
||
if next_page:
|
||
return redirect(next_page)
|
||
|
||
# 根据用户角色重定向
|
||
if user.is_admin():
|
||
flash(f'欢迎回来,管理员!', 'success')
|
||
return redirect(url_for('admin.dashboard'))
|
||
else:
|
||
# 获取学生姓名
|
||
student = Student.query.filter_by(student_number=student_number).first()
|
||
name = student.name if student else student_number
|
||
flash(f'欢迎回来,{name}!', 'success')
|
||
return redirect(url_for('student.dashboard'))
|
||
else:
|
||
flash('学号或密码错误', 'error')
|
||
|
||
return render_template('auth/login.html')
|
||
|
||
|
||
@auth_bp.route('/logout')
|
||
@login_required
|
||
def logout():
|
||
logout_user()
|
||
flash('您已成功退出登录', 'info')
|
||
return redirect(url_for('auth.login'))
|
||
|
||
|
||
@auth_bp.route('/change_password', methods=['GET', 'POST'])
|
||
@login_required
|
||
def change_password():
|
||
if request.method == 'POST':
|
||
current_password = request.form.get('current_password', '')
|
||
new_password = request.form.get('new_password', '')
|
||
confirm_password = request.form.get('confirm_password', '')
|
||
|
||
# 验证输入
|
||
if not all([current_password, new_password, confirm_password]):
|
||
flash('请填写所有密码字段', 'error')
|
||
return render_template('auth/change_password.html')
|
||
|
||
# 验证当前密码
|
||
if not current_user.check_password(current_password):
|
||
flash('当前密码不正确', 'error')
|
||
return render_template('auth/change_password.html')
|
||
|
||
# 验证新密码与确认密码是否一致
|
||
if new_password != confirm_password:
|
||
flash('新密码与确认密码不匹配', 'error')
|
||
return render_template('auth/change_password.html')
|
||
|
||
# 密码长度验证
|
||
if len(new_password) < 6:
|
||
flash('新密码长度至少6位', 'error')
|
||
return render_template('auth/change_password.html')
|
||
|
||
# 密码复杂度验证(可选)
|
||
if not re.search(r'^(?=.*[a-zA-Z])(?=.*\d).+$', new_password):
|
||
flash('新密码必须包含字母和数字', 'error')
|
||
return render_template('auth/change_password.html')
|
||
|
||
# 检查新密码是否与当前密码相同
|
||
if current_user.check_password(new_password):
|
||
flash('新密码不能与当前密码相同', 'error')
|
||
return render_template('auth/change_password.html')
|
||
|
||
try:
|
||
# 更新密码
|
||
current_user.set_password(new_password)
|
||
success, error = safe_commit()
|
||
|
||
if success:
|
||
flash('密码修改成功', 'success')
|
||
# 根据用户角色重定向
|
||
if current_user.is_admin():
|
||
return redirect(url_for('auth.profile'))
|
||
else:
|
||
return redirect(url_for('auth.profile'))
|
||
else:
|
||
flash(f'密码修改失败: {error}', 'error')
|
||
|
||
except Exception as e:
|
||
flash(f'密码修改失败: {str(e)}', 'error')
|
||
|
||
return render_template('auth/change_password.html')
|
||
|
||
|
||
@auth_bp.route('/profile')
|
||
@login_required
|
||
def profile():
|
||
"""用户个人信息页面"""
|
||
try:
|
||
if current_user.is_admin():
|
||
# 管理员信息页面
|
||
user_info = {
|
||
'user_id': current_user.user_id,
|
||
'student_number': current_user.student_number,
|
||
'role': current_user.role,
|
||
'is_active': current_user.is_active,
|
||
'last_login': current_user.last_login,
|
||
'created_at': current_user.created_at
|
||
}
|
||
return render_template('auth/admin_profile.html', user_info=user_info)
|
||
else:
|
||
# 学生信息页面
|
||
student = Student.query.filter_by(student_number=current_user.student_number).first()
|
||
user_info = {
|
||
'user_id': current_user.user_id,
|
||
'student_number': current_user.student_number,
|
||
'role': current_user.role,
|
||
'is_active': current_user.is_active,
|
||
'last_login': current_user.last_login,
|
||
'created_at': current_user.created_at,
|
||
# 学生特有信息
|
||
'name': student.name if student else None,
|
||
'gender': student.gender if student else None,
|
||
'grade': student.grade if student else None,
|
||
'phone': student.phone if student else None,
|
||
'supervisor': student.supervisor if student else None,
|
||
'college': student.college if student else None,
|
||
'major': student.major if student else None,
|
||
'degree_type': student.degree_type if student else None,
|
||
'status': student.status if student else None,
|
||
'enrollment_date': student.enrollment_date if student else None
|
||
}
|
||
return render_template('auth/student_profile.html', user_info=user_info, student=student)
|
||
except Exception as e:
|
||
flash(f'获取个人信息失败: {str(e)}', 'error')
|
||
if current_user.is_admin():
|
||
return redirect(url_for('admin.dashboard'))
|
||
else:
|
||
return redirect(url_for('student.dashboard'))
|