| @@ -13,7 +13,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,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") | |||
| access_token = create_access_token(data={"sub": user.Email}) | |||
| 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}) | |||
| encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM) | |||
| return encoded_jwt | |||
| @@ -1,3 +1,5 @@ | |||
| class Settings: | |||
| PROJECT_NAME: str = "VMS" | |||
| PROJECT_VERSION: str = "1.0.0" | |||
| @@ -13,3 +15,24 @@ class 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 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 | |||
| @@ -12,6 +12,7 @@ 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) | |||
| Base.metadata.create_all(bind=engine) | |||
| createAdminAcc() | |||
| include_routes(app) | |||
| return app | |||