@@ -14,7 +14,7 @@ | |||
## How to launch | |||
First, make sure that python is installed. Create a virtual environment (if you want to) | |||
``` | |||
python -m venv venv | |||
python/python3 -m venv venv | |||
source /venv/bin/activate | |||
``` | |||
(not necessary) | |||
@@ -1 +0,0 @@ | |||
Generic single-database configuration. |
@@ -1,83 +0,0 @@ | |||
from logging.config import fileConfig | |||
from sqlalchemy import engine_from_config | |||
from sqlalchemy import pool | |||
from alembic import context | |||
from core.config import settings | |||
from db.base import Base | |||
# this is the Alembic Config object, which provides | |||
# access to the values within the .ini file in use. | |||
config = context.config | |||
config.set_main_option("sqlalchemy.url", settings.DATABASE_URL) | |||
# Interpret the config file for Python logging. | |||
# This line sets up loggers basically. | |||
if config.config_file_name is not None: | |||
fileConfig(config.config_file_name) | |||
# add your model's MetaData object here | |||
# for 'autogenerate' support | |||
# from myapp import mymodel | |||
# target_metadata = mymodel.Base.metadata | |||
target_metadata = Base.metadata | |||
# other values from the config, defined by the needs of env.py, | |||
# can be acquired: | |||
# my_important_option = config.get_main_option("my_important_option") | |||
# ... etc. | |||
def run_migrations_offline() -> None: | |||
"""Run migrations in 'offline' mode. | |||
This configures the context with just a URL | |||
and not an Engine, though an Engine is acceptable | |||
here as well. By skipping the Engine creation | |||
we don't even need a DBAPI to be available. | |||
Calls to context.execute() here emit the given string to the | |||
script output. | |||
""" | |||
url = config.get_main_option("sqlalchemy.url") | |||
context.configure( | |||
url=url, | |||
target_metadata=target_metadata, | |||
literal_binds=True, | |||
dialect_opts={"paramstyle": "named"}, | |||
) | |||
with context.begin_transaction(): | |||
context.run_migrations() | |||
def run_migrations_online() -> None: | |||
"""Run migrations in 'online' mode. | |||
In this scenario we need to create an Engine | |||
and associate a connection with the context. | |||
""" | |||
connectable = engine_from_config( | |||
config.get_section(config.config_ini_section, {}), | |||
prefix="sqlalchemy.", | |||
poolclass=pool.NullPool, | |||
) | |||
with connectable.connect() as connection: | |||
context.configure(connection=connection, target_metadata=target_metadata) | |||
with context.begin_transaction(): | |||
context.run_migrations() | |||
if context.is_offline_mode(): | |||
run_migrations_offline() | |||
else: | |||
run_migrations_online() |
@@ -1,26 +0,0 @@ | |||
"""${message} | |||
Revision ID: ${up_revision} | |||
Revises: ${down_revision | comma,n} | |||
Create Date: ${create_date} | |||
""" | |||
from typing import Sequence, Union | |||
from alembic import op | |||
import sqlalchemy as sa | |||
${imports if imports else ""} | |||
# revision identifiers, used by Alembic. | |||
revision: str = ${repr(up_revision)} | |||
down_revision: Union[str, None] = ${repr(down_revision)} | |||
branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)} | |||
depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)} | |||
def upgrade() -> None: | |||
${upgrades if upgrades else "pass"} | |||
def downgrade() -> None: | |||
${downgrades if downgrades else "pass"} |
@@ -1,60 +0,0 @@ | |||
"""create User and Vehicle tables | |||
Revision ID: 9a0214838ac8 | |||
Revises: | |||
Create Date: 2023-09-01 13:31:01.324861 | |||
""" | |||
from typing import Sequence, Union | |||
from alembic import op | |||
import sqlalchemy as sa | |||
# revision identifiers, used by Alembic. | |||
revision: str = '9a0214838ac8' | |||
down_revision: Union[str, None] = None | |||
branch_labels: Union[str, Sequence[str], None] = None | |||
depends_on: Union[str, Sequence[str], None] = None | |||
def upgrade() -> None: | |||
# ### commands auto generated by Alembic - please adjust! ### | |||
op.create_table('users', | |||
sa.Column('Id', sa.Integer(), nullable=False), | |||
sa.Column('Name', sa.String(), nullable=False), | |||
sa.Column('MiddleName', sa.String(), nullable=True), | |||
sa.Column('LastName', sa.String(), nullable=False), | |||
sa.Column('BirthDate', sa.DateTime(), nullable=False), | |||
sa.Column('ContactNumber', sa.String(), nullable=False), | |||
sa.Column('Email', sa.String(), nullable=False), | |||
sa.Column('Role', sa.String(), nullable=False), | |||
sa.Column('DrivingLicenseNumber', sa.String(), nullable=True), | |||
sa.Column('HashedPassword', sa.String(), nullable=False), | |||
sa.PrimaryKeyConstraint('Id') | |||
) | |||
op.create_index(op.f('ix_users_Id'), 'users', ['Id'], unique=False) | |||
op.create_table('vehicles', | |||
sa.Column('Id', sa.Integer(), nullable=False), | |||
sa.Column('Model', sa.String(), nullable=False), | |||
sa.Column('Year', sa.Integer(), nullable=False), | |||
sa.Column('LicensePlate', sa.String(), nullable=False), | |||
sa.Column('Type', sa.String(), nullable=False), | |||
sa.Column('AssignedDriverIds', sa.ARRAY(sa.Integer()), nullable=True), | |||
sa.Column('CurrentLocation', sa.ARRAY(sa.String()), nullable=True), | |||
sa.Column('Fuel', sa.Integer(), nullable=False), | |||
sa.Column('Mileage', sa.Integer(), nullable=False), | |||
sa.Column('MaintenanceNotes', sa.ARRAY(sa.String()), nullable=True), | |||
sa.PrimaryKeyConstraint('Id') | |||
) | |||
op.create_index(op.f('ix_vehicles_Id'), 'vehicles', ['Id'], unique=False) | |||
# ### end Alembic commands ### | |||
def downgrade() -> None: | |||
# ### commands auto generated by Alembic - please adjust! ### | |||
op.drop_index(op.f('ix_vehicles_Id'), table_name='vehicles') | |||
op.drop_table('vehicles') | |||
op.drop_index(op.f('ix_users_Id'), table_name='users') | |||
op.drop_table('users') | |||
# ### end Alembic commands ### |
@@ -1,3 +1,4 @@ | |||
from datetime import datetime | |||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm | |||
from fastapi import Depends, APIRouter | |||
from sqlalchemy.orm import Session | |||
@@ -7,20 +8,23 @@ from db.session import get_db | |||
from core.hashing import Hasher | |||
from core.config import settings | |||
from jose import JWTError, jwt | |||
from schemas.token import Token | |||
from schemas.token import Token, TokenPayload | |||
from db.repository.user import get_user_by_email, get_user_by_phone | |||
from core.auth import create_access_token | |||
router = APIRouter() | |||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token") | |||
oauth2_scheme = OAuth2PasswordBearer( | |||
tokenUrl="/token", | |||
) | |||
def authenticate_user(login: str, password: str, db: Session): | |||
print("Trying to auth...") | |||
user = None | |||
if ("@" in login): | |||
if "@" in login: | |||
user = get_user_by_email(email=login, db=db) | |||
elif ("+" in login): | |||
elif "+" in login: | |||
user = get_user_by_phone(phone=login, db=db) | |||
else: | |||
return False | |||
@@ -31,30 +35,61 @@ def authenticate_user(login: str, password: str, db: Session): | |||
return user | |||
def get_current_user(token: Annotated[str, Depends(oauth2_scheme)], db: Annotated[Session, Depends(get_db)]): | |||
def get_current_user( | |||
token: Annotated[str, Depends(oauth2_scheme)], | |||
db: Annotated[Session, Depends(get_db)], | |||
): | |||
print("Getting current user...") | |||
try: | |||
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]) | |||
payload = jwt.decode( | |||
token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM] | |||
) | |||
token_data = TokenPayload(**payload) | |||
if datetime.fromtimestamp(token_data.exp) < datetime.now(): | |||
raise HTTPException( | |||
status_code=status.HTTP_401_UNAUTHORIZED, | |||
detail="Session expired. Please login again.", | |||
) | |||
username: str = payload.get("sub") | |||
if username is None: | |||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials") | |||
raise HTTPException( | |||
status_code=status.HTTP_401_UNAUTHORIZED, | |||
detail="Could not validate credentials", | |||
) | |||
except JWTError: | |||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials") | |||
if ("@" in username): | |||
raise HTTPException( | |||
status_code=status.HTTP_401_UNAUTHORIZED, | |||
detail="Could not validate credentials", | |||
) | |||
if "@" in username: | |||
user = get_user_by_email(email=username, db=db) | |||
elif ("+" in username): | |||
elif "+" in username: | |||
user = get_user_by_phone(phone=username, db=db) | |||
else: | |||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials") | |||
raise HTTPException( | |||
status_code=status.HTTP_401_UNAUTHORIZED, | |||
detail="Could not validate credentials", | |||
) | |||
return user | |||
@router.post("/token", response_model=Token) | |||
def access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)): | |||
def access_token( | |||
form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db) | |||
): | |||
print("Getting token...") | |||
user = authenticate_user(form_data.username, form_data.password, db) | |||
print(user) | |||
if not user: | |||
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid username or password") | |||
raise HTTPException( | |||
status_code=status.HTTP_401_UNAUTHORIZED, | |||
detail="Invalid username or password", | |||
) | |||
access_token = create_access_token(data={"sub": user.Email}) | |||
return {"access_token": access_token, "token_type": "bearer"} | |||
print("TOKENS ARE: ") | |||
print(access_token) | |||
return { | |||
"access_token": access_token, | |||
"token_type": "bearer", | |||
} |
@@ -14,9 +14,15 @@ router = APIRouter() | |||
@router.post("/", response_model=ShowUser, status_code=status.HTTP_201_CREATED) | |||
def create_user(user: UserCreate, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)): | |||
if current_user.Role != "Admin": | |||
def create_user( | |||
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") | |||
# if current_user.Role != "Admin": | |||
# raise HTTPException(status_code=403, detail="You are not authorized to perform this action") | |||
user = create_new_user(user=user, db=db) | |||
return user | |||
@@ -31,7 +37,10 @@ def get_all_users(db: Session = Depends(get_db), role: str = None): | |||
@router.get("/me", response_model=ShowUser, status_code=status.HTTP_200_OK) | |||
def get_user_me(current_user: Annotated[User, Depends(get_current_user)], db: Annotated[Session, Depends(get_db)]): | |||
def get_user_me( | |||
current_user: Annotated[User, Depends(get_current_user)], | |||
db: Annotated[Session, Depends(get_db)], | |||
): | |||
print("Getting current user...") | |||
return current_user | |||
@@ -3,7 +3,7 @@ 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, UpdateVehicle | |||
from schemas.vehicle import OutputVehicle, CreateVehicle, UpdateVehicle, VehicleLocation | |||
from db.repository.vehicle import ( | |||
create_new_vehicle, | |||
assign_vehicle_driver, | |||
@@ -11,6 +11,7 @@ from db.repository.vehicle import ( | |||
get_vehicle_by_id, | |||
replace_vehicle_data, | |||
delete_vehicle_data, | |||
update_vehicle_geoloc, | |||
) | |||
from db.models.user import User | |||
from apis.v1.route_auth import get_current_user | |||
@@ -19,9 +20,16 @@ router = APIRouter() | |||
@router.post("/", response_model=OutputVehicle, status_code=status.HTTP_201_CREATED) | |||
async def create_vehicle(vehicle: CreateVehicle, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)): | |||
async def create_vehicle( | |||
vehicle: CreateVehicle, | |||
db: Session = Depends(get_db), | |||
current_user: User = Depends(get_current_user), | |||
): | |||
print(current_user.Role) | |||
if current_user.Role != "Admin": | |||
raise HTTPException(status_code=403, detail="You are not authorized to perform this action") | |||
raise HTTPException( | |||
status_code=403, detail="You are not authorized to perform this action" | |||
) | |||
vehicle = create_new_vehicle(vehicle=vehicle, db=db) | |||
return vehicle | |||
@@ -52,9 +60,16 @@ async def create_vehicle(vehicle: CreateVehicle, db: Session = Depends(get_db), | |||
response_model=OutputVehicle, | |||
status_code=status.HTTP_200_OK, | |||
) | |||
async def assign_driver(vehicle_id: int, driver_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)): | |||
async def assign_driver( | |||
vehicle_id: int, | |||
driver_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") | |||
raise HTTPException( | |||
status_code=403, detail="You are not authorized to perform this action" | |||
) | |||
vehicle = assign_vehicle_driver(vehicle_id=vehicle_id, driver_id=driver_id, db=db) | |||
if vehicle == "nodriver": | |||
raise HTTPException( | |||
@@ -67,7 +82,7 @@ async def assign_driver(vehicle_id: int, driver_id: int, db: Session = Depends(g | |||
if vehicle == "alreadyassigned": | |||
raise HTTPException( | |||
status_code=400, | |||
detail=f"Driver with id {driver_id} is already assigned to vehicle with id {vehicle_id}", | |||
detail=f"A driver is already assigned to vehicle with id {vehicle_id}", | |||
) | |||
return vehicle | |||
@@ -92,23 +107,60 @@ async def get_vehicle(vehicle_id: int, db: Session = Depends(get_db)): | |||
"/{vehicle_id}", response_model=OutputVehicle, status_code=status.HTTP_200_OK | |||
) | |||
def update_vehicle( | |||
vehicle_id: int, vehicle: UpdateVehicle, db: Session = Depends(get_db), current_user: User = Depends(get_current_user) | |||
vehicle_id: int, | |||
vehicle: UpdateVehicle, | |||
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") | |||
raise HTTPException( | |||
status_code=403, detail="You are not authorized to perform this action" | |||
) | |||
vehicleRes = replace_vehicle_data(id=vehicle_id, vehicle=vehicle, db=db) | |||
if vehicleRes == "vehicleNotFound": | |||
raise HTTPException(status_code=404, detail="Vehicle not found") | |||
elif vehicleRes == "badreq": | |||
raise HTTPException(status_code=502, detail="Bad request") | |||
elif vehicleRes == "driverNotFound": | |||
raise HTTPException(status_code=404, detail="Driver not found") | |||
return vehicleRes | |||
@router.delete("/{vehicle_id}", status_code=status.HTTP_200_OK) | |||
def delete_vehicle(vehicle_id: int, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)): | |||
def delete_vehicle( | |||
vehicle_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") | |||
raise HTTPException( | |||
status_code=403, detail="You are not authorized to perform this action" | |||
) | |||
result = delete_vehicle_data(id=vehicle_id, db=db) | |||
if result == "vehicleNotFound": | |||
raise HTTPException(status_code=404, detail="Vehicle not found") | |||
return {"msg": "Vehicle deleted successfully"} | |||
@router.post("/{vehicle_id}/location", status_code=status.HTTP_200_OK) | |||
def update_vehicle_location( | |||
vehicle_id: int, | |||
location: VehicleLocation, | |||
current_user: User = Depends(get_current_user), | |||
db: Session = Depends(get_db), | |||
): | |||
print(current_user) | |||
print(current_user.Name) | |||
if current_user.Role != "Driver": | |||
raise HTTPException( | |||
status_code=403, detail="You are not authorized to perform this action" | |||
) | |||
if current_user.AssignedVehicle != vehicle_id: | |||
raise HTTPException( | |||
status_code=403, detail="You are not the correct car driver" | |||
) | |||
print("FUNNY") | |||
vehicle = update_vehicle_geoloc(vehicle_id=vehicle_id, location=location, db=db) | |||
if vehicle == "vehiclenotfound": | |||
raise HTTPException(status_code=404, detail="Vehicle not found") | |||
return vehicle |
@@ -12,5 +12,7 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): | |||
else: | |||
expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE) | |||
to_encode.update({"exp": expire}) | |||
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) | |||
encoded_jwt = jwt.encode( | |||
to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM | |||
) | |||
return encoded_jwt |
@@ -7,9 +7,31 @@ class Settings: | |||
POSTGRES_PORT: str = "5432" | |||
POSTGRES_DB: str = "VMSData" | |||
DATABASE_URL = f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_SERVER}:{POSTGRES_PORT}/{POSTGRES_DB}" | |||
ACCESS_TOKEN_EXPIRE: int = 30 | |||
ACCESS_TOKEN_EXPIRE: int = 60 * 24 * 7 # 7 days | |||
SECRET_KEY: str = "tH357aC6oA7ofCaN3yTffYkRh" | |||
ALGORITHM: str = "HS256" | |||
settings = Settings() | |||
def createAdminAcc(): | |||
from db.session import SessionLocal | |||
from db.repository.user import create_new_user | |||
from schemas.user import UserCreate | |||
from db.models.user import User | |||
db = SessionLocal() | |||
user = UserCreate( | |||
Email="madi.turgunov@nu.edu.kz", | |||
Password="1234567", | |||
Name="Madi", | |||
LastName="Turgunov", | |||
ContactNumber="+77071234567", | |||
Role="Admin", | |||
BirthDate="2000-01-01T00:00:00+06:00", | |||
) | |||
if db.query(User).filter(User.Email == user.Email).first(): | |||
return False | |||
create_new_user(user=user, db=db) | |||
return True |
@@ -1,4 +1,4 @@ | |||
# Base class for all sqlalchemy models | |||
from sqlalchemy.ext.declarative import declarative_base | |||
Base = declarative_base() | |||
from db.base_class import Base | |||
from db.models.user import User | |||
from db.models.vehicle import Vehicle |
@@ -0,0 +1,14 @@ | |||
from typing import Any | |||
from sqlalchemy.ext.declarative import as_declarative, declared_attr | |||
@as_declarative() | |||
class Base: | |||
id: Any | |||
__name__: str | |||
# Generate __tablename__ automatically | |||
@declared_attr | |||
def __tablename__(cls) -> str: | |||
return cls.__name__.lower() |
@@ -1,10 +1,10 @@ | |||
# PostgreSQL table model for users | |||
from sqlalchemy import Column, Integer, String, DateTime | |||
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey | |||
from sqlalchemy.orm import relationship | |||
from db.base import Base | |||
class User(Base): | |||
__tablename__ = "users" | |||
Id = Column(Integer, primary_key=True, index=True) | |||
Name = Column(String, nullable=False) | |||
MiddleName = Column(String, nullable=True) | |||
@@ -14,4 +14,6 @@ class User(Base): | |||
Email = Column(String, nullable=False) | |||
Role = Column(String, nullable=False) | |||
DrivingLicenseNumber = Column(String, nullable=True) | |||
AssignedVehicle = Column(Integer, ForeignKey("vehicle.Id"), nullable=True) | |||
vehicle = relationship("Vehicle", back_populates="driver") | |||
HashedPassword = Column(String, nullable=False) |
@@ -5,18 +5,19 @@ from sqlalchemy import ( | |||
String, | |||
ARRAY, | |||
) | |||
from sqlalchemy.orm import relationship | |||
from db.base import Base | |||
class Vehicle(Base): | |||
__tablename__ = "vehicles" | |||
Id = Column(Integer, primary_key=True, index=True) | |||
Model = Column(String, nullable=False) | |||
Year = Column(Integer, nullable=False) | |||
LicensePlate = Column(String, nullable=False) | |||
Type = Column(String, nullable=False) | |||
AssignedDriverIds = Column(ARRAY(Integer), nullable=True) | |||
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) | |||
driver = relationship("User", back_populates="vehicle") |
@@ -47,6 +47,13 @@ def verify_driver_exists(driver_id: int, db: Session): | |||
return True | |||
def get_car_driver(vehicle_id: int, db: Session): | |||
driver = db.query(User).filter(User.AssignedVehicle == vehicle_id).first() | |||
if not driver: | |||
return False | |||
return driver | |||
def list_users(db: Session, role: str = "Any"): | |||
users = db.query(User).filter((User.Role == role) | (role == "Any")).all() | |||
return users |
@@ -1,51 +1,72 @@ | |||
from sqlalchemy.orm import Session | |||
from schemas.vehicle import CreateVehicle, UpdateVehicle | |||
from schemas.vehicle import CreateVehicle, UpdateVehicle, VehicleLocation | |||
from db.models.vehicle import Vehicle | |||
from db.repository.user import verify_driver_exists | |||
from db.base import User | |||
from db.repository.user import get_car_driver | |||
def create_new_vehicle(vehicle: CreateVehicle, db: Session): | |||
vehicle_object = Vehicle( | |||
**vehicle.model_dump(), | |||
Fuel=0, | |||
AssignedDriverIds=[], | |||
Status="Inactive", | |||
CurrentLocation=[], | |||
MaintenanceNotes=[] | |||
) | |||
db.add(vehicle_object) | |||
db.commit() | |||
db.refresh(vehicle_object) | |||
return vehicle | |||
return vehicle_object | |||
def update_vehicle_geoloc(vehicle_id: int, location: VehicleLocation, db: Session): | |||
vehicle_db = db.query(Vehicle).filter(Vehicle.Id == vehicle_id) | |||
vehicle_object = vehicle_db.first() | |||
if not vehicle_object: | |||
return "vehiclenotfound" | |||
print("Location: " + str(location.CurrentLocation)) | |||
vehicle_object.CurrentLocation = location.CurrentLocation | |||
db.add(vehicle_object) | |||
db.commit() | |||
db.refresh(vehicle_object) | |||
return vehicle_object | |||
def assign_vehicle_driver(vehicle_id: int, driver_id: int, db: Session): | |||
vehicledb = db.query(Vehicle).filter(Vehicle.Id == vehicle_id) | |||
vehicle = vehicledb.first() | |||
driver = ( | |||
db.query(User).filter((User.Id == driver_id) & (User.Role == "Driver")).first() | |||
) | |||
print(driver) | |||
vehicle = db.query(Vehicle).filter(Vehicle.Id == vehicle_id).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" | |||
if not driver: | |||
return "nodriver" | |||
driver.AssignedVehicle = vehicle_id | |||
db.add(driver) | |||
db.commit() | |||
return vehicle | |||
def list_vehicles(db: Session): | |||
vehicles = db.query(Vehicle).all() | |||
# assign AssignedDriver to all vehicles based on their drivers | |||
for vehicle in vehicles: | |||
driver = get_car_driver(vehicle.Id, db) | |||
if driver: | |||
vehicle.AssignedDriver = driver.Id | |||
else: | |||
vehicle.AssignedDriver = None | |||
return vehicles | |||
def get_vehicle_by_id(vehicle_id: int, db: Session): | |||
vehicle = db.query(Vehicle).filter(Vehicle.Id == vehicle_id).first() | |||
driver = get_car_driver(vehicle.Id, db) | |||
if driver: | |||
vehicle.AssignedDriver = driver.Id | |||
else: | |||
vehicle.AssignedDriver = None | |||
return vehicle | |||
@@ -54,18 +75,22 @@ def replace_vehicle_data(id: int, vehicle: UpdateVehicle, db: Session): | |||
vehicle_object = vehicle_db.first() | |||
if not vehicle_object: | |||
return "vehiclenotfound" | |||
vehicle_object.AssignedDriverIds = vehicle.AssignedDriverIds | |||
vehicle_object.CurrentLocation = vehicle.CurrentLocation | |||
vehicle_object.Fuel = vehicle.Fuel | |||
vehicle_object.LicensePlate = vehicle.LicensePlate | |||
vehicle_object.MaintenanceNotes = vehicle.MaintenanceNotes | |||
vehicle_object.Mileage = vehicle.Mileage | |||
vehicle_object.Model = vehicle.Model | |||
vehicle_object.Type = vehicle.Type | |||
vehicle_object.Status = vehicle.Status | |||
res = assign_vehicle_driver(id, vehicle.AssignedDriver, db) | |||
if res == "nodriver": | |||
return "driverNotFound" | |||
vehicle_object.Capacity = vehicle.Capacity | |||
vehicle_object.Year = vehicle.Year | |||
print(vehicle_object) | |||
db.add(vehicle_object) | |||
db.commit() | |||
vehicle_object.AssignedDriver = vehicle.AssignedDriver | |||
return vehicle_object | |||
@@ -1,5 +1,5 @@ | |||
from fastapi import FastAPI | |||
from core.config import settings | |||
from core.config import settings, createAdminAcc | |||
from db.session import engine | |||
from db.base import Base | |||
from apis.base import api_router | |||
@@ -10,8 +10,12 @@ def include_routes(app): # include all routes from our api/v1/ | |||
def startup(): # start the project, and create the tables | |||
app = FastAPI(title=settings.PROJECT_NAME, version=settings.PROJECT_VERSION) | |||
app = FastAPI( | |||
title=settings.PROJECT_NAME, | |||
version=settings.PROJECT_VERSION, | |||
) | |||
Base.metadata.create_all(bind=engine) | |||
createAdminAcc() | |||
include_routes(app) | |||
return app | |||
@@ -4,3 +4,8 @@ from pydantic import BaseModel | |||
class Token(BaseModel): | |||
access_token: str | |||
token_type: str | |||
class TokenPayload(BaseModel): | |||
sub: str = None | |||
exp: int = None |
@@ -8,7 +8,7 @@ class UserCreate(BaseModel): | |||
Email: EmailStr | |||
Password: str = Field(..., min_length=7, max_length=20) | |||
Name: str = Field(..., min_length=3, max_length=50) | |||
MiddleName: str = Field(None, min_length=3, max_length=50) | |||
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(...) | |||
@@ -19,12 +19,14 @@ class UserCreate(BaseModel): | |||
class ShowUser(BaseModel): | |||
Id: int | |||
Name: str | |||
MiddleName: str | |||
MiddleName: str | None | |||
LastName: str | |||
ContactNumber: str | |||
BirthDate: datetime | |||
Email: EmailStr | |||
Role: str | |||
AssignedVehicle: int | None | |||
class Config: | |||
orm_mode = True | |||
validate_assignment = True |
@@ -3,12 +3,11 @@ from pydantic import BaseModel | |||
class CreateVehicle(BaseModel): | |||
Id: int | |||
Model: str | |||
Year: int | |||
LicensePlate: str | |||
Type: str | |||
Mileage: int | |||
Capacity: int | |||
class OutputVehicle(BaseModel): | |||
@@ -16,21 +15,27 @@ 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 | |||
AssignedDriver: Optional[int] = None | |||
Capacity: int | |||
Status: str | |||
class UpdateVehicle(BaseModel): | |||
Model: str | |||
Year: int | |||
LicensePlate: str | |||
Type: str | |||
Capacity: int | |||
Mileage: int | |||
Status: str | |||
CurrentLocation: Optional[list[str]] = None | |||
Fuel: Optional[int] = 0 | |||
MaintenanceNotes: Optional[list[str]] = None | |||
AssignedDriverIds: Optional[list[int]] = None | |||
AssignedDriver: Optional[int] = None | |||
class VehicleLocation(BaseModel): | |||
CurrentLocation: list[str] |