@@ -13,7 +13,7 @@ | |||||
## How to launch | ## How to launch | ||||
First, make sure that python is installed. Create a virtual environment (if you want to) | 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 | source /venv/bin/activate | ||||
``` | ``` | ||||
(not necessary) | (not necessary) | ||||
@@ -1 +0,0 @@ | |||||
Generic single-database configuration. |
@@ -1,85 +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 | |||||
print("Alembic env.py target_metadata: ", target_metadata) | |||||
print("Alembic env.py settings: ", settings.DATABASE_URL) | |||||
print("Alembic env.py config: ", Base) | |||||
# 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,30 +0,0 @@ | |||||
"""Edit vehicle table, fix due to SRS | |||||
Revision ID: 47f450cb5e82 | |||||
Revises: aa72d2118245 | |||||
Create Date: 2023-09-04 15:18:23.713730 | |||||
""" | |||||
from typing import Sequence, Union | |||||
from alembic import op | |||||
import sqlalchemy as sa | |||||
# revision identifiers, used by Alembic. | |||||
revision: str = '47f450cb5e82' | |||||
down_revision: Union[str, None] = 'aa72d2118245' | |||||
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! ### | |||||
pass | |||||
# ### end Alembic commands ### | |||||
def downgrade() -> None: | |||||
# ### commands auto generated by Alembic - please adjust! ### | |||||
pass | |||||
# ### end Alembic commands ### |
@@ -1,30 +0,0 @@ | |||||
"""Fix | |||||
Revision ID: 95369c9d99cc | |||||
Revises: f272ebbba83d | |||||
Create Date: 2023-09-04 16:02:51.465863 | |||||
""" | |||||
from typing import Sequence, Union | |||||
from alembic import op | |||||
import sqlalchemy as sa | |||||
# revision identifiers, used by Alembic. | |||||
revision: str = '95369c9d99cc' | |||||
down_revision: Union[str, None] = 'f272ebbba83d' | |||||
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! ### | |||||
pass | |||||
# ### end Alembic commands ### | |||||
def downgrade() -> None: | |||||
# ### commands auto generated by Alembic - please adjust! ### | |||||
pass | |||||
# ### end Alembic commands ### |
@@ -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,62 +0,0 @@ | |||||
"""Fix | |||||
Revision ID: a92339978636 | |||||
Revises: 95369c9d99cc | |||||
Create Date: 2023-09-04 16:03:42.207089 | |||||
""" | |||||
from typing import Sequence, Union | |||||
from alembic import op | |||||
import sqlalchemy as sa | |||||
# revision identifiers, used by Alembic. | |||||
revision: str = 'a92339978636' | |||||
down_revision: Union[str, None] = '95369c9d99cc' | |||||
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('vehicle', | |||||
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('CurrentLocation', sa.ARRAY(sa.String()), nullable=True), | |||||
sa.Column('Fuel', sa.Integer(), nullable=False), | |||||
sa.Column('Mileage', sa.Integer(), nullable=False), | |||||
sa.Column('Status', sa.String(), nullable=False), | |||||
sa.Column('Capacity', sa.Integer(), nullable=False), | |||||
sa.Column('MaintenanceNotes', sa.ARRAY(sa.String()), nullable=True), | |||||
sa.PrimaryKeyConstraint('Id') | |||||
) | |||||
op.create_index(op.f('ix_vehicle_Id'), 'vehicle', ['Id'], unique=False) | |||||
op.create_table('user', | |||||
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('AssignedVehicle', sa.Integer(), nullable=True), | |||||
sa.Column('HashedPassword', sa.String(), nullable=False), | |||||
sa.ForeignKeyConstraint(['AssignedVehicle'], ['vehicle.Id'], ), | |||||
sa.PrimaryKeyConstraint('Id') | |||||
) | |||||
op.create_index(op.f('ix_user_Id'), 'user', ['Id'], unique=False) | |||||
# ### end Alembic commands ### | |||||
def downgrade() -> None: | |||||
# ### commands auto generated by Alembic - please adjust! ### | |||||
op.drop_index(op.f('ix_user_Id'), table_name='user') | |||||
op.drop_table('user') | |||||
op.drop_index(op.f('ix_vehicle_Id'), table_name='vehicle') | |||||
op.drop_table('vehicle') | |||||
# ### end Alembic commands ### |
@@ -1,60 +0,0 @@ | |||||
"""Edit vehicle table, fix due to SRS | |||||
Revision ID: aa72d2118245 | |||||
Revises: 9a0214838ac8 | |||||
Create Date: 2023-09-04 15:16:55.278355 | |||||
""" | |||||
from typing import Sequence, Union | |||||
from alembic import op | |||||
import sqlalchemy as sa | |||||
from sqlalchemy.dialects import postgresql | |||||
# revision identifiers, used by Alembic. | |||||
revision: str = 'aa72d2118245' | |||||
down_revision: Union[str, None] = '9a0214838ac8' | |||||
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.drop_index('ix_vehicles_Id', table_name='vehicles') | |||||
op.drop_table('vehicles') | |||||
op.drop_index('ix_users_Id', table_name='users') | |||||
op.drop_table('users') | |||||
# ### end Alembic commands ### | |||||
def downgrade() -> None: | |||||
# ### commands auto generated by Alembic - please adjust! ### | |||||
op.create_table('users', | |||||
sa.Column('Id', sa.INTEGER(), server_default=sa.text('nextval(\'"users_Id_seq"\'::regclass)'), autoincrement=True, nullable=False), | |||||
sa.Column('Name', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('MiddleName', sa.VARCHAR(), autoincrement=False, nullable=True), | |||||
sa.Column('LastName', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('BirthDate', postgresql.TIMESTAMP(), autoincrement=False, nullable=False), | |||||
sa.Column('ContactNumber', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('Email', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('Role', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('DrivingLicenseNumber', sa.VARCHAR(), autoincrement=False, nullable=True), | |||||
sa.Column('HashedPassword', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.PrimaryKeyConstraint('Id', name='users_pkey') | |||||
) | |||||
op.create_index('ix_users_Id', 'users', ['Id'], unique=False) | |||||
op.create_table('vehicles', | |||||
sa.Column('Id', sa.INTEGER(), server_default=sa.text('nextval(\'"vehicles_Id_seq"\'::regclass)'), autoincrement=True, nullable=False), | |||||
sa.Column('Model', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('Year', sa.INTEGER(), autoincrement=False, nullable=False), | |||||
sa.Column('LicensePlate', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('Type', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('AssignedDriverIds', postgresql.ARRAY(sa.INTEGER()), autoincrement=False, nullable=True), | |||||
sa.Column('CurrentLocation', postgresql.ARRAY(sa.VARCHAR()), autoincrement=False, nullable=True), | |||||
sa.Column('Fuel', sa.INTEGER(), autoincrement=False, nullable=False), | |||||
sa.Column('Mileage', sa.INTEGER(), autoincrement=False, nullable=False), | |||||
sa.Column('MaintenanceNotes', postgresql.ARRAY(sa.VARCHAR()), autoincrement=False, nullable=True), | |||||
sa.PrimaryKeyConstraint('Id', name='vehicles_pkey') | |||||
) | |||||
op.create_index('ix_vehicles_Id', 'vehicles', ['Id'], unique=False) | |||||
# ### end Alembic commands ### |
@@ -1,61 +0,0 @@ | |||||
"""Edit driver assignment | |||||
Revision ID: f272ebbba83d | |||||
Revises: 47f450cb5e82 | |||||
Create Date: 2023-09-04 15:36:52.916595 | |||||
""" | |||||
from typing import Sequence, Union | |||||
from alembic import op | |||||
import sqlalchemy as sa | |||||
from sqlalchemy.dialects import postgresql | |||||
# revision identifiers, used by Alembic. | |||||
revision: str = 'f272ebbba83d' | |||||
down_revision: Union[str, None] = '47f450cb5e82' | |||||
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.drop_index('ix_vehicles_Id', table_name='vehicles') | |||||
op.drop_table('vehicles') | |||||
op.drop_index('ix_users_Id', table_name='users') | |||||
op.drop_table('users') | |||||
# ### end Alembic commands ### | |||||
def downgrade() -> None: | |||||
# ### commands auto generated by Alembic - please adjust! ### | |||||
op.create_table('users', | |||||
sa.Column('Id', sa.INTEGER(), server_default=sa.text('nextval(\'"users_Id_seq"\'::regclass)'), autoincrement=True, nullable=False), | |||||
sa.Column('Name', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('MiddleName', sa.VARCHAR(), autoincrement=False, nullable=True), | |||||
sa.Column('LastName', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('BirthDate', postgresql.TIMESTAMP(), autoincrement=False, nullable=False), | |||||
sa.Column('ContactNumber', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('Email', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('Role', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('DrivingLicenseNumber', sa.VARCHAR(), autoincrement=False, nullable=True), | |||||
sa.Column('HashedPassword', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.PrimaryKeyConstraint('Id', name='users_pkey') | |||||
) | |||||
op.create_index('ix_users_Id', 'users', ['Id'], unique=False) | |||||
op.create_table('vehicles', | |||||
sa.Column('Id', sa.INTEGER(), server_default=sa.text('nextval(\'"vehicles_Id_seq"\'::regclass)'), autoincrement=True, nullable=False), | |||||
sa.Column('Model', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('Year', sa.INTEGER(), autoincrement=False, nullable=False), | |||||
sa.Column('LicensePlate', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('AssignedDriverIds', postgresql.ARRAY(sa.INTEGER()), autoincrement=False, nullable=True), | |||||
sa.Column('CurrentLocation', postgresql.ARRAY(sa.VARCHAR()), autoincrement=False, nullable=True), | |||||
sa.Column('Fuel', sa.INTEGER(), autoincrement=False, nullable=False), | |||||
sa.Column('Mileage', sa.INTEGER(), autoincrement=False, nullable=False), | |||||
sa.Column('Status', sa.VARCHAR(), autoincrement=False, nullable=False), | |||||
sa.Column('Capacity', sa.INTEGER(), autoincrement=False, nullable=False), | |||||
sa.Column('MaintenanceNotes', postgresql.ARRAY(sa.VARCHAR()), autoincrement=False, nullable=True), | |||||
sa.PrimaryKeyConstraint('Id', name='vehicles_pkey') | |||||
) | |||||
op.create_index('ix_vehicles_Id', 'vehicles', ['Id'], unique=False) | |||||
# ### end Alembic commands ### |
@@ -58,3 +58,5 @@ def access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = | |||||
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}) | access_token = create_access_token(data={"sub": user.Email}) | ||||
return {"access_token": access_token, "token_type": "bearer"} | return {"access_token": access_token, "token_type": "bearer"} | ||||
@@ -14,3 +14,4 @@ def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): | |||||
to_encode.update({"exp": 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 | return encoded_jwt | ||||
@@ -1,3 +1,5 @@ | |||||
class Settings: | class Settings: | ||||
PROJECT_NAME: str = "VMS" | PROJECT_NAME: str = "VMS" | ||||
PROJECT_VERSION: str = "1.0.0" | PROJECT_VERSION: str = "1.0.0" | ||||
@@ -13,3 +15,24 @@ class Settings: | |||||
settings = Settings() | settings = Settings() | ||||
def createAdminAcc(): | |||||
from db.session import SessionLocal | |||||
from db.repository.user import create_new_user | |||||
from schemas.user import UserCreate | |||||
from core.hashing import Hasher | |||||
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,5 +1,5 @@ | |||||
from fastapi import FastAPI | from fastapi import FastAPI | ||||
from core.config import settings | |||||
from core.config import settings, createAdminAcc | |||||
from db.session import engine | from db.session import engine | ||||
from db.base import Base | from db.base import Base | ||||
from apis.base import api_router | from apis.base import api_router | ||||
@@ -12,6 +12,7 @@ def include_routes(app): # include all routes from our api/v1/ | |||||
def startup(): # start the project, and create the tables | 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) | Base.metadata.create_all(bind=engine) | ||||
createAdminAcc() | |||||
include_routes(app) | include_routes(app) | ||||
return app | return app | ||||