From 3281e36e60af108d5b76b1d90b599430d0cc847a Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Tue, 27 May 2025 20:26:27 +0500 Subject: [PATCH 01/13] create user fixed and tested --- app/db/crud/users.py | 8 +++++--- app/routers/users.py | 2 +- app/services/users.py | 2 +- app/validators/users.py | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/db/crud/users.py b/app/db/crud/users.py index ec20710..94aad64 100644 --- a/app/db/crud/users.py +++ b/app/db/crud/users.py @@ -16,16 +16,18 @@ def get_all_users(db: Session): return db.query(User).all() def create_user(db: Session, username: str, email: str, hashed_password: str, role: str = "customer") -> User: + print("hehehehe1") user = User( username=username, email=email, hashed_password=hashed_password, - role=role + role_name=role ) + print("hehehehe2") db.add(user) db.commit() - db.refresh(user) - return user + db.refresh(user) # <-- important to reload with DB generated fields + return user # <-- return the User instance, NOT a string or id def update_user_db(db: Session, user_id: int, user_update: UserUpdate): user = get_user_by_id(db, user_id) diff --git a/app/routers/users.py b/app/routers/users.py index 044fa6e..0ff692f 100644 --- a/app/routers/users.py +++ b/app/routers/users.py @@ -27,7 +27,7 @@ def create_user( user_in: UserCreate, db: Session = Depends(get_db), - current_user: TokenData = Depends(permission_required("create_user")), + current_user: TokenData = Depends(permission_required("can_create_user")), ): try: user = create_user_service(db, user_in) diff --git a/app/services/users.py b/app/services/users.py index 194ef3d..79dfe81 100644 --- a/app/services/users.py +++ b/app/services/users.py @@ -14,7 +14,7 @@ def create_user_service(db: Session, user_in: UserCreate): # Hash the password hashed_pw = hash_password(user_in.password) - + print("HEHEHEHHEHEHE") # Create user in DB return db_create_user( db=db, diff --git a/app/validators/users.py b/app/validators/users.py index c8a12e7..a7a5995 100644 --- a/app/validators/users.py +++ b/app/validators/users.py @@ -18,7 +18,7 @@ class UserOut(BaseModel): id: int username: str email: EmailStr - role: str + role_name: str created_at: datetime updated_at: datetime From 73ff2a72d7aa650baca2629abab32b123762c1ab Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Tue, 27 May 2025 20:37:13 +0500 Subject: [PATCH 02/13] list users tested and verified --- app/routers/users.py | 2 +- app/validators/users.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/routers/users.py b/app/routers/users.py index 0ff692f..9b1c355 100644 --- a/app/routers/users.py +++ b/app/routers/users.py @@ -44,7 +44,7 @@ def create_user( @router.get("/", summary="List all users", response_model=List[UserOut]) def list_users( db: Session = Depends(get_db), - current_user: TokenData = Depends(permission_required("list_users")), + current_user: TokenData = Depends(permission_required("can_list_users")), ): try: users = list_users_service(db) diff --git a/app/validators/users.py b/app/validators/users.py index a7a5995..8ea2976 100644 --- a/app/validators/users.py +++ b/app/validators/users.py @@ -8,12 +8,10 @@ class UserCreate(BaseModel): password: Annotated[str, constr(min_length=6, max_length=255)] role: str = "customer" - class UserUpdate(BaseModel): username: Optional[str] = Field(None, min_length=3, max_length=255) email: Optional[EmailStr] = None - class UserOut(BaseModel): id: int username: str From 1d9290b155254df506c9c0b4232cd1c874ae8da7 Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Thu, 29 May 2025 10:27:40 +0500 Subject: [PATCH 03/13] existing endpoints for users thoroughly tested, with slight bug fixes --- app/routers/users.py | 6 +++--- app/utils/jwt.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/routers/users.py b/app/routers/users.py index 9b1c355..2d166cd 100644 --- a/app/routers/users.py +++ b/app/routers/users.py @@ -97,7 +97,7 @@ def get_user( db: Session = Depends(get_db), current_user: TokenData = Depends(get_current_user), ): - if "get_any_user" not in current_user.permissions and current_user.user_id != user_id: + if "can_get_user" not in current_user.permissions and current_user.user_id != user_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Access denied.", @@ -121,7 +121,7 @@ def update_user( db: Session = Depends(get_db), current_user: TokenData = Depends(get_current_user), ): - if "update_any_user" not in current_user.permissions and current_user.user_id != user_id: + if "can_update_user" not in current_user.permissions and current_user.user_id != user_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Access denied.", @@ -142,7 +142,7 @@ def update_user( def delete_user( user_id: int, db: Session = Depends(get_db), - current_user: TokenData = Depends(permission_required("delete_user")), + current_user: TokenData = Depends(permission_required("can_delete_user")), ): try: delete_user_service(db, user_id) diff --git a/app/utils/jwt.py b/app/utils/jwt.py index 7a7af61..cdf2304 100644 --- a/app/utils/jwt.py +++ b/app/utils/jwt.py @@ -9,7 +9,7 @@ JWT_SECRET = os.getenv("JWT_SECRET", "your-secret") JWT_ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256") -ACCESS_TOKEN_EXPIRE_MINUTES = 15 +ACCESS_TOKEN_EXPIRE_MINUTES = 30 REFRESH_TOKEN_EXPIRE_DAYS = 7 oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login") From 8490f046786d2b70a73b61bb649a0824d0f3ce23 Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Thu, 29 May 2025 10:51:47 +0500 Subject: [PATCH 04/13] orders implemented, testing to come --- app/db/crud/orders.py | 25 +++++- app/db/seed.py | 46 ++++++----- app/routers/orders.py | 168 +++++++++++++++++++++++++++++++-------- app/services/orders.py | 55 +++++++++++++ app/validators/orders.py | 27 +++++++ 5 files changed, 268 insertions(+), 53 deletions(-) create mode 100644 app/validators/orders.py diff --git a/app/db/crud/orders.py b/app/db/crud/orders.py index 110d953..e490563 100644 --- a/app/db/crud/orders.py +++ b/app/db/crud/orders.py @@ -1,19 +1,42 @@ from sqlalchemy.orm import Session from app.db.models import Order +from app.validators.orders import OrderUpdate + def get_order_by_id(db: Session, order_id: int) -> Order | None: return db.query(Order).filter(Order.id == order_id).first() -def create_order(db: Session, user_id: int, total_amount, status: str = "pending") -> Order: + +def create_order(db: Session, user_id: int, total_amount: float, status: str = "pending") -> Order: order = Order(user_id=user_id, total_amount=total_amount, status=status) db.add(order) db.commit() db.refresh(order) return order + def get_orders_by_user_id(db: Session, user_id: int) -> list[Order]: return db.query(Order).filter(Order.user_id == user_id).all() + +def get_all_orders(db: Session) -> list[Order]: + return db.query(Order).all() + + +def update_order_db(db: Session, order_id: int, order_update: OrderUpdate) -> Order: + order = get_order_by_id(db, order_id) + if not order: + return None + + # Update allowed fields only + for field, value in order_update.dict(exclude_unset=True).items(): + setattr(order, field, value) + + db.commit() + db.refresh(order) + return order + + def delete_order_by_id(db: Session, order_id: int): order = get_order_by_id(db, order_id) if order: diff --git a/app/db/seed.py b/app/db/seed.py index 4aaa1cb..f35bbc8 100644 --- a/app/db/seed.py +++ b/app/db/seed.py @@ -37,14 +37,25 @@ def seed_permissions(db): Permission(name="can_get_user"), Permission(name="can_update_user"), Permission(name="can_delete_user"), - Permission(name="can_get_own_profile"), Permission(name="can_update_own_profile"), + + # Order related permissions + Permission(name="can_create_order"), + Permission(name="can_list_orders"), + Permission(name="can_get_order"), + Permission(name="can_update_order"), + Permission(name="can_delete_order"), + + Permission(name="can_get_own_orders"), + Permission(name="can_get_own_order"), ] + for perm in permissions: existing = db.query(Permission).filter(Permission.name == perm.name).first() if not existing: db.add(perm) + db.commit() @@ -53,27 +64,22 @@ def seed_rules(db): admin_role = db.query(Role).filter(Role.name == "admin").first() customer_role = db.query(Role).filter(Role.name == "customer").first() - # Fetch permissions - can_create_user = db.query(Permission).filter(Permission.name == "can_create_user").first() - can_list_users = db.query(Permission).filter(Permission.name == "can_list_users").first() - can_get_user = db.query(Permission).filter(Permission.name == "can_get_user").first() - can_update_user = db.query(Permission).filter(Permission.name == "can_update_user").first() - can_delete_user = db.query(Permission).filter(Permission.name == "can_delete_user").first() - - can_get_own_profile = db.query(Permission).filter(Permission.name == "can_get_own_profile").first() - can_update_own_profile = db.query(Permission).filter(Permission.name == "can_update_own_profile").first() + # Fetch all permissions at once + permission_lookup = { + perm.name: perm for perm in db.query(Permission).all() + } rules = [ - # Admin permissions - full user management - Rule(role_name=admin_role.name, permission_name=can_create_user.name), - Rule(role_name=admin_role.name, permission_name=can_list_users.name), - Rule(role_name=admin_role.name, permission_name=can_get_user.name), - Rule(role_name=admin_role.name, permission_name=can_update_user.name), - Rule(role_name=admin_role.name, permission_name=can_delete_user.name), - - # Customer permissions - maybe limited or none here - Rule(role_name=customer_role.name, permission_name=can_get_own_profile.name), - Rule(role_name=customer_role.name, permission_name=can_update_own_profile.name), + # Admin - full order management + Rule(role_name=admin_role.name, permission_name="can_create_order"), + Rule(role_name=admin_role.name, permission_name="can_list_orders"), + Rule(role_name=admin_role.name, permission_name="can_get_order"), + Rule(role_name=admin_role.name, permission_name="can_update_order"), + Rule(role_name=admin_role.name, permission_name="can_delete_order"), + + # Customer - limited order access + Rule(role_name=customer_role.name, permission_name="can_get_own_orders"), + Rule(role_name=customer_role.name, permission_name="can_get_own_order"), ] for rule in rules: diff --git a/app/routers/orders.py b/app/routers/orders.py index ff13515..60a530b 100644 --- a/app/routers/orders.py +++ b/app/routers/orders.py @@ -1,36 +1,140 @@ from fastapi import APIRouter, Depends, HTTPException, status -from typing import List, Optional +from fastapi.responses import JSONResponse +from typing import List + +from sqlalchemy.orm import Session +from app.db.session import get_db + +from app.validators.orders import OrderCreate, OrderUpdate, OrderOut +from app.validators.auth import TokenData + +from app.services.orders import ( + create_order_service, + list_orders_service, + get_order_service, + update_order_service, + delete_order_service, + list_orders_by_user_service, + list_my_orders_service, +) + +from app.utils.jwt import ( + get_current_user, + permission_required, +) router = APIRouter() -# --- Order Endpoints --- - -@router.post("/", summary="Create a new order") -def create_order(order_in: dict): - # Customer or Admin - pass - -@router.get("/", summary="List all orders (Admin only)") -def list_orders(): - # Admin only - pass - -@router.get("/me", summary="List orders for current user") -def list_my_orders(): - # Customer only - pass - -@router.get("/{order_id}", summary="Get order by ID") -def get_order(order_id: int): - # Admin or Customer (own) - pass - -@router.put("/{order_id}", summary="Update order by ID") -def update_order(order_id: int, order_update: dict): - # Admin or Customer (own) - pass - -@router.delete("/{order_id}", summary="Delete order by ID") -def delete_order(order_id: int): - # Admin or Customer (own) - pass \ No newline at end of file +# --- Create Order --- +@router.post("/", summary="Create a new order", response_model=OrderOut) +def create_order( + order_in: OrderCreate, + db: Session = Depends(get_db), + current_user: TokenData = Depends(get_current_user), +): + try: + order = create_order_service(db, current_user.user_id, order_in) + return order + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# --- Get Order by ID --- +@router.get("/{order_id}", summary="Get order by ID", response_model=OrderOut) +def get_order( + order_id: int, + db: Session = Depends(get_db), + current_user: TokenData = Depends(get_current_user), +): + try: + order = get_order_service(db, order_id) + + if "can_get_order" not in current_user.permissions and order.user_id != current_user.user_id: + raise HTTPException(status_code=403, detail="Access denied.") + + return order + except HTTPException as e: + raise e + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# --- Update Order --- +@router.put("/{order_id}", summary="Update order by ID", response_model=OrderOut) +def update_order( + order_id: int, + order_update: OrderUpdate, + db: Session = Depends(get_db), + current_user: TokenData = Depends(get_current_user), +): + try: + order = get_order_service(db, order_id) + + if "can_update_order" not in current_user.permissions and order.user_id != current_user.user_id: + raise HTTPException(status_code=403, detail="Access denied.") + + updated_order = update_order_service(db, order_id, order_update) + return updated_order + except HTTPException as e: + raise e + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# --- Delete Order --- +@router.delete("/{order_id}", summary="Delete order by ID", status_code=200) +def delete_order( + order_id: int, + db: Session = Depends(get_db), + current_user: TokenData = Depends(get_current_user), +): + try: + order = get_order_service(db, order_id) + + if "can_delete_order" not in current_user.permissions and order.user_id != current_user.user_id: + raise HTTPException(status_code=403, detail="Access denied.") + + delete_order_service(db, order_id) + return JSONResponse(content={"message": f"Order {order_id} deleted."}) + except HTTPException as e: + raise e + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# --- List All Orders --- +@router.get("/", summary="List all orders", response_model=List[OrderOut]) +def list_orders( + db: Session = Depends(get_db), + current_user: TokenData = Depends(permission_required("can_list_all_orders")), +): + try: + return list_orders_service(db) + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# --- List Orders by Specific User --- +@router.get("/users/{user_id}/orders", summary="List orders by user", response_model=List[OrderOut]) +def list_user_orders( + user_id: int, + db: Session = Depends(get_db), + current_user: TokenData = Depends(permission_required("can_list_user_orders")), +): + try: + return list_orders_by_user_service(db, user_id) + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# --- List Orders of Logged-In Customer --- +@router.get("/me", summary="List own orders", response_model=List[OrderOut]) +def list_my_orders( + db: Session = Depends(get_db), + current_user: TokenData = Depends(get_current_user), +): + try: + return list_my_orders_service(db, current_user.user_id) + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") diff --git a/app/services/orders.py b/app/services/orders.py index e69de29..9d82b46 100644 --- a/app/services/orders.py +++ b/app/services/orders.py @@ -0,0 +1,55 @@ +from sqlalchemy.orm import Session +from fastapi import HTTPException, status + +from app.db.crud.orders import ( + create_order_db, + get_order_by_id, + get_all_orders, + get_orders_by_user_id, + update_order_db, + delete_order_by_id +) +from app.validators.orders import OrderCreate, OrderUpdate + + +def create_order_service(db: Session, user_id: int, order_in: OrderCreate): + return create_order_db(db, user_id, order_in) + + +def list_orders_service(db: Session): + return get_all_orders(db) + + +def list_my_orders_service(db: Session, user_id: int): + return get_orders_by_user_id(db, user_id) + + +def get_order_service(db: Session, order_id: int, current_user_id: int, is_admin: bool): + order = get_order_by_id(db, order_id) + if not order: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") + if not is_admin and order.user_id != current_user_id: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") + return order + + +def update_order_service(db: Session, order_id: int, order_update: OrderUpdate, current_user_id: int, is_admin: bool): + order = get_order_by_id(db, order_id) + if not order: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") + if not is_admin and order.user_id != current_user_id: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") + return update_order_db(db, order_id, order_update) + + +def delete_order_service(db: Session, order_id: int, current_user_id: int, is_admin: bool): + order = get_order_by_id(db, order_id) + if not order: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") + if not is_admin and order.user_id != current_user_id: + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") + delete_order_by_id(db, order_id) + + +def list_orders_by_user_id_service(db: Session, user_id: int): + return get_orders_by_user_id(db, user_id) diff --git a/app/validators/orders.py b/app/validators/orders.py new file mode 100644 index 0000000..67926a0 --- /dev/null +++ b/app/validators/orders.py @@ -0,0 +1,27 @@ +from typing import Annotated, Optional +from pydantic import BaseModel, Field +from decimal import Decimal +from datetime import datetime + + +class OrderCreate(BaseModel): + total_amount: Annotated[Decimal, Field(gt=0, decimal_places=2)] + status: Optional[Annotated[str, Field(max_length=50)]] = "pending" + + +class OrderUpdate(BaseModel): + total_amount: Optional[Annotated[Decimal, Field(gt=0, decimal_places=2)]] = None + status: Optional[Annotated[str, Field(max_length=50)]] = None + + +class OrderOut(BaseModel): + id: int + user_id: int + order_date: datetime + total_amount: Decimal + status: str + created_at: datetime + updated_at: datetime + + class Config: + orm_mode = True From 1a8140b0c2cb502af4c6d2c1c60b877432fedc64 Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Thu, 29 May 2025 10:56:58 +0500 Subject: [PATCH 05/13] customers seeded --- app/db/seed.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/db/seed.py b/app/db/seed.py index f35bbc8..fc2c07f 100644 --- a/app/db/seed.py +++ b/app/db/seed.py @@ -115,6 +115,25 @@ def seed_admin_user(db): print("Admin user created.") +def seed_customer_users(db, n=3): + customer_role = db.query(Role).filter(Role.name == "customer").first() + + customer_usernames = [f"customer{x}" for x in range(n)] + customer_emails = [f"customer{x}@example.com" for x in range(n)] + customer_passwords = [f"password{x}" for x in range(n)] + + for customer_username, customer_email, customer_password in zip(customer_usernames, customer_emails, customer_passwords): + customer_user = User( + username=customer_username, + email=customer_email, + hashed_password=hash_password(customer_password), + role_name=customer_role.name + ) + db.add(customer_user) + db.commit() + print("Customer user created.") + + def seed_all(): db = SessionLocal() try: @@ -123,6 +142,8 @@ def seed_all(): seed_permissions(db) seed_rules(db) seed_admin_user(db) + seed_customer_users(db, n=3) + finally: db.close() From 415074f53395e6df3a4e19f51234250f43c1a4c1 Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Thu, 29 May 2025 11:26:09 +0500 Subject: [PATCH 06/13] order created implemented and tested --- app/db/crud/users.py | 4 +- app/db/seed.py | 8 +- app/routers/orders.py | 215 +++++++++++++++++++++-------------------- app/services/orders.py | 75 +++++++------- app/services/users.py | 2 +- main.py | 6 +- 6 files changed, 158 insertions(+), 152 deletions(-) diff --git a/app/db/crud/users.py b/app/db/crud/users.py index 94aad64..f1b9129 100644 --- a/app/db/crud/users.py +++ b/app/db/crud/users.py @@ -26,8 +26,8 @@ def create_user(db: Session, username: str, email: str, hashed_password: str, ro print("hehehehe2") db.add(user) db.commit() - db.refresh(user) # <-- important to reload with DB generated fields - return user # <-- return the User instance, NOT a string or id + db.refresh(user) + return user def update_user_db(db: Session, user_id: int, user_update: UserUpdate): user = get_user_by_id(db, user_id) diff --git a/app/db/seed.py b/app/db/seed.py index fc2c07f..8b2abfc 100644 --- a/app/db/seed.py +++ b/app/db/seed.py @@ -118,9 +118,9 @@ def seed_admin_user(db): def seed_customer_users(db, n=3): customer_role = db.query(Role).filter(Role.name == "customer").first() - customer_usernames = [f"customer{x}" for x in range(n)] - customer_emails = [f"customer{x}@example.com" for x in range(n)] - customer_passwords = [f"password{x}" for x in range(n)] + customer_usernames = [f"customer{x}" for x in range(1, n+1)] + customer_emails = [f"customer{x}@example.com" for x in range(1,n+1)] + customer_passwords = [f"password{x}" for x in range(1, n+1)] for customer_username, customer_email, customer_password in zip(customer_usernames, customer_emails, customer_passwords): customer_user = User( @@ -143,7 +143,7 @@ def seed_all(): seed_rules(db) seed_admin_user(db) seed_customer_users(db, n=3) - + finally: db.close() diff --git a/app/routers/orders.py b/app/routers/orders.py index 60a530b..29276de 100644 --- a/app/routers/orders.py +++ b/app/routers/orders.py @@ -10,12 +10,12 @@ from app.services.orders import ( create_order_service, - list_orders_service, - get_order_service, - update_order_service, - delete_order_service, - list_orders_by_user_service, - list_my_orders_service, + # list_orders_service, + # get_order_service, + # update_order_service, + # delete_order_service, + # list_orders_by_user_service, + # list_my_orders_service, ) from app.utils.jwt import ( @@ -30,111 +30,114 @@ def create_order( order_in: OrderCreate, db: Session = Depends(get_db), - current_user: TokenData = Depends(get_current_user), + current_user: TokenData = Depends(permission_required("can_create_order")), ): try: + print(f"Creating order for user: {current_user.user_id} with data: {order_in}") order = create_order_service(db, current_user.user_id, order_in) + print(f"Order created successfully: {order}") return order except Exception as e: print(f"Unexpected error: {e}") raise HTTPException(status_code=500, detail="Unexpected error occurred.") - -# --- Get Order by ID --- -@router.get("/{order_id}", summary="Get order by ID", response_model=OrderOut) -def get_order( - order_id: int, - db: Session = Depends(get_db), - current_user: TokenData = Depends(get_current_user), -): - try: - order = get_order_service(db, order_id) - - if "can_get_order" not in current_user.permissions and order.user_id != current_user.user_id: - raise HTTPException(status_code=403, detail="Access denied.") + + +# # --- Get Order by ID --- +# @router.get("/{order_id}", summary="Get order by ID", response_model=OrderOut) +# def get_order( +# order_id: int, +# db: Session = Depends(get_db), +# current_user: TokenData = Depends(get_current_user), +# ): +# try: +# order = get_order_service(db, order_id) + +# if "can_get_order" not in current_user.permissions and order.user_id != current_user.user_id: +# raise HTTPException(status_code=403, detail="Access denied.") - return order - except HTTPException as e: - raise e - except Exception as e: - print(f"Unexpected error: {e}") - raise HTTPException(status_code=500, detail="Unexpected error occurred.") - -# --- Update Order --- -@router.put("/{order_id}", summary="Update order by ID", response_model=OrderOut) -def update_order( - order_id: int, - order_update: OrderUpdate, - db: Session = Depends(get_db), - current_user: TokenData = Depends(get_current_user), -): - try: - order = get_order_service(db, order_id) - - if "can_update_order" not in current_user.permissions and order.user_id != current_user.user_id: - raise HTTPException(status_code=403, detail="Access denied.") - - updated_order = update_order_service(db, order_id, order_update) - return updated_order - except HTTPException as e: - raise e - except Exception as e: - print(f"Unexpected error: {e}") - raise HTTPException(status_code=500, detail="Unexpected error occurred.") - -# --- Delete Order --- -@router.delete("/{order_id}", summary="Delete order by ID", status_code=200) -def delete_order( - order_id: int, - db: Session = Depends(get_db), - current_user: TokenData = Depends(get_current_user), -): - try: - order = get_order_service(db, order_id) - - if "can_delete_order" not in current_user.permissions and order.user_id != current_user.user_id: - raise HTTPException(status_code=403, detail="Access denied.") - - delete_order_service(db, order_id) - return JSONResponse(content={"message": f"Order {order_id} deleted."}) - except HTTPException as e: - raise e - except Exception as e: - print(f"Unexpected error: {e}") - raise HTTPException(status_code=500, detail="Unexpected error occurred.") - -# --- List All Orders --- -@router.get("/", summary="List all orders", response_model=List[OrderOut]) -def list_orders( - db: Session = Depends(get_db), - current_user: TokenData = Depends(permission_required("can_list_all_orders")), -): - try: - return list_orders_service(db) - except Exception as e: - print(f"Unexpected error: {e}") - raise HTTPException(status_code=500, detail="Unexpected error occurred.") - -# --- List Orders by Specific User --- -@router.get("/users/{user_id}/orders", summary="List orders by user", response_model=List[OrderOut]) -def list_user_orders( - user_id: int, - db: Session = Depends(get_db), - current_user: TokenData = Depends(permission_required("can_list_user_orders")), -): - try: - return list_orders_by_user_service(db, user_id) - except Exception as e: - print(f"Unexpected error: {e}") - raise HTTPException(status_code=500, detail="Unexpected error occurred.") - -# --- List Orders of Logged-In Customer --- -@router.get("/me", summary="List own orders", response_model=List[OrderOut]) -def list_my_orders( - db: Session = Depends(get_db), - current_user: TokenData = Depends(get_current_user), -): - try: - return list_my_orders_service(db, current_user.user_id) - except Exception as e: - print(f"Unexpected error: {e}") - raise HTTPException(status_code=500, detail="Unexpected error occurred.") +# return order +# except HTTPException as e: +# raise e +# except Exception as e: +# print(f"Unexpected error: {e}") +# raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# # --- Update Order --- +# @router.put("/{order_id}", summary="Update order by ID", response_model=OrderOut) +# def update_order( +# order_id: int, +# order_update: OrderUpdate, +# db: Session = Depends(get_db), +# current_user: TokenData = Depends(get_current_user), +# ): +# try: +# order = get_order_service(db, order_id) + +# if "can_update_order" not in current_user.permissions and order.user_id != current_user.user_id: +# raise HTTPException(status_code=403, detail="Access denied.") + +# updated_order = update_order_service(db, order_id, order_update) +# return updated_order +# except HTTPException as e: +# raise e +# except Exception as e: +# print(f"Unexpected error: {e}") +# raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# # --- Delete Order --- +# @router.delete("/{order_id}", summary="Delete order by ID", status_code=200) +# def delete_order( +# order_id: int, +# db: Session = Depends(get_db), +# current_user: TokenData = Depends(get_current_user), +# ): +# try: +# order = get_order_service(db, order_id) + +# if "can_delete_order" not in current_user.permissions and order.user_id != current_user.user_id: +# raise HTTPException(status_code=403, detail="Access denied.") + +# delete_order_service(db, order_id) +# return JSONResponse(content={"message": f"Order {order_id} deleted."}) +# except HTTPException as e: +# raise e +# except Exception as e: +# print(f"Unexpected error: {e}") +# raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# # --- List All Orders --- +# @router.get("/", summary="List all orders", response_model=List[OrderOut]) +# def list_orders( +# db: Session = Depends(get_db), +# current_user: TokenData = Depends(permission_required("can_list_all_orders")), +# ): +# try: +# return list_orders_service(db) +# except Exception as e: +# print(f"Unexpected error: {e}") +# raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# # --- List Orders by Specific User --- +# @router.get("/users/{user_id}/orders", summary="List orders by user", response_model=List[OrderOut]) +# def list_user_orders( +# user_id: int, +# db: Session = Depends(get_db), +# current_user: TokenData = Depends(permission_required("can_list_user_orders")), +# ): +# try: +# return list_orders_by_user_service(db, user_id) +# except Exception as e: +# print(f"Unexpected error: {e}") +# raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +# # --- List Orders of Logged-In Customer --- +# @router.get("/me", summary="List own orders", response_model=List[OrderOut]) +# def list_my_orders( +# db: Session = Depends(get_db), +# current_user: TokenData = Depends(get_current_user), +# ): +# try: +# return list_my_orders_service(db, current_user.user_id) +# except Exception as e: +# print(f"Unexpected error: {e}") +# raise HTTPException(status_code=500, detail="Unexpected error occurred.") diff --git a/app/services/orders.py b/app/services/orders.py index 9d82b46..dad0c77 100644 --- a/app/services/orders.py +++ b/app/services/orders.py @@ -2,54 +2,57 @@ from fastapi import HTTPException, status from app.db.crud.orders import ( - create_order_db, - get_order_by_id, - get_all_orders, - get_orders_by_user_id, - update_order_db, - delete_order_by_id + create_order as create_order_db, + # get_order_by_id, + # get_all_orders, + # get_orders_by_user_id, + # update_order_db, + # delete_order_by_id ) from app.validators.orders import OrderCreate, OrderUpdate - def create_order_service(db: Session, user_id: int, order_in: OrderCreate): - return create_order_db(db, user_id, order_in) - + return create_order_db( + db=db, + user_id=user_id, + total_amount=order_in.total_amount, + status=order_in.status + ) -def list_orders_service(db: Session): - return get_all_orders(db) +# def list_orders_service(db: Session): +# return get_all_orders(db) -def list_my_orders_service(db: Session, user_id: int): - return get_orders_by_user_id(db, user_id) +# def list_my_orders_service(db: Session, user_id: int): +# return get_orders_by_user_id(db, user_id) -def get_order_service(db: Session, order_id: int, current_user_id: int, is_admin: bool): - order = get_order_by_id(db, order_id) - if not order: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") - if not is_admin and order.user_id != current_user_id: - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") - return order +# def get_order_service(db: Session, order_id: int, current_user_id: int, is_admin: bool): +# order = get_order_by_id(db, order_id) +# if not order: +# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") +# if not is_admin and order.user_id != current_user_id: +# raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") +# return order -def update_order_service(db: Session, order_id: int, order_update: OrderUpdate, current_user_id: int, is_admin: bool): - order = get_order_by_id(db, order_id) - if not order: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") - if not is_admin and order.user_id != current_user_id: - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") - return update_order_db(db, order_id, order_update) +# def update_order_service(db: Session, order_id: int, order_update: OrderUpdate, current_user_id: int, is_admin: bool): +# order = get_order_by_id(db, order_id) +# if not order: +# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") +# if not is_admin and order.user_id != current_user_id: +# raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") +# return update_order_db(db, order_id, order_update) -def delete_order_service(db: Session, order_id: int, current_user_id: int, is_admin: bool): - order = get_order_by_id(db, order_id) - if not order: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") - if not is_admin and order.user_id != current_user_id: - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") - delete_order_by_id(db, order_id) +# def delete_order_service(db: Session, order_id: int, current_user_id: int, is_admin: bool): +# order = get_order_by_id(db, order_id) +# if not order: +# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") +# if not is_admin and order.user_id != current_user_id: +# raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") +# delete_order_by_id(db, order_id) -def list_orders_by_user_id_service(db: Session, user_id: int): - return get_orders_by_user_id(db, user_id) +# def list_orders_by_user_id_service(db: Session, user_id: int): +# return get_orders_by_user_id(db, user_id) diff --git a/app/services/users.py b/app/services/users.py index 79dfe81..194ef3d 100644 --- a/app/services/users.py +++ b/app/services/users.py @@ -14,7 +14,7 @@ def create_user_service(db: Session, user_in: UserCreate): # Hash the password hashed_pw = hash_password(user_in.password) - print("HEHEHEHHEHEHE") + # Create user in DB return db_create_user( db=db, diff --git a/main.py b/main.py index 07f8acf..c851e6c 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,5 @@ from fastapi import FastAPI -from app.routers import users, auth +from app.routers import users, orders, auth from dotenv import load_dotenv load_dotenv() # Load env variables early @@ -9,9 +9,9 @@ version="1.0.0", ) -app.include_router(users.router, prefix="/users", tags=["Users"]) app.include_router(auth.router, prefix="/auth", tags=["Auth"]) - +app.include_router(users.router, prefix="/users", tags=["Users"]) +app.include_router(orders.router, prefix="/orders", tags=["Orders"]) @app.on_event("startup") def on_startup(): print("🚀 App starting up...") From aea41f1f990acbbfc9b509ea2c357b4ae5afe07d Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Thu, 29 May 2025 11:50:35 +0500 Subject: [PATCH 07/13] slight users.py refactor to include more explicit permissions, testing everything later --- app/db/crud/orders.py | 8 ++++---- app/routers/orders.py | 26 ++++++++++++-------------- app/routers/users.py | 6 +++--- app/services/orders.py | 6 +++--- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/app/db/crud/orders.py b/app/db/crud/orders.py index e490563..47b105c 100644 --- a/app/db/crud/orders.py +++ b/app/db/crud/orders.py @@ -15,14 +15,14 @@ def create_order(db: Session, user_id: int, total_amount: float, status: str = " return order -def get_orders_by_user_id(db: Session, user_id: int) -> list[Order]: - return db.query(Order).filter(Order.user_id == user_id).all() - - def get_all_orders(db: Session) -> list[Order]: return db.query(Order).all() +def get_orders_by_user_id(db: Session, user_id: int) -> list[Order]: + return db.query(Order).filter(Order.user_id == user_id).all() + + def update_order_db(db: Session, order_id: int, order_update: OrderUpdate) -> Order: order = get_order_by_id(db, order_id) if not order: diff --git a/app/routers/orders.py b/app/routers/orders.py index 29276de..fcbd5ee 100644 --- a/app/routers/orders.py +++ b/app/routers/orders.py @@ -10,7 +10,7 @@ from app.services.orders import ( create_order_service, - # list_orders_service, + list_orders_service, # get_order_service, # update_order_service, # delete_order_service, @@ -25,7 +25,6 @@ router = APIRouter() -# --- Create Order --- @router.post("/", summary="Create a new order", response_model=OrderOut) def create_order( order_in: OrderCreate, @@ -42,7 +41,17 @@ def create_order( raise HTTPException(status_code=500, detail="Unexpected error occurred.") -# # --- Get Order by ID --- +@router.get("/", summary="List all orders", response_model=List[OrderOut]) +def list_orders( + db: Session = Depends(get_db), + current_user: TokenData = Depends(permission_required("can_list_all_orders")), +): + try: + return list_orders_service(db) + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") + # @router.get("/{order_id}", summary="Get order by ID", response_model=OrderOut) # def get_order( # order_id: int, @@ -105,17 +114,6 @@ def create_order( # print(f"Unexpected error: {e}") # raise HTTPException(status_code=500, detail="Unexpected error occurred.") -# # --- List All Orders --- -# @router.get("/", summary="List all orders", response_model=List[OrderOut]) -# def list_orders( -# db: Session = Depends(get_db), -# current_user: TokenData = Depends(permission_required("can_list_all_orders")), -# ): -# try: -# return list_orders_service(db) -# except Exception as e: -# print(f"Unexpected error: {e}") -# raise HTTPException(status_code=500, detail="Unexpected error occurred.") # # --- List Orders by Specific User --- # @router.get("/users/{user_id}/orders", summary="List orders by user", response_model=List[OrderOut]) diff --git a/app/routers/users.py b/app/routers/users.py index 2d166cd..cf5a2ec 100644 --- a/app/routers/users.py +++ b/app/routers/users.py @@ -59,7 +59,7 @@ def list_users( @router.get("/me", summary="Get current user's profile", response_model=UserOut) def get_me( db: Session = Depends(get_db), - current_user: TokenData = Depends(get_current_user), + current_user: TokenData = Depends(permission_required("can_get_own_profile")), ): try: user = get_user_service(db, current_user.user_id) @@ -77,7 +77,7 @@ def get_me( def update_me( user_update: UserUpdate, db: Session = Depends(get_db), - current_user: TokenData = Depends(get_current_user), + current_user: TokenData = Depends(permission_required("can_update_own_profile")), ): try: user = update_user_service(db, current_user.user_id, user_update) @@ -90,7 +90,7 @@ def update_me( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Unexpected error occurred.", ) - + @router.get("/{user_id}", summary="Get user by ID", response_model=UserOut) def get_user( user_id: int, diff --git a/app/services/orders.py b/app/services/orders.py index dad0c77..afe6aa1 100644 --- a/app/services/orders.py +++ b/app/services/orders.py @@ -3,8 +3,8 @@ from app.db.crud.orders import ( create_order as create_order_db, + get_all_orders, # get_order_by_id, - # get_all_orders, # get_orders_by_user_id, # update_order_db, # delete_order_by_id @@ -19,8 +19,8 @@ def create_order_service(db: Session, user_id: int, order_in: OrderCreate): status=order_in.status ) -# def list_orders_service(db: Session): -# return get_all_orders(db) +def list_orders_service(db: Session): + return get_all_orders(db) # def list_my_orders_service(db: Session, user_id: int): From 038c4f64d4fa3d36e5c4b79c2e8d655d9f46a502 Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Thu, 29 May 2025 12:13:16 +0500 Subject: [PATCH 08/13] list and post orders implemented successfully --- app/db/seed.py | 24 ++++++++++++++++++------ app/routers/orders.py | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/db/seed.py b/app/db/seed.py index 8b2abfc..138f981 100644 --- a/app/db/seed.py +++ b/app/db/seed.py @@ -64,20 +64,32 @@ def seed_rules(db): admin_role = db.query(Role).filter(Role.name == "admin").first() customer_role = db.query(Role).filter(Role.name == "customer").first() - # Fetch all permissions at once - permission_lookup = { - perm.name: perm for perm in db.query(Permission).all() - } + # # Fetch all permissions at once + # permission_lookup = { + # perm.name: perm for perm in db.query(Permission).all() + # } rules = [ - # Admin - full order management + # Admin - User Management + Rule(role_name=admin_role.name, permission_name="can_create_user"), + Rule(role_name=admin_role.name, permission_name="can_list_users"), + Rule(role_name=admin_role.name, permission_name="can_get_user"), + Rule(role_name=admin_role.name, permission_name="can_update_user"), + Rule(role_name=admin_role.name, permission_name="can_delete_user"), + + # Admin - Order Management Rule(role_name=admin_role.name, permission_name="can_create_order"), Rule(role_name=admin_role.name, permission_name="can_list_orders"), Rule(role_name=admin_role.name, permission_name="can_get_order"), Rule(role_name=admin_role.name, permission_name="can_update_order"), Rule(role_name=admin_role.name, permission_name="can_delete_order"), - # Customer - limited order access + # Customer - Profile Management + Rule(role_name=customer_role.name, permission_name="can_get_own_profile"), + Rule(role_name=customer_role.name, permission_name="can_update_own_profile"), + + # Customer - Order Management + Rule(role_name=customer_role.name, permission_name="can_create_order"), Rule(role_name=customer_role.name, permission_name="can_get_own_orders"), Rule(role_name=customer_role.name, permission_name="can_get_own_order"), ] diff --git a/app/routers/orders.py b/app/routers/orders.py index fcbd5ee..f75e0ba 100644 --- a/app/routers/orders.py +++ b/app/routers/orders.py @@ -44,7 +44,7 @@ def create_order( @router.get("/", summary="List all orders", response_model=List[OrderOut]) def list_orders( db: Session = Depends(get_db), - current_user: TokenData = Depends(permission_required("can_list_all_orders")), + current_user: TokenData = Depends(permission_required("can_list_orders")), ): try: return list_orders_service(db) From 44127c951411cde958ac4286392e1f0d0de76cd0 Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Thu, 29 May 2025 12:46:38 +0500 Subject: [PATCH 09/13] adding checks to users and orders to avoid user being none --- app/db/crud/users.py | 3 +- app/routers/orders.py | 67 ++++++++++++++++++++++++------------------ app/routers/users.py | 4 +++ app/services/orders.py | 17 ++++------- 4 files changed, 49 insertions(+), 42 deletions(-) diff --git a/app/db/crud/users.py b/app/db/crud/users.py index f1b9129..79c99f0 100644 --- a/app/db/crud/users.py +++ b/app/db/crud/users.py @@ -16,14 +16,13 @@ def get_all_users(db: Session): return db.query(User).all() def create_user(db: Session, username: str, email: str, hashed_password: str, role: str = "customer") -> User: - print("hehehehe1") user = User( username=username, email=email, hashed_password=hashed_password, role_name=role ) - print("hehehehe2") + db.add(user) db.commit() db.refresh(user) diff --git a/app/routers/orders.py b/app/routers/orders.py index f75e0ba..9c99b68 100644 --- a/app/routers/orders.py +++ b/app/routers/orders.py @@ -11,11 +11,11 @@ from app.services.orders import ( create_order_service, list_orders_service, - # get_order_service, + list_my_orders_service, + get_order_service, # update_order_service, # delete_order_service, # list_orders_by_user_service, - # list_my_orders_service, ) from app.utils.jwt import ( @@ -52,24 +52,44 @@ def list_orders( print(f"Unexpected error: {e}") raise HTTPException(status_code=500, detail="Unexpected error occurred.") -# @router.get("/{order_id}", summary="Get order by ID", response_model=OrderOut) -# def get_order( -# order_id: int, -# db: Session = Depends(get_db), -# current_user: TokenData = Depends(get_current_user), -# ): -# try: -# order = get_order_service(db, order_id) -# if "can_get_order" not in current_user.permissions and order.user_id != current_user.user_id: -# raise HTTPException(status_code=403, detail="Access denied.") +@router.get("/me", summary="List own orders", response_model=List[OrderOut]) +def list_my_orders( + db: Session = Depends(get_db), + current_user: TokenData = Depends(permission_required("can_get_own_orders")), +): + try: + return list_my_orders_service(db, current_user.user_id) + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Unexpected error occurred." + ) + + +@router.get("/{order_id}", summary="Get order by ID", response_model=OrderOut) +def get_order( + order_id: int, + db: Session = Depends(get_db), + current_user: TokenData = Depends(get_current_user), +): + try: + order = get_order_service(db, order_id) + + if order is None: + raise HTTPException(status_code=404, detail="Order not found.") + + if "can_get_order" not in current_user.permissions and order.user_id != current_user.user_id: + raise HTTPException(status_code=403, detail="Access denied.") -# return order -# except HTTPException as e: -# raise e -# except Exception as e: -# print(f"Unexpected error: {e}") -# raise HTTPException(status_code=500, detail="Unexpected error occurred.") + return order + + except HTTPException as e: + raise e + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") # # --- Update Order --- # @router.put("/{order_id}", summary="Update order by ID", response_model=OrderOut) @@ -128,14 +148,3 @@ def list_orders( # print(f"Unexpected error: {e}") # raise HTTPException(status_code=500, detail="Unexpected error occurred.") -# # --- List Orders of Logged-In Customer --- -# @router.get("/me", summary="List own orders", response_model=List[OrderOut]) -# def list_my_orders( -# db: Session = Depends(get_db), -# current_user: TokenData = Depends(get_current_user), -# ): -# try: -# return list_my_orders_service(db, current_user.user_id) -# except Exception as e: -# print(f"Unexpected error: {e}") -# raise HTTPException(status_code=500, detail="Unexpected error occurred.") diff --git a/app/routers/users.py b/app/routers/users.py index cf5a2ec..eb30730 100644 --- a/app/routers/users.py +++ b/app/routers/users.py @@ -63,6 +63,8 @@ def get_me( ): try: user = get_user_service(db, current_user.user_id) + if user is None: + raise HTTPException(status_code=404, detail="User not found.") return user except HTTPException as e: raise e @@ -104,6 +106,8 @@ def get_user( ) try: user = get_user_service(db, user_id) + if user is None: + raise HTTPException(status_code=404, detail="User not found.") return user except HTTPException as e: raise e diff --git a/app/services/orders.py b/app/services/orders.py index afe6aa1..d1a85ac 100644 --- a/app/services/orders.py +++ b/app/services/orders.py @@ -4,8 +4,8 @@ from app.db.crud.orders import ( create_order as create_order_db, get_all_orders, - # get_order_by_id, - # get_orders_by_user_id, + get_orders_by_user_id, + get_order_by_id, # update_order_db, # delete_order_by_id ) @@ -23,17 +23,12 @@ def list_orders_service(db: Session): return get_all_orders(db) -# def list_my_orders_service(db: Session, user_id: int): -# return get_orders_by_user_id(db, user_id) +def list_my_orders_service(db: Session, user_id: int): + return get_orders_by_user_id(db, user_id) -# def get_order_service(db: Session, order_id: int, current_user_id: int, is_admin: bool): -# order = get_order_by_id(db, order_id) -# if not order: -# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") -# if not is_admin and order.user_id != current_user_id: -# raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") -# return order +def get_order_service(db: Session, order_id: int): + return get_order_by_id(db, order_id) # def update_order_service(db: Session, order_id: int, order_update: OrderUpdate, current_user_id: int, is_admin: bool): From 064a55db806769a18ad37b91bc2b4ab9be00dfb8 Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Thu, 29 May 2025 12:56:14 +0500 Subject: [PATCH 10/13] update order checked and implemented --- app/routers/orders.py | 55 +++++++++++++++--------------------------- app/services/orders.py | 11 +++------ 2 files changed, 23 insertions(+), 43 deletions(-) diff --git a/app/routers/orders.py b/app/routers/orders.py index 9c99b68..ac83e92 100644 --- a/app/routers/orders.py +++ b/app/routers/orders.py @@ -13,7 +13,7 @@ list_orders_service, list_my_orders_service, get_order_service, - # update_order_service, + update_order_service, # delete_order_service, # list_orders_by_user_service, ) @@ -91,27 +91,27 @@ def get_order( print(f"Unexpected error: {e}") raise HTTPException(status_code=500, detail="Unexpected error occurred.") -# # --- Update Order --- -# @router.put("/{order_id}", summary="Update order by ID", response_model=OrderOut) -# def update_order( -# order_id: int, -# order_update: OrderUpdate, -# db: Session = Depends(get_db), -# current_user: TokenData = Depends(get_current_user), -# ): -# try: -# order = get_order_service(db, order_id) -# if "can_update_order" not in current_user.permissions and order.user_id != current_user.user_id: -# raise HTTPException(status_code=403, detail="Access denied.") +@router.put("/{order_id}", summary="Update order by ID", response_model=OrderOut) +def update_order( + order_id: int, + order_update: OrderUpdate, + db: Session = Depends(get_db), + current_user: TokenData = Depends(get_current_user), +): + try: + order = get_order_service(db, order_id) -# updated_order = update_order_service(db, order_id, order_update) -# return updated_order -# except HTTPException as e: -# raise e -# except Exception as e: -# print(f"Unexpected error: {e}") -# raise HTTPException(status_code=500, detail="Unexpected error occurred.") + if "can_update_order" not in current_user.permissions and order.user_id != current_user.user_id: + raise HTTPException(status_code=403, detail="Access denied.") + + updated_order = update_order_service(db, order_id, order_update) + return updated_order + except HTTPException as e: + raise e + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException(status_code=500, detail="Unexpected error occurred.") # # --- Delete Order --- # @router.delete("/{order_id}", summary="Delete order by ID", status_code=200) @@ -133,18 +133,3 @@ def get_order( # except Exception as e: # print(f"Unexpected error: {e}") # raise HTTPException(status_code=500, detail="Unexpected error occurred.") - - -# # --- List Orders by Specific User --- -# @router.get("/users/{user_id}/orders", summary="List orders by user", response_model=List[OrderOut]) -# def list_user_orders( -# user_id: int, -# db: Session = Depends(get_db), -# current_user: TokenData = Depends(permission_required("can_list_user_orders")), -# ): -# try: -# return list_orders_by_user_service(db, user_id) -# except Exception as e: -# print(f"Unexpected error: {e}") -# raise HTTPException(status_code=500, detail="Unexpected error occurred.") - diff --git a/app/services/orders.py b/app/services/orders.py index d1a85ac..717824a 100644 --- a/app/services/orders.py +++ b/app/services/orders.py @@ -6,7 +6,7 @@ get_all_orders, get_orders_by_user_id, get_order_by_id, - # update_order_db, + update_order_db, # delete_order_by_id ) from app.validators.orders import OrderCreate, OrderUpdate @@ -31,13 +31,8 @@ def get_order_service(db: Session, order_id: int): return get_order_by_id(db, order_id) -# def update_order_service(db: Session, order_id: int, order_update: OrderUpdate, current_user_id: int, is_admin: bool): -# order = get_order_by_id(db, order_id) -# if not order: -# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") -# if not is_admin and order.user_id != current_user_id: -# raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") -# return update_order_db(db, order_id, order_update) +def update_order_service(db: Session, order_id: int, order_update: OrderUpdate): + return update_order_db(db, order_id, order_update) # def delete_order_service(db: Session, order_id: int, current_user_id: int, is_admin: bool): From 16cc200f7ac0d2ecaea036d53a0fac2612bc243e Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Thu, 29 May 2025 13:29:56 +0500 Subject: [PATCH 11/13] final testing pending, last route to be properly implemented (/users/{user_id}/orders) --- app/db/crud/orders.py | 2 ++ app/db/crud/users.py | 2 +- app/routers/orders.py | 60 ++++++++++++++++++++++++++---------------- app/routers/users.py | 24 ++++++++++++----- app/services/orders.py | 16 +++-------- app/services/users.py | 8 ++++++ 6 files changed, 71 insertions(+), 41 deletions(-) diff --git a/app/db/crud/orders.py b/app/db/crud/orders.py index 47b105c..c5e7c37 100644 --- a/app/db/crud/orders.py +++ b/app/db/crud/orders.py @@ -20,6 +20,7 @@ def get_all_orders(db: Session) -> list[Order]: def get_orders_by_user_id(db: Session, user_id: int) -> list[Order]: + print(user_id) return db.query(Order).filter(Order.user_id == user_id).all() @@ -42,3 +43,4 @@ def delete_order_by_id(db: Session, order_id: int): if order: db.delete(order) db.commit() + return \ No newline at end of file diff --git a/app/db/crud/users.py b/app/db/crud/users.py index 79c99f0..a39fd32 100644 --- a/app/db/crud/users.py +++ b/app/db/crud/users.py @@ -49,4 +49,4 @@ def delete_user_by_id(db: Session, user_id: int): user = get_user_by_id(db, user_id) if user: db.delete(user) - db.commit() + db.commit() \ No newline at end of file diff --git a/app/routers/orders.py b/app/routers/orders.py index ac83e92..951da87 100644 --- a/app/routers/orders.py +++ b/app/routers/orders.py @@ -14,8 +14,7 @@ list_my_orders_service, get_order_service, update_order_service, - # delete_order_service, - # list_orders_by_user_service, + delete_order_service, ) from app.utils.jwt import ( @@ -113,23 +112,40 @@ def update_order( print(f"Unexpected error: {e}") raise HTTPException(status_code=500, detail="Unexpected error occurred.") -# # --- Delete Order --- -# @router.delete("/{order_id}", summary="Delete order by ID", status_code=200) -# def delete_order( -# order_id: int, -# db: Session = Depends(get_db), -# current_user: TokenData = Depends(get_current_user), -# ): -# try: -# order = get_order_service(db, order_id) - -# if "can_delete_order" not in current_user.permissions and order.user_id != current_user.user_id: -# raise HTTPException(status_code=403, detail="Access denied.") - -# delete_order_service(db, order_id) -# return JSONResponse(content={"message": f"Order {order_id} deleted."}) -# except HTTPException as e: -# raise e -# except Exception as e: -# print(f"Unexpected error: {e}") -# raise HTTPException(status_code=500, detail="Unexpected error occurred.") + +@router.delete("/{order_id}", summary="Delete order by ID", status_code=200) +def delete_order( + order_id: int, + db: Session = Depends(get_db), + current_user: TokenData = Depends(get_current_user), +): + try: + # First check if order exists + order = get_order_service(db, order_id) + if not order: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Order with id {order_id} not found" + ) + + # Check permissions + if "can_delete_order" not in current_user.permissions and order.user_id != current_user.user_id: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail="Access denied." + ) + + # Delete order + delete_order_service(db, order_id) + return JSONResponse( + status_code=status.HTTP_200_OK, + content={"message": f"Order {order_id} deleted."} + ) + except HTTPException as e: + raise e + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Unexpected error occurred." + ) \ No newline at end of file diff --git a/app/routers/users.py b/app/routers/users.py index eb30730..f9a2bad 100644 --- a/app/routers/users.py +++ b/app/routers/users.py @@ -6,6 +6,7 @@ from app.db.session import get_db from app.validators.users import UserCreate, UserUpdate, UserOut +from app.validators.orders import OrderOut from app.validators.auth import TokenData from app.services.users import ( @@ -14,6 +15,7 @@ get_user_service, delete_user_service, update_user_service, + list_orders_by_user_service, ) from app.utils.jwt import ( @@ -163,9 +165,19 @@ def delete_user( ) -# @router.get("/{user_id}/orders", summary="List orders by user (Admin only)") -# def list_user_orders( -# user_id: int, current_user: TokenData = Depends(admin_required) -# ): -# # Implement orders fetching logic here, admin only -# pass +@router.get("/users/{user_id}/orders", summary="List orders by user", response_model=List[OrderOut]) +def list_user_orders( + user_id: int, + db: Session = Depends(get_db), + current_user: TokenData = Depends(permission_required("can_list_orders")), +): + try: + orders = list_orders_by_user_service(db, user_id) + return orders + except Exception as e: + print(f"Unexpected error: {e}") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Unexpected error occurred.", + ) + diff --git a/app/services/orders.py b/app/services/orders.py index 717824a..ff0a6e8 100644 --- a/app/services/orders.py +++ b/app/services/orders.py @@ -7,8 +7,9 @@ get_orders_by_user_id, get_order_by_id, update_order_db, - # delete_order_by_id + delete_order_by_id ) + from app.validators.orders import OrderCreate, OrderUpdate def create_order_service(db: Session, user_id: int, order_in: OrderCreate): @@ -35,14 +36,5 @@ def update_order_service(db: Session, order_id: int, order_update: OrderUpdate): return update_order_db(db, order_id, order_update) -# def delete_order_service(db: Session, order_id: int, current_user_id: int, is_admin: bool): -# order = get_order_by_id(db, order_id) -# if not order: -# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Order not found") -# if not is_admin and order.user_id != current_user_id: -# raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Access denied") -# delete_order_by_id(db, order_id) - - -# def list_orders_by_user_id_service(db: Session, user_id: int): -# return get_orders_by_user_id(db, user_id) +def delete_order_service(db: Session, order_id: int): + delete_order_by_id(db, order_id) \ No newline at end of file diff --git a/app/services/users.py b/app/services/users.py index 194ef3d..0d7c748 100644 --- a/app/services/users.py +++ b/app/services/users.py @@ -4,6 +4,7 @@ from fastapi import HTTPException, status from app.utils.security import hash_password + def create_user_service(db: Session, user_in: UserCreate): # Check if user exists by email or username if get_user_by_email(db, user_in.email): @@ -42,3 +43,10 @@ def delete_user_service(db: Session, user_id: int): def update_user_service(db: Session, user_id: int, user_update: UserUpdate): return update_user_db(db, user_id, user_update) + +from app.db.crud.orders import get_orders_by_user_id +from app.db.models import Order +from typing import List + +def list_orders_by_user_service(db: Session, user_id: int) -> List[Order]: + return get_orders_by_user_id(db, user_id) From 870f4aec8a84fa799468cec168ecc3eeeaae17c0 Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Fri, 30 May 2025 15:59:23 +0500 Subject: [PATCH 12/13] route fixed, users/userid/orders now working --- app/db/crud/orders.py | 1 + app/routers/users.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/db/crud/orders.py b/app/db/crud/orders.py index c5e7c37..2d317df 100644 --- a/app/db/crud/orders.py +++ b/app/db/crud/orders.py @@ -21,6 +21,7 @@ def get_all_orders(db: Session) -> list[Order]: def get_orders_by_user_id(db: Session, user_id: int) -> list[Order]: print(user_id) + print("HEHEHEHEHEHEH") return db.query(Order).filter(Order.user_id == user_id).all() diff --git a/app/routers/users.py b/app/routers/users.py index f9a2bad..227605e 100644 --- a/app/routers/users.py +++ b/app/routers/users.py @@ -165,7 +165,7 @@ def delete_user( ) -@router.get("/users/{user_id}/orders", summary="List orders by user", response_model=List[OrderOut]) +@router.get("/{user_id}/orders", summary="List orders by user", response_model=List[OrderOut]) def list_user_orders( user_id: int, db: Session = Depends(get_db), From 07b87d039d05ce39520861c125eeacfd027258b5 Mon Sep 17 00:00:00 2001 From: Muhammad Raza Bhatti Date: Fri, 30 May 2025 16:19:18 +0500 Subject: [PATCH 13/13] changed comments, and some formatting as finishing touches. --- .python-version | 2 +- app/db/alembic/env.py | 1 - app/db/crud/orders.py | 3 --- app/db/crud/users.py | 6 ++++++ app/db/seed.py | 8 +------- app/routers/auth.py | 3 +-- app/routers/orders.py | 3 --- app/routers/users.py | 6 ++++++ app/services/auth.py | 2 ++ app/services/orders.py | 1 + app/services/users.py | 8 +++++--- app/utils/jwt.py | 3 +++ app/utils/security.py | 1 + app/validators/auth.py | 2 +- app/validators/orders.py | 1 - app/validators/users.py | 2 ++ main.py | 3 +++ 17 files changed, 33 insertions(+), 22 deletions(-) diff --git a/.python-version b/.python-version index 47fb549..233d4f0 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -apivenv +3.10.17 \ No newline at end of file diff --git a/app/db/alembic/env.py b/app/db/alembic/env.py index fe81294..260fa93 100644 --- a/app/db/alembic/env.py +++ b/app/db/alembic/env.py @@ -16,7 +16,6 @@ from app.db.base import Base def import_all_models(): - # Correct the path to the models directory models_dir = os.path.join(os.path.dirname(__file__), "../models") models_dir = os.path.abspath(models_dir) diff --git a/app/db/crud/orders.py b/app/db/crud/orders.py index 2d317df..fdbbcc7 100644 --- a/app/db/crud/orders.py +++ b/app/db/crud/orders.py @@ -2,7 +2,6 @@ from app.db.models import Order from app.validators.orders import OrderUpdate - def get_order_by_id(db: Session, order_id: int) -> Order | None: return db.query(Order).filter(Order.id == order_id).first() @@ -20,8 +19,6 @@ def get_all_orders(db: Session) -> list[Order]: def get_orders_by_user_id(db: Session, user_id: int) -> list[Order]: - print(user_id) - print("HEHEHEHEHEHEH") return db.query(Order).filter(Order.user_id == user_id).all() diff --git a/app/db/crud/users.py b/app/db/crud/users.py index a39fd32..8f67022 100644 --- a/app/db/crud/users.py +++ b/app/db/crud/users.py @@ -6,15 +6,19 @@ def get_user_by_id(db: Session, user_id: int) -> User | None: return db.query(User).filter(User.id == user_id).first() + def get_user_by_email(db: Session, email: str) -> User | None: return db.query(User).filter(User.email == email).first() + def get_user_by_username(db: Session, username: str) -> User | None: return db.query(User).filter(User.username == username).first() + def get_all_users(db: Session): return db.query(User).all() + def create_user(db: Session, username: str, email: str, hashed_password: str, role: str = "customer") -> User: user = User( username=username, @@ -28,6 +32,7 @@ def create_user(db: Session, username: str, email: str, hashed_password: str, ro db.refresh(user) return user + def update_user_db(db: Session, user_id: int, user_update: UserUpdate): user = get_user_by_id(db, user_id) if not user: @@ -45,6 +50,7 @@ def update_user_db(db: Session, user_id: int, user_update: UserUpdate): db.refresh(user) return user + def delete_user_by_id(db: Session, user_id: int): user = get_user_by_id(db, user_id) if user: diff --git a/app/db/seed.py b/app/db/seed.py index 138f981..9c18262 100644 --- a/app/db/seed.py +++ b/app/db/seed.py @@ -8,7 +8,7 @@ from dotenv import load_dotenv from sqlalchemy import text -load_dotenv() # Load environment variables from .env file +load_dotenv() def clear_tables(db): # Truncate with restart identity to reset auto-increment IDs @@ -60,15 +60,9 @@ def seed_permissions(db): def seed_rules(db): - # Fetch roles admin_role = db.query(Role).filter(Role.name == "admin").first() customer_role = db.query(Role).filter(Role.name == "customer").first() - # # Fetch all permissions at once - # permission_lookup = { - # perm.name: perm for perm in db.query(Permission).all() - # } - rules = [ # Admin - User Management Rule(role_name=admin_role.name, permission_name="can_create_user"), diff --git a/app/routers/auth.py b/app/routers/auth.py index 8c9c617..801c0d2 100644 --- a/app/routers/auth.py +++ b/app/routers/auth.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, HTTPException, status +from fastapi import APIRouter, Depends, HTTPException from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.orm import Session from app.db.session import get_db @@ -18,7 +18,6 @@ def login( if not user: raise HTTPException(status_code=401, detail="Invalid credentials") - # Fetch permissions for user's role from DB permissions = get_permissions_for_role(db, user.role_name) user_data = { diff --git a/app/routers/orders.py b/app/routers/orders.py index 951da87..30bc828 100644 --- a/app/routers/orders.py +++ b/app/routers/orders.py @@ -120,7 +120,6 @@ def delete_order( current_user: TokenData = Depends(get_current_user), ): try: - # First check if order exists order = get_order_service(db, order_id) if not order: raise HTTPException( @@ -128,14 +127,12 @@ def delete_order( detail=f"Order with id {order_id} not found" ) - # Check permissions if "can_delete_order" not in current_user.permissions and order.user_id != current_user.user_id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail="Access denied." ) - # Delete order delete_order_service(db, order_id) return JSONResponse( status_code=status.HTTP_200_OK, diff --git a/app/routers/users.py b/app/routers/users.py index 227605e..2b9e8c8 100644 --- a/app/routers/users.py +++ b/app/routers/users.py @@ -43,6 +43,7 @@ def create_user( detail="Unexpected error occurred.", ) + @router.get("/", summary="List all users", response_model=List[UserOut]) def list_users( db: Session = Depends(get_db), @@ -58,6 +59,7 @@ def list_users( detail="Unexpected error occurred.", ) + @router.get("/me", summary="Get current user's profile", response_model=UserOut) def get_me( db: Session = Depends(get_db), @@ -77,6 +79,7 @@ def get_me( detail="Unexpected error occurred.", ) + @router.put("/me", summary="Update current user's profile", response_model=UserOut) def update_me( user_update: UserUpdate, @@ -95,6 +98,7 @@ def update_me( detail="Unexpected error occurred.", ) + @router.get("/{user_id}", summary="Get user by ID", response_model=UserOut) def get_user( user_id: int, @@ -120,6 +124,7 @@ def get_user( detail="Unexpected error occurred.", ) + @router.put("/{user_id}", summary="Update user by ID", response_model=UserOut) def update_user( user_id: int, @@ -144,6 +149,7 @@ def update_user( detail="Unexpected error occurred.", ) + @router.delete("/{user_id}", summary="Delete user by ID", status_code=200) def delete_user( user_id: int, diff --git a/app/services/auth.py b/app/services/auth.py index 587b3ac..b0faef9 100644 --- a/app/services/auth.py +++ b/app/services/auth.py @@ -6,6 +6,7 @@ from datetime import timedelta from app.utils.security import verify_password + def authenticate_user(db, username: str, password: str): user = get_user_by_username(db, username) if not user: @@ -24,6 +25,7 @@ def get_permissions_for_role(db: Session, role_name: str) -> list[str]: ) return [perm.permission_name for perm in permissions] + def create_token_for_user(db: Session, user): permissions = get_permissions_for_role(db, user.role_name) diff --git a/app/services/orders.py b/app/services/orders.py index ff0a6e8..2daa506 100644 --- a/app/services/orders.py +++ b/app/services/orders.py @@ -20,6 +20,7 @@ def create_order_service(db: Session, user_id: int, order_in: OrderCreate): status=order_in.status ) + def list_orders_service(db: Session): return get_all_orders(db) diff --git a/app/services/users.py b/app/services/users.py index 0d7c748..e4ff372 100644 --- a/app/services/users.py +++ b/app/services/users.py @@ -6,17 +6,14 @@ def create_user_service(db: Session, user_in: UserCreate): - # Check if user exists by email or username if get_user_by_email(db, user_in.email): raise ValueError("Email is already in use.") if get_user_by_username(db, user_in.username): raise ValueError("Username is already taken.") - # Hash the password hashed_pw = hash_password(user_in.password) - # Create user in DB return db_create_user( db=db, username=user_in.username, @@ -25,21 +22,25 @@ def create_user_service(db: Session, user_in: UserCreate): role=user_in.role ) + def list_users_service(db: Session): return get_all_users(db) + def get_user_service(db: Session, user_id: int): user = get_user_by_id(db, user_id) if not user: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found") return user + def delete_user_service(db: Session, user_id: int): user = get_user_by_id(db, user_id) if not user: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found") delete_user_by_id(db, user_id) + def update_user_service(db: Session, user_id: int, user_update: UserUpdate): return update_user_db(db, user_id, user_update) @@ -48,5 +49,6 @@ def update_user_service(db: Session, user_id: int, user_update: UserUpdate): from app.db.models import Order from typing import List + def list_orders_by_user_service(db: Session, user_id: int) -> List[Order]: return get_orders_by_user_id(db, user_id) diff --git a/app/utils/jwt.py b/app/utils/jwt.py index cdf2304..13cc6c4 100644 --- a/app/utils/jwt.py +++ b/app/utils/jwt.py @@ -19,6 +19,7 @@ def create_token(data: dict, expires_delta: datetime.timedelta) -> str: to_encode["exp"] = datetime.datetime.utcnow() + expires_delta return jwt.encode(to_encode, JWT_SECRET, algorithm=JWT_ALGORITHM) + def create_access_token(user: dict) -> str: return create_token( data={ @@ -40,6 +41,7 @@ def create_refresh_token(user: dict) -> str: expires_delta=datetime.timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS) ) + def decode_token(token: str) -> dict: try: payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM]) @@ -51,6 +53,7 @@ def decode_token(token: str) -> dict: headers={"WWW-Authenticate": "Bearer"}, ) + def get_current_user(token: str = Depends(oauth2_scheme)) -> TokenData: payload = decode_token(token) if payload.get("type") != "access": diff --git a/app/utils/security.py b/app/utils/security.py index f57fe04..72dd533 100644 --- a/app/utils/security.py +++ b/app/utils/security.py @@ -5,5 +5,6 @@ def hash_password(password: str) -> str: return pwd_context.hash(password) + def verify_password(plain_password: str, hashed_password: str) -> bool: return pwd_context.verify(plain_password, hashed_password) \ No newline at end of file diff --git a/app/validators/auth.py b/app/validators/auth.py index 09fc1ac..7000c94 100644 --- a/app/validators/auth.py +++ b/app/validators/auth.py @@ -6,6 +6,6 @@ class TokenData(BaseModel): role: str permissions: List[str] - + class RefreshTokenRequest(BaseModel): refresh_token: str diff --git a/app/validators/orders.py b/app/validators/orders.py index 67926a0..0e624f0 100644 --- a/app/validators/orders.py +++ b/app/validators/orders.py @@ -3,7 +3,6 @@ from decimal import Decimal from datetime import datetime - class OrderCreate(BaseModel): total_amount: Annotated[Decimal, Field(gt=0, decimal_places=2)] status: Optional[Annotated[str, Field(max_length=50)]] = "pending" diff --git a/app/validators/users.py b/app/validators/users.py index 8ea2976..a7a5995 100644 --- a/app/validators/users.py +++ b/app/validators/users.py @@ -8,10 +8,12 @@ class UserCreate(BaseModel): password: Annotated[str, constr(min_length=6, max_length=255)] role: str = "customer" + class UserUpdate(BaseModel): username: Optional[str] = Field(None, min_length=3, max_length=255) email: Optional[EmailStr] = None + class UserOut(BaseModel): id: int username: str diff --git a/main.py b/main.py index c851e6c..fbe3b88 100644 --- a/main.py +++ b/main.py @@ -12,10 +12,13 @@ app.include_router(auth.router, prefix="/auth", tags=["Auth"]) app.include_router(users.router, prefix="/users", tags=["Users"]) app.include_router(orders.router, prefix="/orders", tags=["Orders"]) + + @app.on_event("startup") def on_startup(): print("🚀 App starting up...") + @app.on_event("shutdown") def on_shutdown(): print("🛑 App shutting down.")