From 73512d46ad801bdf482a872f077d1b1ae4e14212 Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Sat, 15 Feb 2025 18:57:28 -0600 Subject: [PATCH 1/4] (refactor): change from .venv to venv --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index d25ecb5..27b4c81 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.venv/ +venv/ .env instance models/__pycache__ From 32dcace98575f97f2a14c4d2f8708f4ee0ceeded Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Sat, 15 Feb 2025 18:57:53 -0600 Subject: [PATCH 2/4] (lib): added psycopg2-binary --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index d3e7d39..103960e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ flask_bcrypt flask_cors flask_sqlalchemy python-dotenv -werkzeug \ No newline at end of file +werkzeug +psycopg2-binary \ No newline at end of file From 51f154ab731e9039f5ef1a00d5176bab240bca32 Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Sat, 15 Feb 2025 18:58:48 -0600 Subject: [PATCH 3/4] (feat): Added PostgreSQL connection string encoding. --- models/__init__.py | 21 +++++++++++++++++++-- models/user.py | 17 ++++++++++++++++- routes/auth.py | 4 +--- server.py | 10 ++++------ services/user.py | 25 +++++-------------------- 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/models/__init__.py b/models/__init__.py index 96c5d7b..a53c270 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -1,5 +1,22 @@ +import os from flask_sqlalchemy import SQLAlchemy -from flask_bcrypt import Bcrypt +from dotenv import load_dotenv +from urllib.parse import quote_plus + +load_dotenv() + +PG_USER = quote_plus(os.getenv('PG_USER')) +PG_PASSWORD = quote_plus(os.getenv('PG_PASSWORD')) +PG_HOST = os.getenv('PG_HOST') +PG_PORT = os.getenv('PG_PORT') +PG_DATABASE = os.getenv('PG_DATABASE') + +DATABASE_URI = f"postgresql+psycopg2://{PG_USER}:{PG_PASSWORD}@{PG_HOST}:{PG_PORT}/{PG_DATABASE}" db = SQLAlchemy() -bcrypt = Bcrypt() \ No newline at end of file + +def init_db(app): + """Initialize the SQLAlchemy app with the configuration.""" + app.config['SQLALCHEMY_DATABASE_URI'] = DATABASE_URI + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + db.init_app(app) diff --git a/models/user.py b/models/user.py index 0092d1a..0cdc1e2 100644 --- a/models/user.py +++ b/models/user.py @@ -1,8 +1,23 @@ from models import db +from werkzeug.security import generate_password_hash, check_password_hash class User(db.Model): __tablename__ = 'users' - + id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) password = db.Column(db.String(128), nullable=False) + + def __init__(self, username, password, hash_password=True): + self.username = username + # Optionally hash the password automatically. + if hash_password: + self.password = generate_password_hash(password, method="pbkdf2:sha256") + else: + self.password = password + + def check_password(self, password): + return check_password_hash(self.password, password) + + def __repr__(self): + return f"" \ No newline at end of file diff --git a/routes/auth.py b/routes/auth.py index 770cc96..f73a97b 100644 --- a/routes/auth.py +++ b/routes/auth.py @@ -15,8 +15,6 @@ def signup(): return jsonify({"message": "User created successfully", "username": new_user.username}), 201 except ValueError as e: return jsonify({"message": str(e)}), 400 - - @auth_bp.route('/login', methods=['POST']) def login(): @@ -28,4 +26,4 @@ def login(): user = user_service.verify_user(username, password) return jsonify({"message": "Login successful", "user_id": user.id}), 200 except ValueError as e: - return jsonify({"error": str(e)}), 401 \ No newline at end of file + return jsonify({"error": str(e)}), 401 diff --git a/server.py b/server.py index cd38ee1..1a55e21 100644 --- a/server.py +++ b/server.py @@ -1,6 +1,6 @@ import os from flask import Flask -from models import db, bcrypt +from models import db, init_db from routes.auth import auth_bp from dotenv import load_dotenv from flask_cors import CORS @@ -8,14 +8,12 @@ from flask_cors import CORS load_dotenv() app = Flask(__name__) +CORS(app) -CORS(app) - -app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE') +app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE') # Or use DATABASE_URI from models app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False -db.init_app(app) -bcrypt.init_app(app) +init_db(app) app.register_blueprint(auth_bp) diff --git a/services/user.py b/services/user.py index 600cb78..60754df 100644 --- a/services/user.py +++ b/services/user.py @@ -2,33 +2,18 @@ from werkzeug.security import generate_password_hash, check_password_hash from models.user import User, db class UserService: - def __init__(self): - self.db = db - def create_user(self, username, password): - # Check if the user exists existing_user = User.query.filter_by(username=username).first() if existing_user: raise ValueError("User already exists") - # Hash the password before storing - hash_password = generate_password_hash(password) - - # Create a new user - new_user = User(username=username, password=hash_password) - self.db.session.add(new_user) - self.db.session.commit() - + new_user = User(username=username, password=password) + db.session.add(new_user) + db.session.commit() return new_user def verify_user(self, username, password): - # Fetch the user by username user = User.query.filter_by(username=username).first() - if not user: + if not user or not user.check_password(password): raise ValueError("Invalid username or password") - - # Verify the hashed password - if not check_password_hash(user.password, password): - raise ValueError("Invalid username or password") - - return user \ No newline at end of file + return user From 16520798746317aa1ccb96c1b5ad07b38d7ee34a Mon Sep 17 00:00:00 2001 From: Blake Ridgway Date: Sat, 15 Feb 2025 19:00:00 -0600 Subject: [PATCH 4/4] (remove): Removed temp comments --- models/user.py | 1 - server.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/models/user.py b/models/user.py index 0cdc1e2..a45bbc5 100644 --- a/models/user.py +++ b/models/user.py @@ -10,7 +10,6 @@ class User(db.Model): def __init__(self, username, password, hash_password=True): self.username = username - # Optionally hash the password automatically. if hash_password: self.password = generate_password_hash(password, method="pbkdf2:sha256") else: diff --git a/server.py b/server.py index 1a55e21..d78ab25 100644 --- a/server.py +++ b/server.py @@ -10,7 +10,7 @@ load_dotenv() app = Flask(__name__) CORS(app) -app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE') # Or use DATABASE_URI from models +app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE') app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False init_db(app)