| @@ -33,7 +33,19 @@ OR | |||
| ``` | |||
| 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 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. | |||
| @@ -1,7 +1,8 @@ | |||
| # Base API router -- collecting all APIs here to not clutter main.py | |||
| from fastapi import APIRouter | |||
| from apis.v1 import route_user | |||
| from apis.v1 import route_user, route_vehicle | |||
| api_router = APIRouter() | |||
| 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 sqlalchemy.orm import Session | |||
| from fastapi import Depends | |||
| from typing import List | |||
| from schemas.user import UserCreate, ShowUser | |||
| 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() | |||
| @@ -15,3 +16,12 @@ router = APIRouter() | |||
| def create_user(user: UserCreate, db: Session = Depends(get_db)): | |||
| user = create_new_user(user=user, db=db) | |||
| 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.refresh(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 | |||