Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions .env.local

This file was deleted.

13 changes: 6 additions & 7 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,21 @@
def create_app():
app = Flask(__name__)
app.config.from_object(config)

# Initialize SQLAlchemy
db.init_app(app)

# --- ✅ Enable CORS ---
# Allow both local development and production frontend domains
# Enable CORS
CORS(app, resources={r"/*": {"origins": "*"}})

# --- ✅ Register Blueprints ---
# Register ALL blueprints through main_blueprint
app.register_blueprint(main_blueprint, url_prefix="/api")

# --- ✅ Auto-create tables only in development ---
# Auto-create tables only in dev
with app.app_context():
db.create_all()

# Optional health check route
# Health check
@app.route("/api/ping")
def ping():
return {"message": "pong"}
Expand All @@ -33,4 +32,4 @@ def ping():

if __name__ == "__main__":
app = create_app()
app.run(debug=True, threaded=False,port=5000,host="0.0.0.0")
app.run(debug=True, threaded=False, port=5000, host="0.0.0.0")
19 changes: 19 additions & 0 deletions auth_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from werkzeug.security import generate_password_hash, check_password_hash
import jwt
from datetime import datetime, timedelta
from config import config

SECRET_KEY = config.JWT_SECRET

def hash_password(password: str) -> str:
return generate_password_hash(password)

def verify_password(hashed: str, password: str) -> bool:
return check_password_hash(hashed, password)

def create_jwt(user_id: int) -> str:
payload = {
"user_id": user_id,
"exp": datetime.utcnow() + timedelta(hours=12),
}
return jwt.encode(payload, SECRET_KEY, algorithm="HS256")
31 changes: 30 additions & 1 deletion routes/auth_routes.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,61 @@
from flask import Blueprint, jsonify, request
from werkzeug.security import generate_password_hash, check_password_hash
from models import db, User
import jwt
from datetime import datetime, timedelta
from config import config

auth_bp = Blueprint("auth", __name__)

# Generate JWT token
def create_jwt(user_id):
payload = {
"user_id": user_id,
"exp": datetime.utcnow() + timedelta(hours=12)
}
return jwt.encode(payload, config.SECRET_KEY, algorithm="HS256")


@auth_bp.route("/register", methods=["POST"])
def register():
data = request.get_json()

# Validate required fields
if not data or not all(k in data for k in ("username", "email", "password")):
return jsonify({"error": "username, email, and password are required"}), 400

# Check existing user
if User.query.filter_by(email=data["email"]).first():
return jsonify({"error": "User with this email already exists"}), 400

# Create user
pw_hash = generate_password_hash(data["password"], method="pbkdf2:sha256", salt_length=16)
user = User(username=data["username"], email=data["email"], password_hash=pw_hash)

db.session.add(user)
db.session.commit()

return jsonify({"message": "User registered!", "user_id": user.id}), 201


@auth_bp.route("/login", methods=["POST"])
def login():
data = request.get_json()

# Validate fields
if not data or not all(k in data for k in ("email", "password")):
return jsonify({"error": "Email and password are required"}), 400

user = User.query.filter_by(email=data["email"]).first()

if not user or not check_password_hash(user.password_hash, data["password"]):
return jsonify({"error": "Invalid email or password"}), 401

return jsonify({"message": "Login successful!", "user_id": user.id}), 200
# Create JWT token
token = create_jwt(user.id)

return jsonify({
"message": "Login successful!",
"token": token,
"user_id": user.id
}), 200