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 110d953..fdbbcc7 100644 --- a/app/db/crud/orders.py +++ b/app/db/crud/orders.py @@ -1,21 +1,44 @@ 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_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: + 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: 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 ec20710..8f67022 100644 --- a/app/db/crud/users.py +++ b/app/db/crud/users.py @@ -6,27 +6,33 @@ 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, email=email, hashed_password=hashed_password, - role=role + role_name=role ) + db.add(user) db.commit() 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: @@ -44,8 +50,9 @@ 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: db.delete(user) - db.commit() + db.commit() \ No newline at end of file diff --git a/app/db/seed.py b/app/db/seed.py index 4aaa1cb..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 @@ -37,43 +37,55 @@ 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() 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 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() - 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 - 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 - 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"), ] for rule in rules: @@ -109,6 +121,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(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( + 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: @@ -117,6 +148,8 @@ def seed_all(): seed_permissions(db) seed_rules(db) seed_admin_user(db) + seed_customer_users(db, n=3) + finally: db.close() 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 ff13515..30bc828 100644 --- a/app/routers/orders.py +++ b/app/routers/orders.py @@ -1,36 +1,148 @@ 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, + list_my_orders_service, + get_order_service, + update_order_service, + delete_order_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 +@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(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.") + + +@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_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("/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.") + + +@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.") + + +@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 not order: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Order with id {order_id} not found" + ) + + 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_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 044fa6e..2b9e8c8 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 ( @@ -27,7 +29,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) @@ -41,10 +43,11 @@ 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), - current_user: TokenData = Depends(permission_required("list_users")), + current_user: TokenData = Depends(permission_required("can_list_users")), ): try: users = list_users_service(db) @@ -56,13 +59,16 @@ 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), - 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) + if user is None: + raise HTTPException(status_code=404, detail="User not found.") return user except HTTPException as e: raise e @@ -73,11 +79,12 @@ 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, 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,6 +97,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( @@ -97,13 +105,15 @@ 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.", ) 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 @@ -114,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, @@ -121,7 +132,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.", @@ -138,11 +149,12 @@ 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, 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) @@ -159,9 +171,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("/{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/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 e69de29..2daa506 100644 --- a/app/services/orders.py +++ b/app/services/orders.py @@ -0,0 +1,41 @@ +from sqlalchemy.orm import Session +from fastapi import HTTPException, status + +from app.db.crud.orders import ( + create_order as create_order_db, + get_all_orders, + get_orders_by_user_id, + get_order_by_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=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_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): + return get_order_by_id(db, order_id) + + +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): + 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..e4ff372 100644 --- a/app/services/users.py +++ b/app/services/users.py @@ -4,18 +4,16 @@ 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): 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, @@ -24,21 +22,33 @@ 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) + +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) diff --git a/app/utils/jwt.py b/app/utils/jwt.py index 7a7af61..13cc6c4 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") @@ -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 new file mode 100644 index 0000000..0e624f0 --- /dev/null +++ b/app/validators/orders.py @@ -0,0 +1,26 @@ +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 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 diff --git a/main.py b/main.py index 07f8acf..fbe3b88 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,13 +9,16 @@ 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...") + @app.on_event("shutdown") def on_shutdown(): print("🛑 App shutting down.")