student-admin / routes /auth.py
roshcheeku's picture
Update routes/auth.py
297b6de verified
# routes/auth.py
from flask import Blueprint, request, jsonify
import bcrypt
from bson.objectid import ObjectId
from datetime import datetime, timedelta
import secrets
from db import db
from utils.validators import valid_email, valid_password
from utils.auth import create_token
auth_bp = Blueprint("auth", __name__)
# -----------------------------
# SIGNUP
# -----------------------------
@auth_bp.route("/signup", methods=["POST"])
def signup():
data = request.json or {}
name = data.get("name","").strip()
email = data.get("email","").strip().lower()
password = data.get("password","")
if not name or not email or not password:
return jsonify({"error":"Missing fields"}), 400
if not valid_email(email):
return jsonify({"error":"Invalid email"}), 400
if not valid_password(password):
return jsonify({"error":"Password too weak (min 8, 1 number, 1 special)"}), 400
if db.users.find_one({"email": email}):
return jsonify({"error":"User already exists"}), 400
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
user_doc = {
"name": name,
"email": email,
"password": hashed,
"role": "student",
"blocked": False,
"reset_token": None,
"reset_token_expiry": None
}
res = db.users.insert_one(user_doc)
uid = str(res.inserted_id)
return jsonify({"message":"User created", "id": uid}), 201
# -----------------------------
# LOGIN
# -----------------------------
@auth_bp.route("/login", methods=["POST"])
def login():
data = request.json or {}
email = (data.get("email") or "").strip().lower()
password = data.get("password","")
user = db.users.find_one({"email": email})
if not user:
return jsonify({"error":"Invalid credentials"}), 401
if user.get("blocked", False):
return jsonify({"error":"Account blocked"}), 403
hashed = user["password"]
if not bcrypt.checkpw(password.encode(), hashed.encode()):
return jsonify({"error":"Invalid credentials"}), 401
token = create_token(user["_id"], user.get("role","student"))
return jsonify({
"token": token,
"role": user.get("role","student"),
"name": user.get("name")
})
# -----------------------------
# FORGOT PASSWORD
# -----------------------------
@auth_bp.route("/forgot-password", methods=["POST"])
def forgot_password():
data = request.json or {}
email = (data.get("email") or "").strip().lower()
user = db.users.find_one({"email": email})
if not user:
return jsonify({"error":"User not found"}), 404
# Generate secure token
token = secrets.token_urlsafe(32)
expiry = datetime.utcnow() + timedelta(hours=1) # valid 1 hour
db.users.update_one(
{"_id": user["_id"]},
{"$set": {"reset_token": token, "reset_token_expiry": expiry}}
)
# TODO: send email; for now, print to console
print(f"[RESET LINK] {email}: https://yourfrontend.com/reset-password?token={token}")
return jsonify({"message":"Password reset link sent to email (check console in dev mode)"}), 200
# -----------------------------
# RESET PASSWORD
# -----------------------------
@auth_bp.route("/reset-password", methods=["POST"])
def reset_password():
data = request.json or {}
token = data.get("token")
new_password = data.get("password")
if not token or not new_password:
return jsonify({"error":"Missing token or password"}), 400
if not valid_password(new_password):
return jsonify({"error":"Password too weak (min 8, 1 number, 1 special)"}), 400
user = db.users.find_one({"reset_token": token})
if not user:
return jsonify({"error":"Invalid or expired token"}), 400
if not user.get("reset_token_expiry") or user["reset_token_expiry"] < datetime.utcnow():
return jsonify({"error":"Token expired"}), 400
hashed_pw = bcrypt.hashpw(new_password.encode(), bcrypt.gensalt()).decode()
db.users.update_one(
{"_id": user["_id"]},
{"$set": {"password": hashed_pw},
"$unset": {"reset_token": "", "reset_token_expiry": ""}}
)
return jsonify({"message":"Password reset successful"}), 200