Files
CosScene/server/app/api/v1/endpoints/membership.py
T
2026-05-09 16:40:29 +08:00

82 lines
2.6 KiB
Python

from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.deps import get_current_active_user, get_db
from app.models.membership import MembershipPlan, UserMembership
from app.models.user import User
from app.schemas.membership import MembershipPlanOut, PurchaseMembership, UserMembershipOut
router = APIRouter()
@router.get("/plans", response_model=list[MembershipPlanOut])
async def list_plans(db: AsyncSession = Depends(get_db)):
result = await db.execute(
select(MembershipPlan)
.where(MembershipPlan.is_active == True)
.order_by(MembershipPlan.sort_order.asc())
)
return result.scalars().all()
@router.get("/me", response_model=UserMembershipOut | None)
async def get_my_membership(
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db),
):
now = datetime.now(timezone.utc)
result = await db.execute(
select(UserMembership).where(
UserMembership.user_id == current_user.id,
UserMembership.is_active == True,
UserMembership.end_date >= now,
).order_by(UserMembership.end_date.desc()).limit(1)
)
return result.scalar_one_or_none()
@router.post("/purchase", response_model=UserMembershipOut)
async def purchase_membership(
payload: PurchaseMembership,
current_user: User = Depends(get_current_active_user),
db: AsyncSession = Depends(get_db),
):
plan_result = await db.execute(
select(MembershipPlan).where(
MembershipPlan.id == payload.plan_id,
MembershipPlan.is_active == True,
)
)
plan = plan_result.scalar_one_or_none()
if not plan:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="会员方案不存在或已下架")
now = datetime.now(timezone.utc)
existing = await db.execute(
select(UserMembership).where(
UserMembership.user_id == current_user.id,
UserMembership.is_active == True,
UserMembership.end_date >= now,
).order_by(UserMembership.end_date.desc()).limit(1)
)
current_membership = existing.scalar_one_or_none()
start = current_membership.end_date if current_membership else now
end = start + timedelta(days=plan.duration_days)
membership = UserMembership(
user_id=current_user.id,
plan_id=plan.id,
start_date=start,
end_date=end,
is_active=True,
)
db.add(membership)
await db.commit()
await db.refresh(membership)
return membership