156 lines
5.7 KiB
Python
156 lines
5.7 KiB
Python
from fastapi import APIRouter, Cookie, HTTPException, Request
|
|
from fastapi.responses import JSONResponse
|
|
|
|
from app.db import auth_db
|
|
from app.web.shared import (
|
|
ChangePasswordRequest,
|
|
CompleteRegistrationRequest,
|
|
LoginRequest,
|
|
RegisterRequest,
|
|
ResendVerificationRequest,
|
|
SendCodeRequest,
|
|
VerifyEmailRequest,
|
|
auth_error,
|
|
require_user,
|
|
)
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post("/api/auth/register")
|
|
async def api_auth_register(req: RegisterRequest):
|
|
try:
|
|
result = auth_db.register_user(req.email, req.password, req.invite_code)
|
|
smtp_ready = auth_db.is_smtp_configured()
|
|
return {
|
|
"ok": True,
|
|
"user": {k: v for k, v in result.items() if k not in ("verification_code", "user_id")},
|
|
"dev_verification_code": None if smtp_ready else result.get("verification_code"),
|
|
"email_sent": bool(result.get("email_sent")),
|
|
"message": "注册成功,请查收邮箱验证码" if smtp_ready else "注册成功,请完成邮箱验证码验证",
|
|
}
|
|
except auth_db.AuthError as exc:
|
|
auth_error(exc)
|
|
|
|
|
|
@router.post("/api/auth/send-code")
|
|
async def api_auth_send_code(req: SendCodeRequest):
|
|
try:
|
|
result = auth_db.send_registration_code(req.email)
|
|
smtp_ready = auth_db.is_smtp_configured()
|
|
return {
|
|
"ok": True,
|
|
"email": result["email"],
|
|
"dev_verification_code": None if smtp_ready else result.get("verification_code"),
|
|
"email_sent": bool(result.get("email_sent")),
|
|
"message": "验证码已发送,请查收邮箱" if smtp_ready else "验证码已生成",
|
|
}
|
|
except auth_db.AuthError as exc:
|
|
auth_error(exc)
|
|
|
|
|
|
@router.post("/api/auth/complete-registration")
|
|
async def api_auth_complete_registration(req: CompleteRegistrationRequest):
|
|
try:
|
|
user = auth_db.complete_registration(req.email, req.code, req.password, req.invite_code)
|
|
return {"ok": True, "user": user, "message": "注册成功,请登录"}
|
|
except auth_db.AuthError as exc:
|
|
auth_error(exc)
|
|
|
|
|
|
@router.post("/api/auth/verify-email")
|
|
async def api_auth_verify_email(req: VerifyEmailRequest):
|
|
try:
|
|
user = auth_db.verify_email(req.email, req.code)
|
|
return {"ok": True, "user": user, "message": "邮箱验证成功"}
|
|
except auth_db.AuthError as exc:
|
|
auth_error(exc)
|
|
|
|
|
|
@router.post("/api/auth/resend-verification")
|
|
async def api_auth_resend_verification(req: ResendVerificationRequest):
|
|
try:
|
|
result = auth_db.resend_verification_code(req.email)
|
|
smtp_ready = auth_db.is_smtp_configured()
|
|
return {
|
|
"ok": True,
|
|
"email": result["email"],
|
|
"dev_verification_code": None if smtp_ready else result.get("verification_code"),
|
|
"email_sent": bool(result.get("email_sent")),
|
|
"message": "验证码已重新发送,请查收邮箱" if smtp_ready else "验证码已重新生成",
|
|
}
|
|
except auth_db.AuthError as exc:
|
|
auth_error(exc)
|
|
|
|
|
|
@router.post("/api/auth/login")
|
|
async def api_auth_login(req: LoginRequest, request: Request = None):
|
|
try:
|
|
session = auth_db.login_user(req.email, req.password)
|
|
auth_db.log_user_activity(session["user"]["id"], "login", "auth", ip=request.client.host if request.client else "")
|
|
sub = auth_db.get_current_subscription(session["user"]["id"])
|
|
next_path = "/app" if sub else "/subscription?welcome=1"
|
|
resp = JSONResponse({
|
|
"ok": True,
|
|
"user": session["user"],
|
|
"expires_at": session["expires_at"],
|
|
"subscription": sub,
|
|
"subscription_active": bool(sub),
|
|
"next": next_path,
|
|
})
|
|
resp.set_cookie("altcoin_session", session["token"], httponly=True, samesite="lax", max_age=30 * 24 * 3600)
|
|
return resp
|
|
except auth_db.AuthError as exc:
|
|
auth_error(exc, status_code=400)
|
|
|
|
|
|
@router.get("/api/auth/me")
|
|
async def api_auth_me(altcoin_session: str = Cookie(default="")):
|
|
user = require_user(altcoin_session)
|
|
sub = auth_db.get_current_subscription(user["id"])
|
|
return {"ok": True, "user": user, "subscription": sub, "subscription_active": bool(sub)}
|
|
|
|
|
|
@router.post("/api/auth/change-password")
|
|
async def api_auth_change_password(req: ChangePasswordRequest, altcoin_session: str = Cookie(default="")):
|
|
user = require_user(altcoin_session)
|
|
try:
|
|
return auth_db.change_password(user["id"], req.old_password, req.new_password)
|
|
except auth_db.AuthError as exc:
|
|
auth_error(exc)
|
|
|
|
|
|
@router.post("/api/auth/logout")
|
|
async def api_auth_logout(altcoin_session: str = Cookie(default="")):
|
|
auth_db.logout_user(altcoin_session)
|
|
resp = JSONResponse({"ok": True, "message": "已退出登录"})
|
|
resp.delete_cookie("altcoin_session")
|
|
return resp
|
|
|
|
|
|
@router.post("/api/subscriptions/free-trial")
|
|
async def api_subscription_free_trial(altcoin_session: str = Cookie(default="")):
|
|
user = require_user(altcoin_session)
|
|
try:
|
|
sub = auth_db.claim_free_trial(user["id"])
|
|
return {"ok": True, "subscription": sub, "message": "已开通新用户免费体验1个月"}
|
|
except auth_db.AuthError as exc:
|
|
auth_error(exc)
|
|
|
|
|
|
@router.get("/api/subscription/plans")
|
|
async def api_subscription_plans():
|
|
auth_db.init_auth_db()
|
|
conn = auth_db.get_conn()
|
|
rows = conn.execute("SELECT * FROM subscription_plan ORDER BY sort_order ASC").fetchall()
|
|
conn.close()
|
|
return [dict(r) for r in rows]
|
|
|
|
|
|
@router.get("/api/referral/stats")
|
|
async def api_referral_stats(altcoin_session: str = Cookie(default="")):
|
|
user = auth_db.get_user_by_session_token(altcoin_session)
|
|
if not user:
|
|
raise HTTPException(status_code=401, detail="请先登录")
|
|
return auth_db.get_referral_stats(user["id"])
|