From a3303e729fa88b8d9cc5ed347f41db391f42a78e Mon Sep 17 00:00:00 2001 From: Madiwka3 Date: Sun, 10 Sep 2023 19:43:51 +0600 Subject: [PATCH 1/5] Added improved VMS structures --- app/core/config.py | 3 ++- app/db/models/user.py | 5 +++-- app/db/models/vehicle.py | 3 ++- app/db/repository/user.py | 3 ++- app/db/repository/vehicle.py | 3 ++- app/schemas/user.py | 7 ++++--- app/schemas/vehicle.py | 16 ++++------------ 7 files changed, 19 insertions(+), 21 deletions(-) diff --git a/app/core/config.py b/app/core/config.py index 47e4f74..191fb97 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -29,7 +29,8 @@ def createAdminAcc(): LastName="Turgunov", ContactNumber="+77071234567", Role="Admin", - BirthDate="2000-01-01T00:00:00+06:00", + GovernmentId="123456789", + Address="Nazarbayev University", ) if db.query(User).filter(User.Email == user.Email).first(): return False diff --git a/app/db/models/user.py b/app/db/models/user.py index 6f328fc..26f25ec 100644 --- a/app/db/models/user.py +++ b/app/db/models/user.py @@ -1,5 +1,5 @@ # PostgreSQL table model for users -from sqlalchemy import Column, Integer, String, DateTime, ForeignKey +from sqlalchemy import Column, Integer, String, ForeignKey from sqlalchemy.orm import relationship from db.base import Base @@ -9,7 +9,8 @@ class User(Base): Name = Column(String, nullable=False) MiddleName = Column(String, nullable=True) LastName = Column(String, nullable=False) - BirthDate = Column(DateTime, nullable=False) + GovernmentId = Column(String, nullable=False) + Address = Column(String, nullable=False) ContactNumber = Column(String, nullable=False) Email = Column(String, nullable=False) Role = Column(String, nullable=False) diff --git a/app/db/models/vehicle.py b/app/db/models/vehicle.py index 1c3adce..1d6bf86 100644 --- a/app/db/models/vehicle.py +++ b/app/db/models/vehicle.py @@ -14,10 +14,11 @@ class Vehicle(Base): Model = Column(String, nullable=False) Year = Column(Integer, nullable=False) LicensePlate = Column(String, nullable=False) + Type = Column(String, nullable=False) CurrentLocation = Column(ARRAY(String), nullable=True) Fuel = Column(Integer, nullable=False) Mileage = Column(Integer, nullable=False) Status = Column(String, nullable=False) Capacity = Column(Integer, nullable=False) - MaintenanceNotes = Column(ARRAY(String), nullable=True) + DriverHistory = Column(ARRAY(Integer), nullable=True) driver = relationship("User", back_populates="vehicle") diff --git a/app/db/repository/user.py b/app/db/repository/user.py index 6737f48..64b3068 100644 --- a/app/db/repository/user.py +++ b/app/db/repository/user.py @@ -12,7 +12,8 @@ def create_new_user(user: UserCreate, db: Session): Name=user.Name, MiddleName=user.MiddleName, LastName=user.LastName, - BirthDate=user.BirthDate, + GovernmentId=user.GovernmentId, + Address=user.Address, ContactNumber=user.ContactNumber, Role=user.Role, HashedPassword=Hasher.get_password_hash(user.Password), diff --git a/app/db/repository/vehicle.py b/app/db/repository/vehicle.py index 572482f..2498bcf 100644 --- a/app/db/repository/vehicle.py +++ b/app/db/repository/vehicle.py @@ -78,7 +78,8 @@ def replace_vehicle_data(id: int, vehicle: UpdateVehicle, db: Session): vehicle_object.CurrentLocation = vehicle.CurrentLocation vehicle_object.Fuel = vehicle.Fuel vehicle_object.LicensePlate = vehicle.LicensePlate - vehicle_object.MaintenanceNotes = vehicle.MaintenanceNotes + vehicle_object.DriverHistory = vehicle.DriverHistory + vehicle_object.Type = vehicle.Type vehicle_object.Mileage = vehicle.Mileage vehicle_object.Model = vehicle.Model vehicle_object.Status = vehicle.Status diff --git a/app/schemas/user.py b/app/schemas/user.py index 61ff6a5..2410607 100644 --- a/app/schemas/user.py +++ b/app/schemas/user.py @@ -1,6 +1,5 @@ # Purpose: User schema for pydantic (validation, inside-api usage) -from datetime import datetime from pydantic import BaseModel, EmailStr, Field @@ -11,7 +10,8 @@ class UserCreate(BaseModel): MiddleName: str = Field(None) LastName: str = Field(..., min_length=3, max_length=50) ContactNumber: str = Field(..., min_length=12, max_length=12) - BirthDate: datetime = Field(...) + GovernmentId: str = Field(...) + Address: str = Field(...) Email: EmailStr = Field(...) Role: str = Field(..., min_length=3, max_length=50) @@ -22,7 +22,8 @@ class ShowUser(BaseModel): MiddleName: str | None LastName: str ContactNumber: str - BirthDate: datetime + GovernmentId: str + Address: str Email: EmailStr Role: str AssignedVehicle: int | None diff --git a/app/schemas/vehicle.py b/app/schemas/vehicle.py index 7eb2ce7..70ee787 100644 --- a/app/schemas/vehicle.py +++ b/app/schemas/vehicle.py @@ -18,23 +18,15 @@ class OutputVehicle(BaseModel): Mileage: int CurrentLocation: Optional[list[str]] = None Fuel: Optional[int] = 0 - MaintenanceNotes: Optional[list[str]] = None + Type: str + DriverHistory: Optional[list[int]] = None AssignedDriver: Optional[int] = None Capacity: int Status: str -class UpdateVehicle(BaseModel): - Model: str - Year: int - LicensePlate: str - Capacity: int - Mileage: int - Status: str - CurrentLocation: Optional[list[str]] = None - Fuel: Optional[int] = 0 - MaintenanceNotes: Optional[list[str]] = None - AssignedDriver: Optional[int] = None +class UpdateVehicle(OutputVehicle): + pass class VehicleLocation(BaseModel): From c8e4058629885ba9cb2db000e40f4fe58a32b772 Mon Sep 17 00:00:00 2001 From: Madiwka3 Date: Sun, 10 Sep 2023 20:42:50 +0600 Subject: [PATCH 2/5] assignments added (WIP) --- app/apis/base.py | 3 ++- app/apis/v1/route_task.py | 32 ++++++++++++++++++++++++++++++++ app/db/models/assignment.py | 0 app/db/models/drivetask.py | 11 +++++++++++ app/db/repository/drivetask.py | 24 ++++++++++++++++++++++++ app/schemas/drivetask.py | 20 ++++++++++++++++++++ 6 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 app/apis/v1/route_task.py delete mode 100644 app/db/models/assignment.py create mode 100644 app/db/models/drivetask.py create mode 100644 app/db/repository/drivetask.py create mode 100644 app/schemas/drivetask.py diff --git a/app/apis/base.py b/app/apis/base.py index f42c022..fa7d033 100644 --- a/app/apis/base.py +++ b/app/apis/base.py @@ -1,9 +1,10 @@ # Base API router -- collecting all APIs here to not clutter main.py from fastapi import APIRouter -from apis.v1 import route_user, route_vehicle, route_auth +from apis.v1 import route_user, route_vehicle, route_auth, route_task 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"]) api_router.include_router(route_auth.router, prefix="", tags=["auth"]) +api_router.include_router(route_task.router, prefix="/task", tags=["task"]) diff --git a/app/apis/v1/route_task.py b/app/apis/v1/route_task.py new file mode 100644 index 0000000..fca5770 --- /dev/null +++ b/app/apis/v1/route_task.py @@ -0,0 +1,32 @@ +from fastapi import Depends, APIRouter +from sqlalchemy.orm import Session +from fastapi import status, HTTPException +from typing import Annotated +from db.session import get_db +from core.config import settings +from db.repository.drivetask import ( + create_new_task, +) +from schemas.drivetask import CreateTask +from db.models.user import User +from apis.v1.route_auth import get_current_user + +router = APIRouter() + + +@router.post("/", status_code=status.HTTP_201_CREATED) +def create_tasK( + task: CreateTask, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role != "Admin": + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + task_res = create_new_task(task=task, db=db) + if task_res == "notdriver": + raise HTTPException( + status_code=404, detail=f"Driver with id {task.DriverId} not found" + ) + return task diff --git a/app/db/models/assignment.py b/app/db/models/assignment.py deleted file mode 100644 index e69de29..0000000 diff --git a/app/db/models/drivetask.py b/app/db/models/drivetask.py new file mode 100644 index 0000000..f6d21b1 --- /dev/null +++ b/app/db/models/drivetask.py @@ -0,0 +1,11 @@ +from sqlalchemy import Column, Integer, String, ForeignKey, ARRAY +from db.base import Base + + +class DriveTask(Base): + Id = Column(Integer, primary_key=True, index=True) + DriverId = Column(ForeignKey("user.Id"), nullable=False) + Description = Column(String, nullable=True) + Status = Column(String, nullable=False) + StartLocation = Column(ARRAY(String), nullable=False) + EndLocation = Column(ARRAY(String), nullable=False) diff --git a/app/db/repository/drivetask.py b/app/db/repository/drivetask.py new file mode 100644 index 0000000..3887b79 --- /dev/null +++ b/app/db/repository/drivetask.py @@ -0,0 +1,24 @@ +from sqlalchemy.orm import Session + +from schemas.drivetask import CreateTask +from db.models.drivetask import DriveTask +from db.repository.user import get_user_by_id + + +def create_new_task(task: CreateTask, db: Session): + driver = get_user_by_id(task.DriverId, db) + if driver is None: + return "notdriver" + elif driver.Role != "Driver": + return "notdriver" + task_object = DriveTask( + DriverId=task.DriverId, + Description=task.Description, + Status="Pending", + StartLocation=task.StartLocation, + EndLocation=task.EndLocation, + ) + db.add(task_object) + db.commit() + db.refresh(task_object) + return task_object diff --git a/app/schemas/drivetask.py b/app/schemas/drivetask.py new file mode 100644 index 0000000..0a36e1d --- /dev/null +++ b/app/schemas/drivetask.py @@ -0,0 +1,20 @@ +from pydantic import BaseModel, Field + + +class CreateTask(BaseModel): + DriverId: int = Field() + Description: str = Field(..., min_length=3, max_length=200) + StartLocation: tuple[str, str] = Field(...) + EndLocation: tuple[str, str] = Field(...) + + +class ShowTask(BaseModel): + Id: int + DriverId: int + Description: str + Status: str + StartLocation: tuple[str, str] + EndLocation: tuple[str, str] + + class Config: + orm_mode = True From 03082929c64115e2b0d0d702caa93062c684c105 Mon Sep 17 00:00:00 2001 From: Madiwka3 Date: Sat, 16 Sep 2023 18:13:03 +0600 Subject: [PATCH 3/5] Added more assignment/task functions --- app/apis/v1/route_task.py | 93 +++++++++++++++++++++++++++++++++- app/core/config.py | 1 + app/db/repository/drivetask.py | 42 +++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) diff --git a/app/apis/v1/route_task.py b/app/apis/v1/route_task.py index fca5770..d3ab91f 100644 --- a/app/apis/v1/route_task.py +++ b/app/apis/v1/route_task.py @@ -6,16 +6,22 @@ from db.session import get_db from core.config import settings from db.repository.drivetask import ( create_new_task, + get_task_driver, + change_task_status, + get_all_tasks, + get_task_by_id, + get_tasks_by_driver, ) from schemas.drivetask import CreateTask from db.models.user import User from apis.v1.route_auth import get_current_user +from db.models.drivetask import DriveTask router = APIRouter() @router.post("/", status_code=status.HTTP_201_CREATED) -def create_tasK( +def create_task( task: CreateTask, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), @@ -30,3 +36,88 @@ def create_tasK( status_code=404, detail=f"Driver with id {task.DriverId} not found" ) return task + + +@router.patch("/", status_code=status.HTTP_200_OK) +def changeStatus( + task_id: int, + status: str, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role == "Admin" or current_user.Role == "Driver": + if status not in settings.ALLOWED_TASK_STATUS: + raise HTTPException( + status_code=400, + detail=f"Status {status} is not allowed. Allowed status are {settings.ALLOWED_TASK_STATUS}", + ) + if current_user.Role == "Driver": + verification = get_task_driver(task_id, db) + if verification.Id != current_user.Id: + raise HTTPException( + status_code=403, + detail="You are not authorized to perform this action", + ) + task = change_task_status(task_id, status, db) + if task == "notaskfound": + raise HTTPException( + status_code=404, detail=f"Task with id {task_id} not found" + ) + return task + else: + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + + +@router.get("/", status_code=status.HTTP_200_OK) +def getAllTasks( + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role == "Admin": + tasks = get_all_tasks(db) + return tasks + else: + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + + +@router.get("/{task_id}", status_code=status.HTTP_200_OK) +def getTaskById( + task_id: int, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role != "Admin": + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + task = get_task_by_id(task_id, db) + if task == "notaskfound": + raise HTTPException(status_code=404, detail=f"Task with id {task_id} not found") + return task + + +@router.get("/driver/{driver_id}", status_code=status.HTTP_200_OK) +def getTasksByDriver( + driver_id: int, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role != "Admin" and current_user.Role != "Driver": + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + if current_user.Role == "Driver": + if current_user.Id != driver_id: + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + tasks = get_tasks_by_driver(driver_id, db) + if tasks == "notdriver": + raise HTTPException( + status_code=404, detail=f"Driver with id {driver_id} not found" + ) + return tasks diff --git a/app/core/config.py b/app/core/config.py index 191fb97..f9bf511 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -10,6 +10,7 @@ class Settings: ACCESS_TOKEN_EXPIRE: int = 60 * 24 * 7 # 7 days SECRET_KEY: str = "tH357aC6oA7ofCaN3yTffYkRh" ALGORITHM: str = "HS256" + ALLOWED_TASK_STATUS: list = ["Pending", "In Progress", "Completed", "Cancelled"] settings = Settings() diff --git a/app/db/repository/drivetask.py b/app/db/repository/drivetask.py index 3887b79..e27f9cf 100644 --- a/app/db/repository/drivetask.py +++ b/app/db/repository/drivetask.py @@ -22,3 +22,45 @@ def create_new_task(task: CreateTask, db: Session): db.commit() db.refresh(task_object) return task_object + + +def change_task_status(task_id: int, status: str, db: Session): + task = db.query(DriveTask).filter(DriveTask.Id == task_id).first() + if not task: + return "notaskfound" + task.Status = status + db.commit() + db.refresh(task) + return task + + +def get_task_driver(task_id: int, db: Session): + task = db.query(DriveTask).filter(DriveTask.Id == task_id).first() + if not task: + return "notaskfound" + driver = get_user_by_id(task.DriverId, db) + if not driver: + return "notdriver" + return driver + + +def get_tasks_by_driver(driver_id: int, db: Session): + driver = get_user_by_id(driver_id, db) + if not driver: + return "notdriver" + if driver.Role != "Driver": + return "notdriver" + tasks = db.query(DriveTask).filter(DriveTask.DriverId == driver_id).all() + return tasks + + +def get_task_by_id(task_id: int, db: Session): + task = db.query(DriveTask).filter(DriveTask.Id == task_id).first() + if not task: + return "notaskfound" + return task + + +def get_all_tasks(db: Session): + tasks = db.query(DriveTask).all() + return tasks From b74c00fdc5c68af3e5ca399ae4971477dfda69f1 Mon Sep 17 00:00:00 2001 From: Madiwka3 Date: Sun, 1 Oct 2023 20:54:01 +0600 Subject: [PATCH 4/5] Added carparts and maintenanceJobs --- app/apis/base.py | 11 ++++- app/apis/v1/route_maintenancejob.py | 76 +++++++++++++++++++++++++++++ app/apis/v1/route_task.py | 5 +- app/db/base.py | 3 ++ app/db/models/carpart.py | 15 ++++++ app/db/models/maintenancejob.py | 12 +++++ app/db/repository/maintenancejob.py | 63 ++++++++++++++++++++++++ app/schemas/carpart.py | 10 ++++ app/schemas/maintenancejob.py | 7 +++ 9 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 app/apis/v1/route_maintenancejob.py create mode 100644 app/db/models/carpart.py create mode 100644 app/db/models/maintenancejob.py create mode 100644 app/db/repository/maintenancejob.py create mode 100644 app/schemas/carpart.py create mode 100644 app/schemas/maintenancejob.py diff --git a/app/apis/base.py b/app/apis/base.py index fa7d033..29a1f3a 100644 --- a/app/apis/base.py +++ b/app/apis/base.py @@ -1,10 +1,19 @@ # Base API router -- collecting all APIs here to not clutter main.py from fastapi import APIRouter -from apis.v1 import route_user, route_vehicle, route_auth, route_task +from apis.v1 import ( + route_user, + route_vehicle, + route_auth, + route_task, + route_maintenancejob, +) 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"]) api_router.include_router(route_auth.router, prefix="", tags=["auth"]) api_router.include_router(route_task.router, prefix="/task", tags=["task"]) +api_router.include_router( + route_maintenancejob.router, prefix="/maintenancejob", tags=["maintenancejob"] +) diff --git a/app/apis/v1/route_maintenancejob.py b/app/apis/v1/route_maintenancejob.py new file mode 100644 index 0000000..d66eb7f --- /dev/null +++ b/app/apis/v1/route_maintenancejob.py @@ -0,0 +1,76 @@ +from fastapi import Depends, APIRouter, HTTPException, status +from sqlalchemy.orm import Session +from db.session import get_db +from db.repository.maintenancejob import ( + create_new_maintenancejob, + create_car_part, + get_all_maintenance_jobs, + get_maintenance_job, +) +from schemas.maintenancejob import CreateMaintenanceJob +from schemas.carpart import CreateCarPart +from db.models.user import User +from apis.v1.route_auth import get_current_user + +router = APIRouter() + + +@router.post("/", status_code=status.HTTP_201_CREATED) +def create_maintenancejob( + maintenancejob: CreateMaintenanceJob, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role != "Maintenance" and current_user.Role != "Admin": + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + + maintenancejob_res = create_new_maintenancejob( + maintenancejob=maintenancejob, maintenanceworker=current_user.Id, db=db + ) + return maintenancejob_res + + +@router.post("/carpart", status_code=status.HTTP_201_CREATED) +def create_carpart( + car_part: CreateCarPart, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role != "Maintenance" and current_user.Role != "Admin": + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + + car_part_res = create_car_part(car_part=car_part, db=db) + return car_part_res + + +@router.get("/", status_code=status.HTTP_200_OK) +def get_all_maintenancejobs( + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role != "Maintenance" and current_user.Role != "Admin": + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + + maintenancejobs = get_all_maintenance_jobs(db) + return maintenancejobs + + +@router.get("/{maintenance_job_id}", status_code=status.HTTP_200_OK) +def get_maintenancejob( + maintenance_job_id: int, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role != "Maintenance" and current_user.Role != "Admin": + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + + maintenancejob = get_maintenance_job(maintenance_job_id, db) + return maintenancejob diff --git a/app/apis/v1/route_task.py b/app/apis/v1/route_task.py index d3ab91f..15adf72 100644 --- a/app/apis/v1/route_task.py +++ b/app/apis/v1/route_task.py @@ -1,7 +1,5 @@ -from fastapi import Depends, APIRouter +from fastapi import Depends, APIRouter, HTTPException, status from sqlalchemy.orm import Session -from fastapi import status, HTTPException -from typing import Annotated from db.session import get_db from core.config import settings from db.repository.drivetask import ( @@ -15,7 +13,6 @@ from db.repository.drivetask import ( from schemas.drivetask import CreateTask from db.models.user import User from apis.v1.route_auth import get_current_user -from db.models.drivetask import DriveTask router = APIRouter() diff --git a/app/db/base.py b/app/db/base.py index 2662b7f..57fff10 100644 --- a/app/db/base.py +++ b/app/db/base.py @@ -2,3 +2,6 @@ from db.base_class import Base from db.models.user import User from db.models.vehicle import Vehicle +from db.models.carpart import CarPart +from db.models.maintenancejob import MaintenanceJob +from db.models.drivetask import DriveTask diff --git a/app/db/models/carpart.py b/app/db/models/carpart.py new file mode 100644 index 0000000..b721c51 --- /dev/null +++ b/app/db/models/carpart.py @@ -0,0 +1,15 @@ +from sqlalchemy import Column, Integer, String, ForeignKey +from sqlalchemy.orm import relationship +from db.base import Base + + +class CarPart(Base): + Id = Column(Integer, primary_key=True, index=True) + # a list of weak entities of class CarPart + ParentId = Column(Integer, ForeignKey("maintenancejob.Id"), nullable=False) + parent = relationship("MaintenanceJob", back_populates="CarParts") + Name = Column(String, nullable=False) + Number = Column(String, nullable=False) + Condition = Column(String, nullable=False) + ImageURL = Column(String, nullable=False) + Cost = Column(Integer, nullable=False) diff --git a/app/db/models/maintenancejob.py b/app/db/models/maintenancejob.py new file mode 100644 index 0000000..3191b76 --- /dev/null +++ b/app/db/models/maintenancejob.py @@ -0,0 +1,12 @@ +from sqlalchemy import Column, Integer, String, DateTime, ForeignKey +from sqlalchemy.orm import relationship +from db.base import Base + + +class MaintenanceJob(Base): + Id = Column(Integer, primary_key=True, index=True) + # a list of weak entities of class CarPart + CarParts = relationship("CarPart", back_populates="parent") + Description = Column(String, nullable=False) + Date = Column(DateTime, nullable=False) + MaintenanceWorker = Column(ForeignKey("user.Id"), nullable=False) diff --git a/app/db/repository/maintenancejob.py b/app/db/repository/maintenancejob.py new file mode 100644 index 0000000..1584516 --- /dev/null +++ b/app/db/repository/maintenancejob.py @@ -0,0 +1,63 @@ +from sqlalchemy.orm import Session +from schemas.maintenancejob import CreateMaintenanceJob +from db.models.maintenancejob import MaintenanceJob +from schemas.carpart import CreateCarPart +from db.models.carpart import CarPart + + +def create_new_maintenancejob( + maintenancejob: CreateMaintenanceJob, maintenanceworker, db: Session +): + maintenancejob_object = MaintenanceJob( + MaintenanceWorker=maintenanceworker, + Description=maintenancejob.Description, + Date=maintenancejob.Date, + ) + print("OBJECT CREATED") + db.add(maintenancejob_object) + db.commit() + db.refresh(maintenancejob_object) + return maintenancejob_object + + +def create_car_part(car_part: CreateCarPart, db: Session): + car_part_object = CarPart( + ParentId=car_part.ParentId, + Name=car_part.Name, + Number=car_part.Number, + Condition=car_part.Condition, + ImageURL=car_part.ImageURL, + Cost=car_part.Cost, + ) + print("OBJECT CREATED") + db.add(car_part_object) + db.commit() + db.refresh(car_part_object) + return car_part_object + + +def calculate_total_cost(car_parts: CarPart): + total_cost = 0 + for part in car_parts: + total_cost += part["Cost"] + return total_cost + + +def get_all_maintenance_jobs(db: Session): + maintenancejobs = db.query(MaintenanceJob).all() + result = [] + for job in maintenancejobs: + job_dict = job.__dict__ + job_dict["CarParts"] = [part.__dict__ for part in job.CarParts] + job_dict["TotalCost"] = calculate_total_cost(job.CarParts) + result.append(job_dict) + return maintenancejobs + + +def get_maintenance_job(maintenancejob_id: int, db: Session): + maintenancejob = ( + db.query(MaintenanceJob).filter(MaintenanceJob.Id == maintenancejob_id).first() + ) + result = maintenancejob.__dict__ + result["CarParts"] = [part.__dict__ for part in maintenancejob.CarParts] + return result diff --git a/app/schemas/carpart.py b/app/schemas/carpart.py new file mode 100644 index 0000000..6bf14b2 --- /dev/null +++ b/app/schemas/carpart.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel, Field + + +class CreateCarPart(BaseModel): + ParentId: int = Field(...) + Name: str = Field(...) + Number: str = Field(...) + Condition: str = Field(...) + ImageURL: str = Field(...) + Cost: int = Field(...) diff --git a/app/schemas/maintenancejob.py b/app/schemas/maintenancejob.py new file mode 100644 index 0000000..aaffb2e --- /dev/null +++ b/app/schemas/maintenancejob.py @@ -0,0 +1,7 @@ +from pydantic import BaseModel, Field +from datetime import datetime + + +class CreateMaintenanceJob(BaseModel): + Description: str = Field(...) + Date: datetime = Field(...) From ad7ce19915baffdd43a0e5a47e043abf16a4c4cd Mon Sep 17 00:00:00 2001 From: Madiwka Date: Wed, 18 Oct 2023 17:15:28 +0600 Subject: [PATCH 5/5] things --- app/apis/v1/route_maintenancejob.py | 19 +++++++++++++++++++ app/apis/v1/route_user.py | 14 +++++++++++++- app/apis/v1/route_vehicle.py | 6 ++++-- app/db/models/auction.py | 16 ++++++++++++++++ app/db/models/drivetask.py | 2 ++ app/db/models/maintenancejob.py | 1 + app/db/models/user.py | 13 ++++++++++++- app/db/repository/maintenancejob.py | 11 +++++++++++ app/db/repository/user.py | 17 +++++++++++++++++ app/db/repository/vehicle.py | 5 +++-- app/main.py | 5 ----- app/schemas/user.py | 1 + app/schemas/vehicle.py | 1 + 13 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 app/db/models/auction.py diff --git a/app/apis/v1/route_maintenancejob.py b/app/apis/v1/route_maintenancejob.py index d66eb7f..00484d6 100644 --- a/app/apis/v1/route_maintenancejob.py +++ b/app/apis/v1/route_maintenancejob.py @@ -6,6 +6,7 @@ from db.repository.maintenancejob import ( create_car_part, get_all_maintenance_jobs, get_maintenance_job, + change_maintenance_status ) from schemas.maintenancejob import CreateMaintenanceJob from schemas.carpart import CreateCarPart @@ -74,3 +75,21 @@ def get_maintenancejob( maintenancejob = get_maintenance_job(maintenance_job_id, db) return maintenancejob + +@router.patch("/{maintenance_job_id}", status_code=status.HTTP_200_OK) +def change_status( + maintenance_job_id: int, + status: str, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role != "Maintenance" and current_user.Role != "Admin": + raise HTTPException( + status_code=403, detail="You are not authorized to perform this action" + ) + result = change_maintenance_status(maintenance_job_id, status, db) + if result is None: + raise HTTPException( + status_code=404, detail="Maintenance job not found" + ) + return result \ No newline at end of file diff --git a/app/apis/v1/route_user.py b/app/apis/v1/route_user.py index 13037bf..9088633 100644 --- a/app/apis/v1/route_user.py +++ b/app/apis/v1/route_user.py @@ -7,7 +7,7 @@ from apis.v1.route_auth import get_current_user from db.models.user import User from schemas.user import UserCreate, ShowUser from db.session import get_db -from db.repository.user import create_new_user, list_users, get_user_by_id +from db.repository.user import create_new_user, list_users, get_user_by_id, replace_user_data router = APIRouter() @@ -35,6 +35,18 @@ def get_all_users(db: Session = Depends(get_db), role: str = None): users = list_users(db=db, role=role) return users +@router.put("/{user_id}", response_model=ShowUser, status_code=status.HTTP_202_ACCEPTED) +def update_user( + user_id: int, + user: UserCreate, + db: Session = Depends(get_db), + current_user: User = Depends(get_current_user), +): + if current_user.Role != "Admin": + raise HTTPException(status_code=403, detail="You are not authorized to perform this action") + user = replace_user_data(user_id=user_id, user=user, db=db) + return user + @router.get("/me", response_model=ShowUser, status_code=status.HTTP_200_OK) def get_user_me( diff --git a/app/apis/v1/route_vehicle.py b/app/apis/v1/route_vehicle.py index f41e08c..21c8290 100644 --- a/app/apis/v1/route_vehicle.py +++ b/app/apis/v1/route_vehicle.py @@ -90,6 +90,8 @@ async def assign_driver( @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) + if vehicles == []: + raise HTTPException(status_code=404, detail="No vehicles found") return vehicles @@ -151,11 +153,11 @@ def update_vehicle_location( ): print(current_user) print(current_user.Name) - if current_user.Role != "Driver": + if current_user.Role != "Driver" and current_user.Role != "Admin": raise HTTPException( status_code=403, detail="You are not authorized to perform this action" ) - if current_user.AssignedVehicle != vehicle_id: + if current_user.AssignedVehicle != vehicle_id and current_user.Role != "Admin": raise HTTPException( status_code=403, detail="You are not the correct car driver" ) diff --git a/app/db/models/auction.py b/app/db/models/auction.py new file mode 100644 index 0000000..0f6ed49 --- /dev/null +++ b/app/db/models/auction.py @@ -0,0 +1,16 @@ +from sqlalchemy import Column, Integer, String, ForeignKey, DateTime +from sqlalchemy.orm import relationship +from db.base import Base + + +class Auction(Base): + Id = Column(Integer, primary_key=True, index=True) + + initialPrice = Column(Integer, nullable=False) + minimalBet = Column(Integer, nullable=False) + carID = Column(Integer, ForeignKey("car.Id"), nullable=False) + vehicle = relationship("Vehicle", back_populates="auction") + CreatedBy = relationship("User", back_populates="auctions") + dateStart = Column(DateTime, nullable=False) + dateEnd = Column(DateTime, nullable=False) + diff --git a/app/db/models/drivetask.py b/app/db/models/drivetask.py index f6d21b1..4328212 100644 --- a/app/db/models/drivetask.py +++ b/app/db/models/drivetask.py @@ -1,10 +1,12 @@ from sqlalchemy import Column, Integer, String, ForeignKey, ARRAY from db.base import Base +from sqlalchemy.orm import relationship class DriveTask(Base): Id = Column(Integer, primary_key=True, index=True) DriverId = Column(ForeignKey("user.Id"), nullable=False) + CreatedBy = relationship("User", back_populates="driveTasks") Description = Column(String, nullable=True) Status = Column(String, nullable=False) StartLocation = Column(ARRAY(String), nullable=False) diff --git a/app/db/models/maintenancejob.py b/app/db/models/maintenancejob.py index 3191b76..6914241 100644 --- a/app/db/models/maintenancejob.py +++ b/app/db/models/maintenancejob.py @@ -7,6 +7,7 @@ class MaintenanceJob(Base): Id = Column(Integer, primary_key=True, index=True) # a list of weak entities of class CarPart CarParts = relationship("CarPart", back_populates="parent") + CreatedBy = relationship("MaintenancePerson", back_populates="maintenanceJobs") Description = Column(String, nullable=False) Date = Column(DateTime, nullable=False) MaintenanceWorker = Column(ForeignKey("user.Id"), nullable=False) diff --git a/app/db/models/user.py b/app/db/models/user.py index 26f25ec..c518fb1 100644 --- a/app/db/models/user.py +++ b/app/db/models/user.py @@ -14,7 +14,18 @@ class User(Base): ContactNumber = Column(String, nullable=False) Email = Column(String, nullable=False) Role = Column(String, nullable=False) + HashedPassword = Column(String, nullable=False) + + + #Admin-specific relationships + CreatedAuctions = relationship("Auction", back_populates="CreatedBy") + #Driver-specific relationships DrivingLicenseNumber = Column(String, nullable=True) AssignedVehicle = Column(Integer, ForeignKey("vehicle.Id"), nullable=True) + DriveTasks = relationship("DriveTask", back_populates="CreatedBy") vehicle = relationship("Vehicle", back_populates="driver") - HashedPassword = Column(String, nullable=False) + #MaintenancePerson-specific relationships + maintenanceJobs = relationship("MaintenanceJob", back_populates="CreatedBy") + #FuelingPerson-specific relationships + fuelingJobs = relationship("FuelingJob", back_populates="CreatedBy") + diff --git a/app/db/repository/maintenancejob.py b/app/db/repository/maintenancejob.py index 1584516..8bb7f1e 100644 --- a/app/db/repository/maintenancejob.py +++ b/app/db/repository/maintenancejob.py @@ -61,3 +61,14 @@ def get_maintenance_job(maintenancejob_id: int, db: Session): result = maintenancejob.__dict__ result["CarParts"] = [part.__dict__ for part in maintenancejob.CarParts] return result + +def change_maintenance_status(maintenancejob_id: int, status: str, db: Session): + maintenancejob = ( + db.query(MaintenanceJob).filter(MaintenanceJob.Id == maintenancejob_id).first() + ) + if maintenancejob is None: + return None + maintenancejob.Status = status + db.commit() + db.refresh(maintenancejob) + return maintenancejob \ No newline at end of file diff --git a/app/db/repository/user.py b/app/db/repository/user.py index 64b3068..3064c1e 100644 --- a/app/db/repository/user.py +++ b/app/db/repository/user.py @@ -58,3 +58,20 @@ def get_car_driver(vehicle_id: int, db: Session): def list_users(db: Session, role: str = "Any"): users = db.query(User).filter((User.Role == role) | (role == "Any")).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: + return "userNotFound" + user.Email = user_data.Email + user.Name = user_data.Name + user.MiddleName = user_data.MiddleName + user.LastName = user_data.LastName + user.GovernmentId = user_data.GovernmentId + user.Address = user_data.Address + user.ContactNumber = user_data.ContactNumber + user.Role = user_data.Role + user.HashedPassword = Hasher.get_password_hash(user_data.Password) + db.commit() + db.refresh(user) + return user \ No newline at end of file diff --git a/app/db/repository/vehicle.py b/app/db/repository/vehicle.py index 2498bcf..748ce69 100644 --- a/app/db/repository/vehicle.py +++ b/app/db/repository/vehicle.py @@ -10,8 +10,7 @@ def create_new_vehicle(vehicle: CreateVehicle, db: Session): **vehicle.model_dump(), Fuel=0, Status="Inactive", - CurrentLocation=[], - MaintenanceNotes=[] + CurrentLocation=[] ) db.add(vehicle_object) db.commit() @@ -62,6 +61,8 @@ def list_vehicles(db: Session): def get_vehicle_by_id(vehicle_id: int, db: Session): vehicle = db.query(Vehicle).filter(Vehicle.Id == vehicle_id).first() + if not vehicle: + return None driver = get_car_driver(vehicle.Id, db) if driver: vehicle.AssignedDriver = driver.Id diff --git a/app/main.py b/app/main.py index a4ca6e1..5cabeba 100644 --- a/app/main.py +++ b/app/main.py @@ -27,8 +27,3 @@ app = startup() @app.get("/") def root(): return {"message": "Hello World!"} - - -@app.get("/user") -def get_users(): - return {{"name": "almaz"}, {"name": "madi"}} diff --git a/app/schemas/user.py b/app/schemas/user.py index 2410607..782fc06 100644 --- a/app/schemas/user.py +++ b/app/schemas/user.py @@ -31,3 +31,4 @@ class ShowUser(BaseModel): class Config: orm_mode = True validate_assignment = True + diff --git a/app/schemas/vehicle.py b/app/schemas/vehicle.py index 70ee787..e441adb 100644 --- a/app/schemas/vehicle.py +++ b/app/schemas/vehicle.py @@ -8,6 +8,7 @@ class CreateVehicle(BaseModel): LicensePlate: str Mileage: int Capacity: int + Type: str class OutputVehicle(BaseModel):