diff --git a/app/.DS_Store b/app/.DS_Store new file mode 100644 index 0000000..8defa37 Binary files /dev/null and b/app/.DS_Store differ diff --git a/app/apis/v1/route_auction.py b/app/apis/v1/route_auction.py index bc9d31b..eefc1b4 100644 --- a/app/apis/v1/route_auction.py +++ b/app/apis/v1/route_auction.py @@ -32,6 +32,10 @@ def getAuction( current_user: User = Depends(get_current_user), ): auction = get_auction_by_id(id, db) + if auction is None: + raise HTTPException( + status_code=404, detail="Auction with this ID does not exist" + ) return auction diff --git a/app/apis/v1/route_fuelingtask.py b/app/apis/v1/route_fuelingtask.py index ae1b8b9..403d577 100644 --- a/app/apis/v1/route_fuelingtask.py +++ b/app/apis/v1/route_fuelingtask.py @@ -4,14 +4,21 @@ from db.session import get_db from db.repository.fuelingtask import ( create_fueling_task, delete_fueling_task, - get_fueling_task_by_id + get_fueling_task_by_id, + get_all_fueling_tasks, +) +from schemas.fuelingtask import ( + CreateFuelingTask, + OutputFuelingTask, + OutputFuelingTaskMin, + OutputFuelingTaskList, ) -from schemas.fuelingtask import CreateFuelingTask, OutputFuelingTask from db.models.user import User from apis.v1.route_auth import get_current_user router = APIRouter() + @router.post("/", response_model=OutputFuelingTask, status_code=status.HTTP_201_CREATED) def create_fuelingtask( fuelingtask: CreateFuelingTask = Depends(), @@ -28,19 +35,18 @@ def create_fuelingtask( ) print("Created FuelTask") if fuelingtask_res == "nodriver": - raise HTTPException( - status_code=404, detail="Driver ID not found" - ) + raise HTTPException(status_code=404, detail="Driver ID not found") if fuelingtask_res == "novehicle": - raise HTTPException( - status_code=404, detail="Vehicle ID not found" - ) + raise HTTPException(status_code=404, detail="Vehicle ID not found") return fuelingtask_res - -@router.get("/{fueling_task_id}", response_model=OutputFuelingTask, status_code=status.HTTP_200_OK) +@router.get( + "/{fueling_task_id}", + response_model=OutputFuelingTask, + status_code=status.HTTP_200_OK, +) def get_fuelingtask( fueling_task_id: int, db: Session = Depends(get_db), @@ -50,26 +56,35 @@ def get_fuelingtask( raise HTTPException( status_code=403, detail="You are not authorized to perform this action" ) - + fuelingtask = get_fueling_task_by_id(fueling_task_id, db) if fuelingtask == "notfound": - raise HTTPException( - status_code=404, detail="fuck off" - ) + raise HTTPException(status_code=404, detail="fuck off") return fuelingtask + @router.delete("/{fueling_task_id}", status_code=status.HTTP_204_NO_CONTENT) def delete_fuelingtask( fueling_task_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): - if current_user.Role != "FuelingPerson" and current_user.Role != "Admin": + if current_user.Role != "Fueling" and current_user.Role != "Admin": raise HTTPException( status_code=403, detail="You are not authorized to perform this action" ) if not delete_fueling_task(fueling_task_id, db): + raise HTTPException(status_code=404, detail="Fueling task not found") + + +@router.get("/", response_model=OutputFuelingTaskList, status_code=status.HTTP_200_OK) +def get_all( + db: Session = Depends(get_db), current_user: User = Depends(get_current_user) +): + if current_user.Role != "Admin" and current_user.Role != "Fueling": raise HTTPException( - status_code=404, detail="Fueling task not found" - ) \ No newline at end of file + status_code=403, detail="You are not authorized to perform this action" + ) + tasks = get_all_fueling_tasks(db) + return tasks diff --git a/app/apis/v1/route_maintenancejob.py b/app/apis/v1/route_maintenancejob.py index 9a17c3f..ed64d30 100644 --- a/app/apis/v1/route_maintenancejob.py +++ b/app/apis/v1/route_maintenancejob.py @@ -38,7 +38,9 @@ def create_maintenancejob( return maintenancejob_res -@router.post("/carpart", response_model = ShowCarPart ,status_code=status.HTTP_201_CREATED) +@router.post( + "/carpart", response_model=ShowCarPart, status_code=status.HTTP_201_CREATED +) def create_carpart( car_part: CreateCarPart = Depends(), db: Session = Depends(get_db), @@ -80,6 +82,10 @@ def get_maintenancejob( db: Session = Depends(get_db), ): maintenancejob = get_maintenance_job(maintenance_job_id, db) + if maintenancejob is None: + raise HTTPException( + status_code=404, detail="Maintenance job with this id does not exist" + ) print(maintenancejob) return maintenancejob diff --git a/app/apis/v1/route_task.py b/app/apis/v1/route_task.py index 756dfe8..168ace4 100644 --- a/app/apis/v1/route_task.py +++ b/app/apis/v1/route_task.py @@ -165,14 +165,16 @@ def getActiveRoute( return route -@router.get("/myroutes", status_code=status.HTTP_200_OK) +@router.get("/myroutes/", status_code=status.HTTP_200_OK) def getMyRoutes( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): + print("here") if current_user.Role != "Driver": raise HTTPException( - status_code=403, detail="You are not authorized to perform this action" + status_code=403, + detail="You are not a driver, you can't have routes, silly!", ) routes = get_my_routes(current_user.Id, db) if routes == "notdriver": diff --git a/app/apis/v1/route_user.py b/app/apis/v1/route_user.py index 2490d0d..f8920d1 100644 --- a/app/apis/v1/route_user.py +++ b/app/apis/v1/route_user.py @@ -1,12 +1,21 @@ # Routes for user. MAIN PART OF THE API -from fastapi import APIRouter, HTTPException, status +from math import ceil +from fastapi import APIRouter, HTTPException, status, Query from sqlalchemy.orm import Session +from sqlalchemy import or_ from fastapi import Depends from typing import List, Annotated from apis.v1.route_auth import get_current_user from core.config import settings from db.models.user import User -from schemas.user import UserCreate, ShowUser, ShowDriver, DriverCreate +from schemas.user import ( + UserCreate, + ShowUser, + ShowDriver, + DriverCreate, + OutputUser, + UsersPage, +) from db.session import get_db from db.repository.user import ( create_new_user, @@ -15,6 +24,8 @@ from db.repository.user import ( replace_user_data, create_new_driver, delete_user_data, + get_users_by_name, + user_search_query, ) @@ -126,3 +137,14 @@ def delete_user( if result == "userNotFound": raise HTTPException(status_code=404, detail="User not found") return result + + +@router.get("/search/", response_model=UsersPage) +def search_users( + db: Session = Depends(get_db), + name: str = None, + role: str = None, + page: int = 1, + per_page: int = 20, +): + return user_search_query(db=db, name=name, role=role, page=page, per_page=per_page) diff --git a/app/db/models/fuelingtask.py b/app/db/models/fuelingtask.py index 4d837fa..bfd0442 100644 --- a/app/db/models/fuelingtask.py +++ b/app/db/models/fuelingtask.py @@ -10,7 +10,7 @@ class FuelingTask(Base): CreatedById = Column(ForeignKey("user.Id"), nullable=False) Date = Column(DateTime, nullable=False) Description = Column(String, nullable=True) - Cost = Column(Integer, nullable=False) + Cost = Column(Float, nullable=False) FuelRefilled = Column(Float, nullable=False) GasStationName = Column(String, nullable=False) ImageBefore = Column(LargeBinary, nullable=False) diff --git a/app/db/repository/auction.py b/app/db/repository/auction.py index e98dda8..00efa1c 100644 --- a/app/db/repository/auction.py +++ b/app/db/repository/auction.py @@ -14,6 +14,8 @@ def get_all_auctions(db: Session): def get_auction_by_id(id: int, db: Session): auction = db.query(Auction).filter(Auction.Id == id).first() + if not auction: + return None auction.car = auction.vehicle return auction diff --git a/app/db/repository/drivetask.py b/app/db/repository/drivetask.py index 3e8e391..f33ae20 100644 --- a/app/db/repository/drivetask.py +++ b/app/db/repository/drivetask.py @@ -63,10 +63,10 @@ def get_tasks_by_driver(driver_id: int, db: Session): def get_task_by_id(task_id: int, db: Session): task = db.query(DriveTask).filter(DriveTask.Id == task_id).first() - task.Driver = task.CreatedBy.__dict__ - task.Driver["AssignedVehicle"] = task.CreatedBy.vehicle if not task: return "notaskfound" + task.Driver = task.CreatedBy.__dict__ + task.Driver["AssignedVehicle"] = task.CreatedBy.vehicle return task diff --git a/app/db/repository/fuelingtask.py b/app/db/repository/fuelingtask.py index 6b3cd7e..5a083c4 100644 --- a/app/db/repository/fuelingtask.py +++ b/app/db/repository/fuelingtask.py @@ -7,16 +7,17 @@ from db.models.fuelingtask import FuelingTask from db.repository.user import get_car_driver, get_user_by_id from db.repository.vehicle import get_vehicle_by_id -def create_fueling_task(fueling_task: CreateFuelingTask, current_user: int, db: Session): - + +def create_fueling_task( + fueling_task: CreateFuelingTask, current_user: int, db: Session +): if not get_vehicle_by_id(fueling_task.VehicleId, db=db): return "novehicle" - + driver = get_car_driver(fueling_task.VehicleId, db=db) - + if not driver: return "nodriver" - fueling_task_object = FuelingTask( DriverId=driver.Id, VehicleId=fueling_task.VehicleId, @@ -35,31 +36,59 @@ def create_fueling_task(fueling_task: CreateFuelingTask, current_user: int, db: print(driver.__dict__) driverobj = driver.__dict__ driverobj["AssignedVehicle"] = driver.vehicle.__dict__ - fueling_task_object.Driver = driverobj - return fueling_task_object + resobj = fueling_task_object.__dict__ + resobj["Driver"] = driverobj + ia = fueling_task_object.ImageAfter + ib = fueling_task_object.ImageBefore + if ia is not None: + ia = base64.b64encode(ia).decode("ascii") + if ib is not None: + ib = base64.b64encode(ib).decode("ascii") + resobj["ImageBefore"] = ib + resobj["ImageAfter"] = ia + return resobj def delete_fueling_task(fueling_task_id: int, db: Session): - fueling_task = db.query(FuelingTask).filter(FuelingTask.Id == fueling_task_id).first() + fueling_task = ( + db.query(FuelingTask).filter(FuelingTask.Id == fueling_task_id).first() + ) if fueling_task: db.delete(fueling_task) db.commit() return True return False + def get_fueling_task_by_id(fuel_task_id: int, db: Session): fuel_task = db.query(FuelingTask).filter(FuelingTask.Id == fuel_task_id).first() if not fuel_task: return "notfound" - res = fuel_task.__dict__ + res = fuel_task.__dict__ driver = get_user_by_id(fuel_task.DriverId, role="Driver", db=db) driver_obj = driver.__dict__ imagebefore = fuel_task.ImageBefore imageafter = fuel_task.ImageAfter - imagebeforeBase64 = base64.b64encode(imagebefore).decode('ascii') - imageafterBase64 = base64.b64encode(imageafter).decode('ascii') + imagebeforeBase64 = base64.b64encode(imagebefore).decode("ascii") + imageafterBase64 = base64.b64encode(imageafter).decode("ascii") res["ImageBefore"] = imagebeforeBase64 res["ImageAfter"] = imageafterBase64 res["Driver"] = driver_obj res["Driver"]["AssignedVehicle"] = driver.vehicle - return res \ No newline at end of file + return res + + +def get_all_fueling_tasks(db: Session): + fuel_task = db.query(FuelingTask).all() + result = [] + for task in fuel_task: + res = task.__dict__ + res["ImageBefore"] = "" + res["ImageAfter"] = "" + driver = get_user_by_id(task.DriverId, role="Driver", db=db) + driver_obj = driver.__dict__ + res["Driver"] = driver_obj + res["Driver"]["AssignedVehicle"] = driver.vehicle + result.append(res) + x = {"FuelingTasks": result} + return x diff --git a/app/db/repository/maintenancejob.py b/app/db/repository/maintenancejob.py index cf1b7a0..7d261c1 100644 --- a/app/db/repository/maintenancejob.py +++ b/app/db/repository/maintenancejob.py @@ -58,16 +58,23 @@ def calculate_total_cost(car_parts: CarPart): def get_all_maintenance_jobs(db: Session): maintenancejobs = db.query(MaintenanceJob).all() + print("DB Access complete") result = [] for job in maintenancejobs: job_dict = job.__dict__ + print(job_dict) job_dict["CarPartsList"] = [part.__dict__ for part in job.CarParts] + print(len(job_dict["CarPartsList"])) for part in job_dict["CarPartsList"]: - part["image"] = base64.b64encode(part["ImageURL"]).decode("ascii") + if (part["ImageURL"] is None) or (part["ImageURL"] == ""): + part["image"] = "" + else: + part["image"] = base64.b64encode(part["ImageURL"]).decode("ascii") job_dict["TotalCost"] = calculate_total_cost(job.CarParts) job_dict["AssignedTo"] = job.CreatedBy.__dict__ job_dict["Vehicle"] = job.Vehicle.__dict__ result.append(job_dict) + print("Returning...") return maintenancejobs @@ -75,11 +82,13 @@ def get_maintenance_job(maintenancejob_id: int, db: Session): maintenancejob = ( db.query(MaintenanceJob).filter(MaintenanceJob.Id == maintenancejob_id).first() ) + if maintenancejob is None: + return None res = maintenancejob.__dict__ res["CarPartsList"] = [part.__dict__ for part in maintenancejob.CarParts] for part in maintenancejob.CarPartsList: part["image"] = base64.b64encode(part["ImageURL"]).decode("ascii") - + # print(type(result.CarPartsList)) res["TotalCost"] = calculate_total_cost(maintenancejob.CarParts) # print(result.TotalCost) diff --git a/app/db/repository/user.py b/app/db/repository/user.py index 6499ca4..d1ad2ec 100644 --- a/app/db/repository/user.py +++ b/app/db/repository/user.py @@ -1,7 +1,8 @@ # Creating a new user in the database +from math import ceil from sqlalchemy.orm import Session -from schemas.user import UserCreate, DriverCreate +from schemas.user import OutputUser, UserCreate, DriverCreate from db.models.user import User from core.hashing import Hasher from db.models.drivetask import DriveTask @@ -84,6 +85,19 @@ def list_users(db: Session, role: str = "Any"): return users +def get_users_by_name( + db: Session, name: str = "", role: str = None, page: int = 1, per_page: int = 20 +): + if role == "Admin": + return None + if role is None: + users = db.query(User).filter(User.Name.like(f"{name}%"), User.Role != "Admin") + else: + users = db.query(User).filter(User.Name.like(f"{name}%"), User.Role == role) + users = users.offset((page - 1) * per_page).limit(per_page).all() + return users + + def replace_user_data(user_id: int, user_data: UserCreate, db: Session): user = db.query(User).filter(User.Id == user_id).first() if not user: @@ -112,3 +126,31 @@ def delete_user_data(id: int, db: Session): db.delete(user) db.commit() return "userDeleted" + + +def user_search_query( + db: Session, name: str = "", role: str = None, page: int = 1, per_page: int = 20 +): + query = db.query(User).filter(User.Name.like(f"{name}%")) + if role is not None and role != "Admin": + query = query.filter(User.Role == role) + total_users = query.count() + total_pages = ceil(total_users / per_page) + users = query.offset((page - 1) * per_page).limit(per_page).all() + + output_users = [ + OutputUser( + id=user.Id, + Name=user.Name, + MiddleName=user.MiddleName, + LastName=user.LastName, + ContactNumber=user.ContactNumber, + Address=user.Address, + Email=user.Email, + Role=user.Role, + AssignedVehicle=None, + ) + for user in users + ] + + return {"users": output_users, "total_pages": total_pages} diff --git a/app/schemas/carpart.py b/app/schemas/carpart.py index e2e3770..8ebf37e 100644 --- a/app/schemas/carpart.py +++ b/app/schemas/carpart.py @@ -1,4 +1,3 @@ - from fastapi import Form, UploadFile from pydantic import BaseModel, Field from dataclasses import dataclass @@ -9,10 +8,8 @@ class CreateCarPart(BaseModel): Name: str = Form(...) Number: str = Form(...) Condition: str = Form(...) - Cost: int = Form(...) + Cost: float = Form(...) image: UploadFile = Form(...) - - class ShowCarPart(BaseModel): @@ -20,5 +17,5 @@ class ShowCarPart(BaseModel): Name: str = Field(...) Number: str = Field(...) Condition: str = Field(...) - Cost: int = Field(...) - image: str = Field(...) \ No newline at end of file + Cost: float = Field(...) + image: str = Field(...) diff --git a/app/schemas/drivetask.py b/app/schemas/drivetask.py index 2132f08..57eef64 100644 --- a/app/schemas/drivetask.py +++ b/app/schemas/drivetask.py @@ -5,7 +5,7 @@ from typing import Optional class CreateTask(BaseModel): - DriverId: int = Field() + DriverId: int = Field(...) Description: str = Field(..., min_length=3, max_length=200) StartLocation: tuple[str, str] = Field(...) EndLocation: tuple[str, str] = Field(...) diff --git a/app/schemas/fuelingtask.py b/app/schemas/fuelingtask.py index fbbed6c..94ee7df 100644 --- a/app/schemas/fuelingtask.py +++ b/app/schemas/fuelingtask.py @@ -3,29 +3,43 @@ from fastapi import Form, UploadFile from datetime import datetime from schemas.user import ShowDriver + class CreateFuelingTask(BaseModel): VehicleId: int = Form(...) Description: str = Form(...) Date: datetime = Form(...) - Cost: int = Form(...) - FuelRefilled: int = Form(...) + Cost: float = Form(...) + FuelRefilled: float = Form(...) GasStationName: str = Form(...) ImageBefore: UploadFile = Form(...) ImageAfter: UploadFile = Form(...) - model_config={ - "arbitrary_types_allowed": True - } + model_config = {"arbitrary_types_allowed": True} + class OutputFuelingTask(BaseModel): + Id: int = Field(...) VehicleId: int = Field(...) Description: str = Field(...) Date: datetime = Field(...) - Cost: int = Field(...) - FuelRefilled: int = Field(...) + Cost: float = Field(...) + FuelRefilled: float = Field(...) GasStationName: str = Field(...) Driver: ShowDriver | None ImageBefore: str = Field(...) ImageAfter: str = Field(...) - model_config={ - "arbitrary_types_allowed": True - } \ No newline at end of file + model_config = {"arbitrary_types_allowed": True} + + +class OutputFuelingTaskMin(BaseModel): + Id: int = Field(...) + VehicleId: int = Field(...) + Description: str = Field(...) + Date: datetime = Field(...) + Cost: float = Field(...) + FuelRefilled: float = Field(...) + GasStationName: str = Field(...) + Driver: ShowDriver | None + + +class OutputFuelingTaskList(BaseModel): + FuelingTasks: list[OutputFuelingTaskMin] diff --git a/app/schemas/maintenancejob.py b/app/schemas/maintenancejob.py index aee6e25..de117f0 100644 --- a/app/schemas/maintenancejob.py +++ b/app/schemas/maintenancejob.py @@ -17,7 +17,7 @@ class OutputMaintenanceJob(BaseModel): Description: str Date: datetime CarPartsList: Optional[List[ShowCarPart]] - TotalCost: int + TotalCost: float Vehicle: OutputVehicle FinishedBy: Optional[ShowUser] Status: str diff --git a/app/schemas/user.py b/app/schemas/user.py index 61b4ff1..1a9f188 100644 --- a/app/schemas/user.py +++ b/app/schemas/user.py @@ -1,6 +1,7 @@ # Purpose: User schema for pydantic (validation, inside-api usage) from pydantic import BaseModel, EmailStr, Field +from typing import Optional, List class UserCreate(BaseModel): @@ -36,6 +37,28 @@ class ShowUser(BaseModel): validate_assignment = True +class OutputUser(BaseModel): + id: int + Name: str + MiddleName: Optional[str] + LastName: str + ContactNumber: str + Address: str + Email: EmailStr + Role: str + AssignedVehicle: Optional[ + str + ] # replace str with the actual type of AssignedVehicle + + class Config: + orm_mode = True + + +class UsersPage(BaseModel): + users: List[OutputUser] + total_pages: int + + class ShowDriverNoVehicle(ShowUser): DrivingLicenseNumber: str | None