| @@ -33,7 +33,19 @@ OR | |||||
| ``` | ``` | ||||
| python3 -m uvicorn main:app --reload | python3 -m uvicorn main:app --reload | ||||
| ``` | ``` | ||||
| ## Explaining the file structure | |||||
| ``` | |||||
| app //main app | |||||
| |-alembic //Alembic -- database migration manager. Helps keep databases in sync and changeable (handles all SQL logic and keeps everything up-to-date) | |||||
| | |- //All files irrelevant | |||||
| |-apis //Stores the actual API Endpoints. | |||||
| | |-v1 //Main API endpoints | |||||
| |-core //Core project components | |||||
| |-db //Stores database information and data | |||||
| | |-models //Stores database models (represents SQL Tables) | |||||
| | |-repository //Stores scripts to create, update and interact with the database | |||||
| |-schemas //Stores Pydantic data models (Kind of like db/models except for use in the API itself, not just the database. Uses for data validation and stuff) | |||||
| ``` | |||||
| ## Git Guide | ## Git Guide | ||||
| - [Git Reference](http://git.github.io/git-reference): despite its name it is more of a user guide. | - [Git Reference](http://git.github.io/git-reference): despite its name it is more of a user guide. | ||||
| - ["Pro Git" Book](http://git-scm.com/book): by a core developer, also a thorough user guide. | - ["Pro Git" Book](http://git-scm.com/book): by a core developer, also a thorough user guide. | ||||
| @@ -1,7 +1,8 @@ | |||||
| # Base API router -- collecting all APIs here to not clutter main.py | # Base API router -- collecting all APIs here to not clutter main.py | ||||
| from fastapi import APIRouter | from fastapi import APIRouter | ||||
| from apis.v1 import route_user | |||||
| from apis.v1 import route_user, route_vehicle | |||||
| api_router = APIRouter() | api_router = APIRouter() | ||||
| api_router.include_router(route_user.router, prefix="/user", tags=["users"]) | api_router.include_router(route_user.router, prefix="/user", tags=["users"]) | ||||
| api_router.include_router(route_vehicle.router, prefix="/vehicle", tags=["vehicles"]) | |||||
| @@ -2,10 +2,11 @@ | |||||
| from fastapi import APIRouter, status | from fastapi import APIRouter, status | ||||
| from sqlalchemy.orm import Session | from sqlalchemy.orm import Session | ||||
| from fastapi import Depends | from fastapi import Depends | ||||
| from typing import List | |||||
| from schemas.user import UserCreate, ShowUser | from schemas.user import UserCreate, ShowUser | ||||
| from db.session import get_db | from db.session import get_db | ||||
| from db.repository.user import create_new_user | |||||
| from db.repository.user import create_new_user, list_users | |||||
| router = APIRouter() | router = APIRouter() | ||||
| @@ -15,3 +16,12 @@ router = APIRouter() | |||||
| def create_user(user: UserCreate, db: Session = Depends(get_db)): | def create_user(user: UserCreate, db: Session = Depends(get_db)): | ||||
| user = create_new_user(user=user, db=db) | user = create_new_user(user=user, db=db) | ||||
| return user | return user | ||||
| @router.get("/", response_model=List[ShowUser], status_code=status.HTTP_200_OK) | |||||
| def get_all_users(db: Session = Depends(get_db), role: str = None): | |||||
| if role == None: | |||||
| users = list_users(db=db) | |||||
| return users | |||||
| users = list_users(db=db, role=role) | |||||
| return users | |||||
| @@ -0,0 +1,48 @@ | |||||
| from fastapi import APIRouter, status, HTTPException | |||||
| from sqlalchemy.orm import Session | |||||
| from fastapi import Depends | |||||
| from typing import List | |||||
| from db.session import get_db | |||||
| from schemas.vehicle import OutputVehicle, CreateVehicle | |||||
| from db.repository.vehicle import ( | |||||
| create_new_vehicle, | |||||
| assign_vehicle_driver, | |||||
| list_vehicles, | |||||
| ) | |||||
| router = APIRouter() | |||||
| @router.post("/new", response_model=OutputVehicle, status_code=status.HTTP_201_CREATED) | |||||
| async def create_vehicle(vehicle: CreateVehicle, db: Session = Depends(get_db)): | |||||
| vehicle = create_new_vehicle(vehicle=vehicle, db=db) | |||||
| return vehicle | |||||
| @router.get( | |||||
| "/assign/{vehicle_id}/{driver_id}", | |||||
| response_model=OutputVehicle, | |||||
| status_code=status.HTTP_200_OK, | |||||
| ) | |||||
| async def assign_drver(vehicle_id: int, driver_id: int, db: Session = Depends(get_db)): | |||||
| vehicle = assign_vehicle_driver(vehicle_id=vehicle_id, driver_id=driver_id, db=db) | |||||
| if vehicle == "nodriver": | |||||
| raise HTTPException( | |||||
| status_code=404, detail=f"Driver with id {driver_id} not found" | |||||
| ) | |||||
| if vehicle == "novehicle": | |||||
| raise HTTPException( | |||||
| status_code=404, detail=f"Vehicle with id {vehicle_id} not found" | |||||
| ) | |||||
| if vehicle == "alreadyassigned": | |||||
| raise HTTPException( | |||||
| status_code=400, | |||||
| detail=f"Driver with id {driver_id} is already assigned to vehicle with id {vehicle_id}", | |||||
| ) | |||||
| return vehicle | |||||
| @router.get("/", response_model=List[OutputVehicle], status_code=status.HTTP_200_OK) | |||||
| async def get_all_vehicles(db: Session = Depends(get_db)): | |||||
| vehicles = list_vehicles(db=db) | |||||
| return vehicles | |||||
| @@ -21,3 +21,17 @@ def create_new_user(user: UserCreate, db: Session): | |||||
| db.commit() | db.commit() | ||||
| db.refresh(user) | db.refresh(user) | ||||
| return user | return user | ||||
| def verify_driver_exists(driver_id: int, db: Session): | |||||
| driver = db.query(User).filter(User.Id == driver_id).first() | |||||
| if not driver: | |||||
| return False | |||||
| if driver.Role != "Driver": | |||||
| return False | |||||
| return True | |||||
| def list_users(db: Session, role: str = "Any"): | |||||
| users = db.query(User).filter((User.Role == role) | (role == "Any")).all() | |||||
| return users | |||||
| @@ -0,0 +1,46 @@ | |||||
| from sqlalchemy.orm import Session | |||||
| from schemas.vehicle import CreateVehicle, OutputVehicle | |||||
| from db.models.vehicle import Vehicle | |||||
| from db.repository.user import verify_driver_exists | |||||
| def create_new_vehicle(vehicle: CreateVehicle, db: Session): | |||||
| vehicle = Vehicle( | |||||
| Model=vehicle.model, | |||||
| Year=vehicle.year, | |||||
| LicensePlate=vehicle.license_plate, | |||||
| Type=vehicle.type, | |||||
| Mileage=vehicle.mileage, | |||||
| AssignedDriverIds=[], | |||||
| CurrentLocation=[], | |||||
| Fuel=0, | |||||
| MaintenanceNotes=[], | |||||
| ) | |||||
| db.add(vehicle) | |||||
| db.commit() | |||||
| db.refresh(vehicle) | |||||
| return vehicle | |||||
| def assign_vehicle_driver(vehicle_id: int, driver_id: int, db: Session): | |||||
| vehicledb = db.query(Vehicle).filter(Vehicle.Id == vehicle_id) | |||||
| vehicle = vehicledb.first() | |||||
| if not vehicle: | |||||
| return "novehicle" | |||||
| if driver_id in vehicle.AssignedDriverIds: | |||||
| return "alreadyassigned" | |||||
| if verify_driver_exists(driver_id=driver_id, db=db): | |||||
| print(vehicle.AssignedDriverIds) | |||||
| vehicledb.update({"AssignedDriverIds": vehicle.AssignedDriverIds + [driver_id]}) | |||||
| print(vehicle.AssignedDriverIds) | |||||
| db.add(vehicle) | |||||
| db.commit() | |||||
| db.refresh(vehicle) | |||||
| return vehicle | |||||
| # return a 404 error if the driver does not exist | |||||
| return "nodriver" | |||||
| def list_vehicles(db: Session): | |||||
| vehicles = db.query(Vehicle).all() | |||||
| return vehicles | |||||
| @@ -0,0 +1,24 @@ | |||||
| from typing import Optional | |||||
| from pydantic import BaseModel, root_validator | |||||
| from datetime import datetime | |||||
| class CreateVehicle(BaseModel): | |||||
| id: int | |||||
| model: str | |||||
| year: int | |||||
| license_plate: str | |||||
| type: str | |||||
| mileage: int | |||||
| class OutputVehicle(BaseModel): | |||||
| Model: str | |||||
| Year: int | |||||
| LicensePlate: str | |||||
| Type: str | |||||
| Mileage: int | |||||
| CurrentLocation: Optional[list[str]] = None | |||||
| Fuel: Optional[int] = 0 | |||||
| MaintenanceNotes: Optional[list[str]] = None | |||||
| AssignedDriverIds: Optional[list[int]] = None | |||||