初始提交: Qihu-AIFlow v2.0.1 完整项目

- 前端 React+TypeScript (源码+构建产物)
- 后端 Python FastAPI
- 数据库迁移 001-015
- Docker部署配置
- 微信ClawBot API频道绑定
- 项目文档 README.md
This commit is contained in:
qyyfw committed 2026-07-02 14:40:46 +08:00
commit 78ff261b5a
199 files changed
+69126

No files matched your search

+231
View File
@@ -0,0 +1,231 @@
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import and_
from pydantic import BaseModel, Field
from typing import Optional
import uuid
from datetime import datetime
from ..database import get_db
from ..models import (
User, LoginLog, RegisterSetting,
gen_uuid
)
from ..auth import get_current_user, hash_password, verify_password, create_access_token
from ..middleware.log_service import LogService
router = APIRouter()
class LoginRequest(BaseModel):
username: str
password: str
class RegisterRequest(BaseModel):
username: str = Field(min_length=3, max_length=50)
password: str = Field(min_length=6, max_length=100)
email: Optional[str] = None
phone: Optional[str] = None
@router.post("/login")
def login(req: LoginRequest, db: Session = Depends(get_db)):
import logging
logger = logging.getLogger(__name__)
user = db.query(User).filter(User.username == req.username).first()
if not user:
logger.warning(f"登录失败: 用户 '{req.username}' 不存在")
raise HTTPException(status_code=401, detail="用户名不存在")
stored_hash = user.password_hash
logger.info(f"登录调试: username={req.username} hash_prefix={stored_hash[:7] if stored_hash else 'None'} hash_len={len(stored_hash) if stored_hash else 0}")
if not verify_password(req.password, user.password_hash):
logger.warning(f"登录失败: 用户 '{req.username}' 密码验证失败 hash_prefix={stored_hash[:7] if stored_hash else 'None'} hash_len={len(stored_hash) if stored_hash else 0}")
raise HTTPException(status_code=401, detail="密码错误")
if user.status == "banned":
raise HTTPException(status_code=403, detail="账号已被封禁")
token_data = {"sub": user.id, "username": user.username, "role": user.role}
access_token = create_access_token(token_data)
# 记录登录日志
login_log = LoginLog(
id=gen_uuid(),
user_id=user.id,
ip="",
login_at=datetime.now(),
)
db.add(login_log)
# 记录操作日志
LogService.log_operation(
user_id=user.id,
username=user.username,
action="login",
target="user",
detail=f"用户 {user.username} 登录成功",
)
db.commit()
return {
"code": 0,
"data": {
"access_token": access_token,
"token_type": "bearer",
"user": {
"id": user.id,
"username": user.username,
"email": user.email,
"phone": user.phone,
"avatar": user.avatar,
"role": user.role,
"status": user.status,
"membership_level": user.membership_level,
"membership_expire_at": str(user.membership_expire_at) if user.membership_expire_at else None,
"created_at": str(user.created_at) if user.created_at else None,
},
},
"message": "登录成功",
}
@router.post("/register")
def register(req: RegisterRequest, db: Session = Depends(get_db)):
# 检查注册设置
reg_setting = db.query(RegisterSetting).first()
if reg_setting and reg_setting.phone_required and not req.phone:
raise HTTPException(status_code=400, detail="手机号为必填项")
if reg_setting and reg_setting.email_required and not req.email:
raise HTTPException(status_code=400, detail="邮箱为必填项")
# 检查用户名是否已存在
existing = db.query(User).filter(User.username == req.username).first()
if existing:
raise HTTPException(status_code=400, detail="用户名已存在")
if req.email:
existing_email = db.query(User).filter(User.email == req.email).first()
if existing_email:
raise HTTPException(status_code=400, detail="邮箱已被注册")
if req.phone:
existing_phone = db.query(User).filter(User.phone == req.phone).first()
if existing_phone:
raise HTTPException(status_code=400, detail="手机号已被注册")
user = User(
id=gen_uuid(),
username=req.username,
password_hash=hash_password(req.password),
email=req.email,
phone=req.phone,
avatar=None,
role="user",
status="active",
real_name_status="unverified",
membership_level=0,
created_at=datetime.now(),
updated_at=datetime.now(),
)
db.add(user)
db.flush()
# 创建Token余额记录
from ..models import TokenBalance
balance = TokenBalance(
id=gen_uuid(),
user_id=user.id,
total_consumed=0,
balance=0,
daily_free_used=0,
)
db.add(balance)
token_data = {"sub": user.id, "username": user.username, "role": user.role}
access_token = create_access_token(token_data)
LogService.log_operation(
user_id=user.id,
username=user.username,
action="register",
target="user",
detail=f"新用户 {user.username} 注册成功",
)
db.commit()
return {
"code": 0,
"data": {
"access_token": access_token,
"token_type": "bearer",
"user": {
"id": user.id,
"username": user.username,
"email": user.email or "",
"phone": user.phone or "",
"avatar": user.avatar or "",
"role": user.role,
"status": user.status,
"membership_level": user.membership_level,
"created_at": str(user.created_at) if user.created_at else None,
},
},
"message": "注册成功",
}
@router.get("/me")
def get_me(current_user: User = Depends(get_current_user)):
return {
"code": 0,
"data": {
"id": current_user.id,
"username": current_user.username,
"email": current_user.email or "",
"phone": current_user.phone or "",
"avatar": current_user.avatar or "",
"role": current_user.role,
"status": current_user.status,
"real_name_status": current_user.real_name_status,
"membership_level": current_user.membership_level,
"membership_expire_at": str(current_user.membership_expire_at) if current_user.membership_expire_at else None,
"auto_renew": current_user.auto_renew,
"created_at": str(current_user.created_at) if current_user.created_at else None,
},
"message": "ok",
}
@router.post("/logout")
def logout(current_user: User = Depends(get_current_user)):
LogService.log_operation(
user_id=current_user.id,
username=current_user.username,
action="logout",
target="user",
detail=f"用户 {current_user.username} 登出",
)
return {"code": 0, "message": "登出成功"}
@router.get("/settings")
def get_settings(db: Session = Depends(get_db)):
settings = db.query(RegisterSetting).first()
if not settings:
return {"code": 0, "data": {}, "message": "ok"}
return {
"code": 0,
"data": {
"phone_required": settings.phone_required,
"phone_sms_required": settings.phone_sms_required,
"email_required": settings.email_required,
"email_verify_required": settings.email_verify_required,
"real_name_required": settings.real_name_required,
},
"message": "ok",
}