diff --git a/backend/__pycache__/db_utils.cpython-313.pyc b/backend/__pycache__/db_utils.cpython-313.pyc index e224238..943fab4 100644 Binary files a/backend/__pycache__/db_utils.cpython-313.pyc and b/backend/__pycache__/db_utils.cpython-313.pyc differ diff --git a/backend/__pycache__/main.cpython-313.pyc b/backend/__pycache__/main.cpython-313.pyc index ad86ee8..c6a32ef 100644 Binary files a/backend/__pycache__/main.cpython-313.pyc and b/backend/__pycache__/main.cpython-313.pyc differ diff --git a/backend/__pycache__/user_db_utils.cpython-313.pyc b/backend/__pycache__/user_db_utils.cpython-313.pyc index 89b66ff..22faed0 100644 Binary files a/backend/__pycache__/user_db_utils.cpython-313.pyc and b/backend/__pycache__/user_db_utils.cpython-313.pyc differ diff --git a/backend/main.py b/backend/main.py index ae87be5..26a2f4d 100644 --- a/backend/main.py +++ b/backend/main.py @@ -94,6 +94,7 @@ class UserResponse(BaseModel): first_name: Optional[str] = None last_name: Optional[str] = None display_name: str + is_admin: bool = False app = FastAPI( @@ -164,7 +165,7 @@ def create_recipe(recipe_in: RecipeCreate, current_user: dict = Depends(get_curr @app.put("/recipes/{recipe_id}", response_model=Recipe) def update_recipe(recipe_id: int, recipe_in: RecipeUpdate, current_user: dict = Depends(get_current_user)): - # Check ownership BEFORE updating + # Check ownership BEFORE updating (admins can edit any recipe) conn = get_conn() try: with conn.cursor() as cur: @@ -172,7 +173,8 @@ def update_recipe(recipe_id: int, recipe_in: RecipeUpdate, current_user: dict = recipe = cur.fetchone() if not recipe: raise HTTPException(status_code=404, detail="המתכון לא נמצא") - if recipe["user_id"] != current_user["user_id"]: + # Allow if user is owner OR admin + if recipe["user_id"] != current_user["user_id"] and not current_user.get("is_admin", False): raise HTTPException(status_code=403, detail="אין לך הרשאה לערוך מתכון זה") finally: conn.close() @@ -201,7 +203,7 @@ def update_recipe(recipe_id: int, recipe_in: RecipeUpdate, current_user: dict = @app.delete("/recipes/{recipe_id}", status_code=204) def delete_recipe(recipe_id: int, current_user: dict = Depends(get_current_user)): - # Get recipe first to check ownership + # Get recipe first to check ownership (admins can delete any recipe) conn = get_conn() try: with conn.cursor() as cur: @@ -209,7 +211,8 @@ def delete_recipe(recipe_id: int, current_user: dict = Depends(get_current_user) recipe = cur.fetchone() if not recipe: raise HTTPException(status_code=404, detail="המתכון לא נמצא") - if recipe["user_id"] != current_user["user_id"]: + # Allow if user is owner OR admin + if recipe["user_id"] != current_user["user_id"] and not current_user.get("is_admin", False): raise HTTPException(status_code=403, detail="אין לך הרשאה למחוק מתכון זה") finally: conn.close() diff --git a/backend/schema.sql b/backend/schema.sql index 78b2138..94b95c9 100644 --- a/backend/schema.sql +++ b/backend/schema.sql @@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS users ( first_name TEXT, last_name TEXT, display_name TEXT UNIQUE NOT NULL, + is_admin BOOLEAN DEFAULT FALSE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); @@ -41,4 +42,10 @@ CREATE INDEX IF NOT EXISTS idx_recipes_made_by CREATE INDEX IF NOT EXISTS idx_recipes_user_id ON recipes (user_id); +-- Create default admin user (password: admin123) +-- Password hash generated with bcrypt for 'admin123' +INSERT INTO users (username, email, password_hash, first_name, last_name, display_name, is_admin) +VALUES ('admin', 'admin@myrecipes.local', '$2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewY5lE7UGf3rCvHC', 'Admin', 'User', 'מנהל', TRUE) +ON CONFLICT (username) DO NOTHING; + diff --git a/backend/user_db_utils.py b/backend/user_db_utils.py index 0b4be44..9944e84 100644 --- a/backend/user_db_utils.py +++ b/backend/user_db_utils.py @@ -14,7 +14,7 @@ def get_db_connection(): ) -def create_user(username: str, email: str, password_hash: str, first_name: str = None, last_name: str = None, display_name: str = None): +def create_user(username: str, email: str, password_hash: str, first_name: str = None, last_name: str = None, display_name: str = None, is_admin: bool = False): """Create a new user""" conn = get_db_connection() cur = conn.cursor(cursor_factory=RealDictCursor) @@ -24,11 +24,11 @@ def create_user(username: str, email: str, password_hash: str, first_name: str = cur.execute( """ - INSERT INTO users (username, email, password_hash, first_name, last_name, display_name) - VALUES (%s, %s, %s, %s, %s, %s) - RETURNING id, username, email, first_name, last_name, display_name, created_at + INSERT INTO users (username, email, password_hash, first_name, last_name, display_name, is_admin) + VALUES (%s, %s, %s, %s, %s, %s, %s) + RETURNING id, username, email, first_name, last_name, display_name, is_admin, created_at """, - (username, email, password_hash, first_name, last_name, final_display_name) + (username, email, password_hash, first_name, last_name, final_display_name, is_admin) ) user = cur.fetchone() conn.commit() @@ -44,7 +44,7 @@ def get_user_by_username(username: str): cur = conn.cursor(cursor_factory=RealDictCursor) try: cur.execute( - "SELECT id, username, email, password_hash, first_name, last_name, display_name, created_at FROM users WHERE username = %s", + "SELECT id, username, email, password_hash, first_name, last_name, display_name, is_admin, created_at FROM users WHERE username = %s", (username,) ) user = cur.fetchone() @@ -60,7 +60,7 @@ def get_user_by_email(email: str): cur = conn.cursor(cursor_factory=RealDictCursor) try: cur.execute( - "SELECT id, username, email, password_hash, first_name, last_name, display_name, created_at FROM users WHERE email = %s", + "SELECT id, username, email, password_hash, first_name, last_name, display_name, is_admin, created_at FROM users WHERE email = %s", (email,) ) user = cur.fetchone() @@ -76,7 +76,7 @@ def get_user_by_id(user_id: int): cur = conn.cursor(cursor_factory=RealDictCursor) try: cur.execute( - "SELECT id, username, email, first_name, last_name, display_name, created_at FROM users WHERE id = %s", + "SELECT id, username, email, first_name, last_name, display_name, is_admin, created_at FROM users WHERE id = %s", (user_id,) ) user = cur.fetchone() @@ -92,7 +92,7 @@ def get_user_by_display_name(display_name: str): cur = conn.cursor(cursor_factory=RealDictCursor) try: cur.execute( - "SELECT id, username, email, display_name, created_at FROM users WHERE display_name = %s", + "SELECT id, username, email, display_name, is_admin, created_at FROM users WHERE display_name = %s", (display_name,) ) user = cur.fetchone()