fix(auth): resolve demo login redirect loop, fix backend API bugs, restore clean login UI, and add comprehensive API docs with headers

This commit is contained in:
2026-09-04 11:49:13 +05:30
parent b152f73c3d
commit 3ad281aae6
8 changed files with 1299 additions and 52 deletions

View File

@@ -123,22 +123,33 @@ def register(payload: RegisterPayload, session: Session = Depends(get_session)):
def login(payload: LoginPayload, session: Session = Depends(get_session)):
import bcrypt
user = session.exec(select(models.User).where(models.User.email == payload.email)).first()
# Allow demo/admin mock logic to still work if needed
if payload.email == "demo@pragativeer.com" and payload.password == "Pv9#kL2$mQ8!vX4@":
return {"success": True, "role": "user", "token": "mock_token"}
demo_user = session.exec(select(models.User).where(models.User.email == "student@pragativeer.com")).first()
token_id = str(demo_user.id) if demo_user else "b0e17378-864d-439e-8806-708dc48a891b"
return {"success": True, "role": "user", "token": token_id}
if payload.email == "admin@pragativeer.com" and payload.password == "admin123":
return {"success": True, "role": "admin", "token": "mock_admin_token"}
return {"success": True, "role": "admin", "token": "admin"}
user = session.exec(select(models.User).where(models.User.email == payload.email)).first()
if not user:
raise HTTPException(status_code=401, detail="Invalid email or password")
# Handle legacy mock_hash from initial seed
if user.password_hash == "mock_hash":
if payload.password in ("Password123!", "Pv9#kL2$mQ8!vX4@", "admin123"):
user.password_hash = bcrypt.hashpw(payload.password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
session.add(user)
session.commit()
return {"success": True, "role": "admin" if (user.email and "admin" in user.email) else "user", "token": str(user.id)}
else:
raise HTTPException(status_code=401, detail="Invalid email or password")
if not bcrypt.checkpw(payload.password.encode('utf-8'), user.password_hash.encode('utf-8')):
raise HTTPException(status_code=401, detail="Invalid email or password")
# Real application would issue a JWT here
return {"success": True, "role": "user", "token": str(user.id)}
return {"success": True, "role": "admin" if (user.email and "admin" in user.email) else "user", "token": str(user.id)}
# --- CBT ENGINE ---
@@ -154,7 +165,7 @@ def list_active_tests(exam_pattern: Optional[str] = None, type: Optional[str] =
return session.exec(query).all()
@app.get("/api/tests/{test_id}", response_model=models.Test, tags=["CBT Engine"])
def get_test_by_id(test_id: UUID, user_id: UUID, session: Session = Depends(get_session)):
def get_test_by_id(test_id: UUID, user_id: Optional[UUID] = None, session: Session = Depends(get_session)):
test = session.get(models.Test, test_id)
if not test:
raise HTTPException(status_code=404, detail="Requested examination structure not found.")
@@ -444,20 +455,6 @@ def get_parent_dashboard_metrics(parent_id: UUID, student_id: UUID, session: Ses
# --- BILLING & SUBSCRIPTION ---
@app.post("/api/billing/create-order", tags=["Subscription Engine"])
def create_subscription_order(user_id: UUID, plan_tier: str, session: Session = Depends(get_session)):
user = session.get(models.User, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found.")
pricing_map = {"Pro": 29900, "Al_Coach": 59900}
amount = pricing_map.get(plan_tier)
if not amount:
raise HTTPException(status_code=400, detail="Invalid subscription tier requested.")
order = generate_mock_order(user_id, plan_tier, amount)
return {"order_id": order["id"], "amount": amount, "currency": "INR"}
@app.post("/api/billing/webhook/razorpay", tags=["Subscription Engine"])
async def razorpay_webhook_handler(request: Request, session: Session = Depends(get_session)):
payload_bytes = await request.body()
@@ -943,7 +940,9 @@ def delete_coupon(coupon_id: UUID, session: Session = Depends(get_session)):
session.delete(coupon)
session.commit()
return {"status": "success", "message": "Coupon deleted successfully"}@app.post("/api/users/{user_id}/avatar", tags=["Users"])
return {"status": "success", "message": "Coupon deleted successfully"}
@app.post("/api/users/{user_id}/avatar", tags=["Users"])
async def upload_avatar(user_id: UUID, file: UploadFile = File(...), session: Session = Depends(get_session)):
user = session.get(models.User, user_id)
if not user:
@@ -1186,21 +1185,19 @@ def verify_payment(payload: VerifyPaymentPayload, session: Session = Depends(get
raise HTTPException(status_code=400, detail="Invalid gateway")
# Update user's tier
if payload.tier == "Al_Coach":
user.tier = models.TierEnum.al_coach
if payload.tier in ("Al_Coach", "AI_Coach"):
user.tier = models.TierEnum.AI_COACH
elif payload.tier == "Pro":
user.tier = models.TierEnum.pro
user.tier = models.TierEnum.PRO
session.add(user)
# Log transaction
txn = models.Transaction(
user_id=user.id,
amount=11999.00 if payload.tier == "Al_Coach" else 3499.00,
currency="INR",
status="completed",
razorpay_order_id=payload.razorpay_order_id if payload.gateway == "razorpay" else None,
razorpay_payment_id=payload.razorpay_payment_id if payload.gateway == "razorpay" else (payload.phonepe_transaction_id or payload.stripe_session_id)
amount=11999.00 if payload.tier in ("Al_Coach", "AI_Coach") else 3499.00,
tier=payload.tier,
status="completed"
)
session.add(txn)
session.commit()