init
This commit is contained in:
276
routes/auth.py
Normal file
276
routes/auth.py
Normal file
@@ -0,0 +1,276 @@
|
||||
from flask import Blueprint, request, jsonify, session
|
||||
from flask_login import login_user, logout_user, login_required, current_user
|
||||
from models import User, EmailVerification
|
||||
from models import db
|
||||
from utils.security import hash_password, verify_password, generate_verification_code, get_client_ip
|
||||
from utils.email import EmailService
|
||||
from datetime import datetime, timedelta
|
||||
import re
|
||||
|
||||
auth_bp = Blueprint('auth', __name__)
|
||||
|
||||
def validate_email(email):
|
||||
"""验证邮箱格式"""
|
||||
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
||||
return re.match(pattern, email) is not None
|
||||
|
||||
@auth_bp.route('/send-code', methods=['POST'])
|
||||
def send_verification_code():
|
||||
"""发送验证码"""
|
||||
data = request.get_json()
|
||||
email = data.get('email')
|
||||
purpose = data.get('purpose', 'register')
|
||||
|
||||
if not email or not validate_email(email):
|
||||
return jsonify({'success': False, 'message': '邮箱格式不正确'}), 400
|
||||
|
||||
# 检查用户是否已存在
|
||||
if purpose == 'register':
|
||||
if User.query.filter_by(email=email).first():
|
||||
return jsonify({'success': False, 'message': '该邮箱已被注册'}), 400
|
||||
elif purpose in ['reset_password', 'forgot_password']:
|
||||
if not User.query.filter_by(email=email).first():
|
||||
return jsonify({'success': False, 'message': '该邮箱未注册'}), 400
|
||||
|
||||
# 生成验证码
|
||||
code = generate_verification_code(6)
|
||||
expires_at = datetime.utcnow() + timedelta(minutes=10)
|
||||
|
||||
# 保存验证码
|
||||
verification = EmailVerification(
|
||||
email=email,
|
||||
code=code,
|
||||
purpose=purpose,
|
||||
expires_at=expires_at
|
||||
)
|
||||
db.session.add(verification)
|
||||
db.session.commit()
|
||||
|
||||
# 发送邮件
|
||||
try:
|
||||
EmailService.send_verification_code(email, code, purpose)
|
||||
return jsonify({'success': True, 'message': '验证码已发送'})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'message': str(e)}), 500
|
||||
|
||||
@auth_bp.route('/register', methods=['GET', 'POST'])
|
||||
def register():
|
||||
"""用户注册"""
|
||||
if request.method == 'GET':
|
||||
from flask import render_template
|
||||
return render_template('register.html')
|
||||
|
||||
data = request.get_json()
|
||||
username = data.get('username')
|
||||
email = data.get('email')
|
||||
password = data.get('password')
|
||||
code = data.get('code')
|
||||
|
||||
# 验证输入
|
||||
if not all([username, email, password, code]):
|
||||
return jsonify({'success': False, 'message': '请填写完整信息'}), 400
|
||||
|
||||
if not validate_email(email):
|
||||
return jsonify({'success': False, 'message': '邮箱格式不正确'}), 400
|
||||
|
||||
if len(password) < 6:
|
||||
return jsonify({'success': False, 'message': '密码长度至少6位'}), 400
|
||||
|
||||
# 检查用户名和邮箱是否已存在
|
||||
if User.query.filter_by(username=username).first():
|
||||
return jsonify({'success': False, 'message': '用户名已存在'}), 400
|
||||
|
||||
if User.query.filter_by(email=email).first():
|
||||
return jsonify({'success': False, 'message': '邮箱已被注册'}), 400
|
||||
|
||||
# 验证验证码
|
||||
verification = EmailVerification.query.filter_by(
|
||||
email=email,
|
||||
code=code,
|
||||
purpose='register',
|
||||
is_used=False
|
||||
).filter(EmailVerification.expires_at > datetime.utcnow()).first()
|
||||
|
||||
if not verification:
|
||||
return jsonify({'success': False, 'message': '验证码无效或已过期'}), 400
|
||||
|
||||
# 创建用户
|
||||
user = User(
|
||||
username=username,
|
||||
email=email,
|
||||
password=hash_password(password),
|
||||
register_ip=get_client_ip(request),
|
||||
group_id=2 # 默认普通用户
|
||||
)
|
||||
db.session.add(user)
|
||||
|
||||
# 标记验证码已使用
|
||||
verification.is_used = True
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({'success': True, 'message': '注册成功'})
|
||||
|
||||
@auth_bp.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
"""用户登录"""
|
||||
if request.method == 'GET':
|
||||
from flask import render_template
|
||||
return render_template('login.html')
|
||||
|
||||
data = request.get_json()
|
||||
email = data.get('email')
|
||||
password = data.get('password')
|
||||
|
||||
if not all([email, password]):
|
||||
return jsonify({'success': False, 'message': '请填写完整信息'}), 400
|
||||
|
||||
user = User.query.filter_by(email=email).first()
|
||||
|
||||
if not user or not verify_password(password, user.password):
|
||||
return jsonify({'success': False, 'message': '邮箱或密码错误'}), 401
|
||||
|
||||
if not user.is_active:
|
||||
return jsonify({'success': False, 'message': '账号已被禁用'}), 403
|
||||
|
||||
# 更新登录信息
|
||||
user.last_login_ip = get_client_ip(request)
|
||||
db.session.commit()
|
||||
|
||||
# 登录用户
|
||||
login_user(user)
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': '登录成功',
|
||||
'user': {
|
||||
'id': user.id,
|
||||
'username': user.username,
|
||||
'email': user.email
|
||||
}
|
||||
})
|
||||
|
||||
@auth_bp.route('/logout', methods=['POST'])
|
||||
@login_required
|
||||
def logout():
|
||||
"""用户登出"""
|
||||
logout_user()
|
||||
return jsonify({'success': True, 'message': '已退出登录'})
|
||||
|
||||
@auth_bp.route('/reset-password', methods=['POST'])
|
||||
def reset_password():
|
||||
"""重置密码"""
|
||||
data = request.get_json()
|
||||
email = data.get('email')
|
||||
code = data.get('code')
|
||||
new_password = data.get('new_password')
|
||||
|
||||
if not all([email, code, new_password]):
|
||||
return jsonify({'success': False, 'message': '请填写完整信息'}), 400
|
||||
|
||||
if len(new_password) < 6:
|
||||
return jsonify({'success': False, 'message': '密码长度至少6位'}), 400
|
||||
|
||||
# 验证验证码
|
||||
verification = EmailVerification.query.filter_by(
|
||||
email=email,
|
||||
code=code,
|
||||
is_used=False
|
||||
).filter(
|
||||
EmailVerification.purpose.in_(['reset_password', 'forgot_password'])
|
||||
).filter(EmailVerification.expires_at > datetime.utcnow()).first()
|
||||
|
||||
if not verification:
|
||||
return jsonify({'success': False, 'message': '验证码无效或已过期'}), 400
|
||||
|
||||
# 更新密码
|
||||
user = User.query.filter_by(email=email).first()
|
||||
if not user:
|
||||
return jsonify({'success': False, 'message': '用户不存在'}), 404
|
||||
|
||||
user.password = hash_password(new_password)
|
||||
verification.is_used = True
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({'success': True, 'message': '密码重置成功'})
|
||||
|
||||
@auth_bp.route('/user-info', methods=['GET'])
|
||||
@login_required
|
||||
def user_info():
|
||||
"""获取当前用户信息"""
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'user': {
|
||||
'id': current_user.id,
|
||||
'username': current_user.username,
|
||||
'email': current_user.email,
|
||||
'group_id': current_user.group_id,
|
||||
'total_parse_count': current_user.total_parse_count
|
||||
}
|
||||
})
|
||||
|
||||
@auth_bp.route('/profile', methods=['GET'])
|
||||
@login_required
|
||||
def profile():
|
||||
"""用户个人中心页面"""
|
||||
from flask import render_template
|
||||
return render_template('profile.html')
|
||||
|
||||
@auth_bp.route('/api/profile', methods=['GET'])
|
||||
@login_required
|
||||
def get_profile():
|
||||
"""获取用户个人中心数据"""
|
||||
from models import UserGroup, DailyParseStat, ParseLog
|
||||
from datetime import date
|
||||
|
||||
# 获取用户组信息
|
||||
user_group = UserGroup.query.get(current_user.group_id)
|
||||
daily_limit = user_group.daily_limit if user_group else 10
|
||||
group_name = user_group.name if user_group else '普通用户'
|
||||
|
||||
# 获取今日使用次数
|
||||
today = date.today()
|
||||
today_stat = DailyParseStat.query.filter_by(
|
||||
user_id=current_user.id,
|
||||
date=today
|
||||
).first()
|
||||
|
||||
today_used = today_stat.parse_count if today_stat else 0
|
||||
today_remaining = max(0, daily_limit - today_used)
|
||||
|
||||
# 获取解析记录(最近20条)
|
||||
parse_logs = ParseLog.query.filter_by(
|
||||
user_id=current_user.id
|
||||
).order_by(ParseLog.created_at.desc()).limit(20).all()
|
||||
|
||||
logs_data = [{
|
||||
'id': log.id,
|
||||
'platform': log.platform,
|
||||
'video_url': log.video_url[:50] + '...' if len(log.video_url) > 50 else log.video_url,
|
||||
'status': log.status,
|
||||
'response_time': log.response_time,
|
||||
'created_at': log.created_at.strftime('%Y-%m-%d %H:%M:%S') if log.created_at else ''
|
||||
} for log in parse_logs]
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'data': {
|
||||
'user': {
|
||||
'id': current_user.id,
|
||||
'username': current_user.username,
|
||||
'email': current_user.email,
|
||||
'created_at': current_user.created_at.strftime('%Y-%m-%d') if current_user.created_at else ''
|
||||
},
|
||||
'group': {
|
||||
'id': current_user.group_id,
|
||||
'name': group_name,
|
||||
'daily_limit': daily_limit
|
||||
},
|
||||
'usage': {
|
||||
'daily_limit': daily_limit,
|
||||
'today_used': today_used,
|
||||
'today_remaining': today_remaining,
|
||||
'total_parse_count': current_user.total_parse_count or 0
|
||||
},
|
||||
'parse_logs': logs_data
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user