feat: Add Bulk Registration, Change Password, and update Auth UI

This commit is contained in:
2026-09-24 20:53:21 +05:30
parent 3ed7028bda
commit 85974b97f5
7 changed files with 204 additions and 14 deletions

View File

@@ -195,6 +195,93 @@ class LoginPayload(BaseModel):
email: str
password: str
import csv
import io
import secrets
import string
import bcrypt
class ChangePasswordRequest(BaseModel):
current_password: str
new_password: str
@app.post("/api/auth/change-password", tags=["Authentication"])
def change_password(payload: ChangePasswordRequest, session: Session = Depends(get_session), current_user: models.User = Depends(get_current_user)):
# Check demo account
if current_user.email == "demo@pragativeer.com":
if payload.current_password != "Pv9#kL2$mQ8!vX4@":
raise HTTPException(status_code=400, detail="Incorrect current password")
# Don't actually change demo password
return {"success": True, "message": "Demo password unchanged"}
if not current_user.password_hash or current_user.password_hash == "mock_hash":
raise HTTPException(status_code=400, detail="User has no password set")
if not bcrypt.checkpw(payload.current_password.encode('utf-8'), current_user.password_hash.encode('utf-8')):
raise HTTPException(status_code=400, detail="Incorrect current password")
hashed_password = bcrypt.hashpw(payload.new_password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
current_user.password_hash = hashed_password
session.add(current_user)
session.commit()
return {"success": True, "message": "Password updated successfully"}
@app.post("/api/admin/students/bulk", tags=["Admin"])
async def bulk_register_students(file: UploadFile = File(...), session: Session = Depends(get_session)):
# Simple check for now (we can rely on frontend calling it correctly or auth middleware if we add it)
content = await file.read()
decoded = content.decode('utf-8')
csv_reader = csv.DictReader(io.StringIO(decoded))
results = []
for row in csv_reader:
email = row.get("email", "").strip()
name = row.get("name", "").strip()
phone = row.get("phone", "").strip()
target_exam_str = row.get("target_exam", "JEE_Main").strip()
tier_str = row.get("tier", "Free").strip()
if not email or not name:
continue
existing = session.exec(select(models.User).where(models.User.email == email)).first()
if existing:
continue
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))
exam = models.ExamEnum.JEE_Main
if target_exam_str == "NEET": exam = models.ExamEnum.NEET
elif target_exam_str == "JEE_Advanced": exam = models.ExamEnum.JEE_Advanced
elif target_exam_str == "JEE_NEET": exam = models.ExamEnum.JEE_NEET
elif target_exam_str == "JEE + NEET": exam = models.ExamEnum.JEE_NEET
tier = models.TierEnum.Free
if tier_str == "Pro": tier = models.TierEnum.Pro
elif tier_str in ("Al_Coach", "AI Coach"): tier = models.TierEnum.Al_Coach
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
user = models.User(
email=email,
name=name,
phone=phone,
password_hash=hashed_password,
target_exam=exam,
tier=tier
)
session.add(user)
results.append({
"name": name,
"email": email,
"password": password
})
session.commit()
return results
@app.post("/api/auth/register", tags=["Authentication"])
def register(payload: RegisterPayload, session: Session = Depends(get_session)):
import bcrypt