worked out how to migrate and got the database working
This commit is contained in:
parent
39ba464237
commit
5393ea5669
@ -11,7 +11,7 @@ script_location = %(here)s/pillar_tool/db/migrations
|
|||||||
# Uncomment the line below if you want the files to be prepended with date and time
|
# Uncomment the line below if you want the files to be prepended with date and time
|
||||||
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
|
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
|
||||||
# for all available tokens
|
# for all available tokens
|
||||||
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
|
file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
|
||||||
|
|
||||||
# sys.path path, will be prepended to sys.path if present.
|
# sys.path path, will be prepended to sys.path if present.
|
||||||
# defaults to the current working directory. for multiple paths, the path separator
|
# defaults to the current working directory. for multiple paths, the path separator
|
||||||
|
|||||||
@ -1,46 +0,0 @@
|
|||||||
|
|
||||||
# load config so everything else can work
|
|
||||||
from pillar_tool.util import load_config, config
|
|
||||||
load_config()
|
|
||||||
|
|
||||||
from contextlib import asynccontextmanager
|
|
||||||
|
|
||||||
from fastapi import FastAPI
|
|
||||||
from starlette.middleware.authentication import AuthenticationMiddleware
|
|
||||||
from starlette.requests import Request
|
|
||||||
from fastapi.responses import HTMLResponse, PlainTextResponse
|
|
||||||
from starlette.responses import JSONResponse
|
|
||||||
|
|
||||||
from pillar_tool.middleware.basicauth_backend import BasicAuthBackend
|
|
||||||
from pillar_tool.db import run_db_migrations
|
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
|
||||||
async def app_lifespan(app: FastAPI):
|
|
||||||
run_db_migrations()
|
|
||||||
|
|
||||||
yield
|
|
||||||
|
|
||||||
|
|
||||||
def on_auth_error(request: Request, exc: Exception):
|
|
||||||
response = PlainTextResponse(str(exc), status_code=401)
|
|
||||||
response.headers["WWW-Authenticate"] = "Basic"
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
def on_general_error(request: Request, exc: Exception):
|
|
||||||
print("wtf?")
|
|
||||||
response = PlainTextResponse(str(exc), status_code=500)
|
|
||||||
|
|
||||||
app = FastAPI(lifespan=app_lifespan)
|
|
||||||
app.add_middleware(AuthenticationMiddleware, backend=BasicAuthBackend(), on_error=on_auth_error)
|
|
||||||
app.exception_handler(Exception)(on_general_error)
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
|
||||||
async def root():
|
|
||||||
return {"message": "Hello World"}
|
|
||||||
|
|
||||||
@app.get("/pillar/{host}")
|
|
||||||
async def pillar(host: str):
|
|
||||||
return JSONResponse(content=collect_pillar_data(host))
|
|
||||||
Binary file not shown.
@ -1,26 +1 @@
|
|||||||
from os import lockf, F_LOCK
|
|
||||||
from os.path import dirname, realpath
|
|
||||||
|
|
||||||
from alembic.config import Config
|
|
||||||
from alembic.command import upgrade, check, util
|
|
||||||
from pillar_tool.util import config
|
|
||||||
|
|
||||||
|
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
cfg = config()
|
|
||||||
user = cfg.db.user
|
|
||||||
password = cfg.db.password
|
|
||||||
host = cfg.db.host
|
|
||||||
port = cfg.db.port
|
|
||||||
database = cfg.db.database
|
|
||||||
alembic_cfg = Config()
|
|
||||||
alembic_cfg.set_main_option('script_location', f'{dirname(realpath(__file__))}/migrations')
|
|
||||||
alembic_cfg.set_main_option('sqlalchemy.url', f'postgresql://{user}:{password}@{host}:{port}/{database}')
|
|
||||||
alembic_cfg.set_main_option('prepend_sys_path', '.')
|
|
||||||
|
|
||||||
|
|
||||||
def run_db_migrations():
|
|
||||||
with open(realpath(__file__), 'a') as f:
|
|
||||||
lockf(f.fileno(), F_LOCK, 0)
|
|
||||||
upgrade(config=alembic_cfg, revision='head')
|
|
||||||
|
|||||||
4
pillar_tool/db/base_model.py
Normal file
4
pillar_tool/db/base_model.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from sqlalchemy.orm import declarative_base
|
||||||
|
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
@ -1,9 +1,32 @@
|
|||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import Session, sessionmaker, declarative_base
|
from sqlalchemy.orm import sessionmaker
|
||||||
from sqlalchemy.sql.annotation import Annotated
|
|
||||||
|
|
||||||
from pillar_tool.util import config
|
from pillar_tool.util import config
|
||||||
|
|
||||||
|
from os import lockf, F_LOCK
|
||||||
|
from os.path import dirname, realpath
|
||||||
|
|
||||||
|
from alembic.config import Config
|
||||||
|
from alembic.command import upgrade, check, util
|
||||||
|
from pillar_tool.util import config
|
||||||
|
|
||||||
|
def run_db_migrations():
|
||||||
|
cfg = config()
|
||||||
|
user = cfg.db.user
|
||||||
|
password = cfg.db.password
|
||||||
|
host = cfg.db.host
|
||||||
|
port = cfg.db.port
|
||||||
|
database = cfg.db.database
|
||||||
|
alembic_cfg = Config()
|
||||||
|
alembic_cfg.set_main_option('script_location', f'{dirname(realpath(__file__))}/migrations')
|
||||||
|
alembic_cfg.set_main_option('sqlalchemy.url', f'postgresql://{user}:{password}@{host}:{port}/{database}')
|
||||||
|
alembic_cfg.set_main_option('prepend_sys_path', '.')
|
||||||
|
|
||||||
|
with open(realpath(__file__), 'a') as f:
|
||||||
|
lockf(f.fileno(), F_LOCK, 0)
|
||||||
|
upgrade(config=alembic_cfg, revision='head')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cfg = config()
|
cfg = config()
|
||||||
SessionLocal = sessionmaker(
|
SessionLocal = sessionmaker(
|
||||||
@ -14,20 +37,7 @@ SessionLocal = sessionmaker(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
Base = declarative_base()
|
|
||||||
|
|
||||||
def get_connection():
|
def get_connection():
|
||||||
session = SessionLocal()
|
return SessionLocal()
|
||||||
# noinspection PyBroadException
|
|
||||||
try:
|
|
||||||
yield session
|
|
||||||
except:
|
|
||||||
session.rollback()
|
|
||||||
session.close()
|
|
||||||
else:
|
|
||||||
session.commit()
|
|
||||||
session.close()
|
|
||||||
|
|
||||||
|
|
||||||
DB = Annotated[Session, get_connection()]
|
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import tomllib
|
import tomllib
|
||||||
|
from inspect import stack
|
||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
|
|
||||||
from sqlalchemy import engine_from_config
|
from sqlalchemy import engine_from_config
|
||||||
@ -6,7 +7,6 @@ from sqlalchemy import pool
|
|||||||
|
|
||||||
from alembic import context
|
from alembic import context
|
||||||
|
|
||||||
from pillar_tool.db.database import Base
|
|
||||||
|
|
||||||
# this is the Alembic Config object, which provides
|
# this is the Alembic Config object, which provides
|
||||||
# access to the values within the .ini file in use.
|
# access to the values within the .ini file in use.
|
||||||
@ -21,6 +21,7 @@ if config.config_file_name is not None:
|
|||||||
# for 'autogenerate' support
|
# for 'autogenerate' support
|
||||||
# from myapp import mymodel
|
# from myapp import mymodel
|
||||||
# target_metadata = mymodel.Base.metadata
|
# target_metadata = mymodel.Base.metadata
|
||||||
|
from pillar_tool.db.base_model import Base
|
||||||
target_metadata = Base.metadata
|
target_metadata = Base.metadata
|
||||||
|
|
||||||
# other values from the config, defined by the needs of env.py,
|
# other values from the config, defined by the needs of env.py,
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
"""added email to user
|
||||||
|
|
||||||
|
Revision ID: f6c806bab641
|
||||||
|
Revises: e1f390264396
|
||||||
|
Create Date: 2025-12-27 11:52:45.372890
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = 'f6c806bab641'
|
||||||
|
down_revision: Union[str, Sequence[str], None] = 'e1f390264396'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Upgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('pillar_tool_user', sa.Column('email', sa.String(), nullable=True))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Downgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('pillar_tool_user', 'email')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
"""username is now unique
|
||||||
|
|
||||||
|
Revision ID: ae8de58aa10c
|
||||||
|
Revises: f6c806bab641
|
||||||
|
Create Date: 2025-12-27 11:58:25.636598
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = 'ae8de58aa10c'
|
||||||
|
down_revision: Union[str, Sequence[str], None] = 'f6c806bab641'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Upgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_unique_constraint('pillar_tool_user_unique_constraint_username', 'pillar_tool_user', ['username'])
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Downgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_constraint('pillar_tool_user_unique_constraint_username', 'pillar_tool_user', type_='unique')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
"""added unique to permission and role name
|
||||||
|
|
||||||
|
Revision ID: 4cc7f4e295f1
|
||||||
|
Revises: ae8de58aa10c
|
||||||
|
Create Date: 2025-12-27 11:59:54.246224
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = '4cc7f4e295f1'
|
||||||
|
down_revision: Union[str, Sequence[str], None] = 'ae8de58aa10c'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Upgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.create_unique_constraint('pillar_tool_permission_unique_constraint_name', 'pillar_tool_permission', ['name'])
|
||||||
|
op.create_unique_constraint('pillar_tool_role_unique_constraint_name', 'pillar_tool_role', ['name'])
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Downgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_constraint('pillar_tool_role_unique_constraint_name', 'pillar_tool_role', type_='unique')
|
||||||
|
op.drop_constraint('pillar_tool_permission_unique_constraint_name', 'pillar_tool_permission', type_='unique')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -1,6 +1,6 @@
|
|||||||
from sqlalchemy import Column, String, UUID, ForeignKey
|
from sqlalchemy import Column, String, UUID, ForeignKey, UniqueConstraint
|
||||||
|
|
||||||
from pillar_tool.db.database import Base
|
from pillar_tool.db.base_model import Base
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -10,17 +10,30 @@ class User(Base):
|
|||||||
username = Column(String, nullable=False)
|
username = Column(String, nullable=False)
|
||||||
pw_hash = Column(String, nullable=False)
|
pw_hash = Column(String, nullable=False)
|
||||||
pw_salt = Column(String, nullable=False)
|
pw_salt = Column(String, nullable=False)
|
||||||
|
email = Column(String, nullable=True)
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
UniqueConstraint('username', name='pillar_tool_user_unique_constraint_username'),
|
||||||
|
)
|
||||||
|
|
||||||
class Role(Base):
|
class Role(Base):
|
||||||
__tablename__ = 'pillar_tool_role'
|
__tablename__ = 'pillar_tool_role'
|
||||||
id = Column(UUID, primary_key=True)
|
id = Column(UUID, primary_key=True)
|
||||||
name = Column(String, nullable=False)
|
name = Column(String, nullable=False)
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
UniqueConstraint('name', name='pillar_tool_role_unique_constraint_name'),
|
||||||
|
)
|
||||||
|
|
||||||
class Permission(Base):
|
class Permission(Base):
|
||||||
__tablename__ = 'pillar_tool_permission'
|
__tablename__ = 'pillar_tool_permission'
|
||||||
id = Column(UUID, primary_key=True)
|
id = Column(UUID, primary_key=True)
|
||||||
name = Column(String, nullable=False)
|
name = Column(String, nullable=False)
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
UniqueConstraint('name', name='pillar_tool_permission_unique_constraint_name'),
|
||||||
|
)
|
||||||
|
|
||||||
class RolePermission(Base):
|
class RolePermission(Base):
|
||||||
__tablename__ = 'pillar_tool_role_permission'
|
__tablename__ = 'pillar_tool_role_permission'
|
||||||
role_id = Column(UUID, ForeignKey("pillar_tool_role.id"), primary_key=True)
|
role_id = Column(UUID, ForeignKey("pillar_tool_role.id"), primary_key=True)
|
||||||
|
|||||||
0
pillar_tool/db/queries/__init__.py
Normal file
0
pillar_tool/db/queries/__init__.py
Normal file
45
pillar_tool/db/queries/auth_queries.py
Normal file
45
pillar_tool/db/queries/auth_queries.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import pwd
|
||||||
|
import uuid
|
||||||
|
|
||||||
|
from sqlalchemy import select, insert
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
from pillar_tool.db.models.user import User
|
||||||
|
|
||||||
|
from Crypto.Hash import SHA3_256
|
||||||
|
from secrets import token_bytes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def create_user(db: Session, username: str, password: str) -> None:
|
||||||
|
pw_salt = token_bytes(32).hex()
|
||||||
|
pw_hash = compute_password_hash(password, pw_salt)
|
||||||
|
user_id = uuid.uuid4()
|
||||||
|
|
||||||
|
db.execute(insert(User).values(id=user_id, username=username, pw_hash=pw_hash, pw_salt=pw_salt))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def compute_password_hash(password: str, salt: str) -> str:
|
||||||
|
full_salted_password = salt + password
|
||||||
|
digest = SHA3_256.new(full_salted_password.encode('ascii')).digest()
|
||||||
|
digest_output = digest.hex()
|
||||||
|
|
||||||
|
return digest_output
|
||||||
|
|
||||||
|
def verify_user(db: Session, user: str, password: str) -> User | None:
|
||||||
|
# noinspection PyTypeChecker
|
||||||
|
selected_users = db.execute(select(User).where(User.username == user)).fetchall()
|
||||||
|
|
||||||
|
assert len(selected_users) < 2
|
||||||
|
if len(selected_users) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# get the first user from the result
|
||||||
|
user: User = selected_users[0][0]
|
||||||
|
pw_hash = compute_password_hash(password, user.pw_salt)
|
||||||
|
|
||||||
|
if pw_hash == user.pw_hash:
|
||||||
|
return user
|
||||||
|
return None
|
||||||
70
pillar_tool/main.py
Normal file
70
pillar_tool/main.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# load config so everything else can work
|
||||||
|
from pillar_tool.util import load_config, config
|
||||||
|
load_config()
|
||||||
|
|
||||||
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
|
|
||||||
|
from pillar_tool.db.database import get_connection
|
||||||
|
from pillar_tool.db.queries.auth_queries import create_user
|
||||||
|
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from starlette.middleware.authentication import AuthenticationMiddleware
|
||||||
|
from starlette.requests import Request
|
||||||
|
from fastapi.responses import HTMLResponse, PlainTextResponse
|
||||||
|
from starlette.responses import JSONResponse
|
||||||
|
|
||||||
|
from pillar_tool.middleware.basicauth_backend import BasicAuthBackend
|
||||||
|
from pillar_tool.middleware.db_connection import db_connection_middleware
|
||||||
|
from pillar_tool.db.database import run_db_migrations
|
||||||
|
|
||||||
|
|
||||||
|
# run any pending migrations
|
||||||
|
run_db_migrations()
|
||||||
|
|
||||||
|
# get a database connection
|
||||||
|
db = get_connection()
|
||||||
|
|
||||||
|
# create default user if it does not exist
|
||||||
|
# noinspection PyBroadException
|
||||||
|
try:
|
||||||
|
create_user(db, "admin", "admin")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# commit and close the db
|
||||||
|
db.commit()
|
||||||
|
db.close()
|
||||||
|
|
||||||
|
|
||||||
|
def on_auth_error(request: Request, exc: Exception):
|
||||||
|
response = PlainTextResponse(str(exc), status_code=401)
|
||||||
|
response.headers["WWW-Authenticate"] = "Basic"
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def on_db_error(request: Request, exc: Exception):
|
||||||
|
response = PlainTextResponse(str(exc), status_code=500)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def on_general_error(request: Request, exc: Exception):
|
||||||
|
print("wtf?")
|
||||||
|
response = PlainTextResponse(str(exc), status_code=500)
|
||||||
|
return response
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
app.add_middleware(AuthenticationMiddleware, backend=BasicAuthBackend(), on_error=on_auth_error)
|
||||||
|
app.add_middleware(BaseHTTPMiddleware, dispatch=db_connection_middleware)
|
||||||
|
app.exception_handler(Exception)(on_general_error)
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
async def root():
|
||||||
|
return {"message": "Hello World"}
|
||||||
|
|
||||||
|
@app.get("/pillar/{host}")
|
||||||
|
async def pillar(req: Request, host: str):
|
||||||
|
print(req.headers)
|
||||||
|
#return JSONResponse(content=collect_pillar_data(host))
|
||||||
|
return JSONResponse({})
|
||||||
Binary file not shown.
@ -1,12 +1,17 @@
|
|||||||
import base64
|
import base64
|
||||||
import binascii
|
import binascii
|
||||||
|
|
||||||
import hypercorn.logging
|
import hypercorn.logging
|
||||||
|
|
||||||
from starlette.authentication import AuthenticationBackend, AuthenticationError, AuthCredentials, SimpleUser
|
from starlette.authentication import AuthenticationBackend, AuthenticationError, AuthCredentials, SimpleUser
|
||||||
|
|
||||||
|
from pillar_tool.db.queries.auth_queries import verify_user
|
||||||
|
|
||||||
|
|
||||||
class BasicAuthBackend(AuthenticationBackend):
|
class BasicAuthBackend(AuthenticationBackend):
|
||||||
|
|
||||||
async def authenticate(self, conn):
|
async def authenticate(self, conn):
|
||||||
|
print("test 2")
|
||||||
if "Authorization" not in conn.headers:
|
if "Authorization" not in conn.headers:
|
||||||
raise AuthenticationError('No Authorization Header')
|
raise AuthenticationError('No Authorization Header')
|
||||||
|
|
||||||
@ -21,7 +26,10 @@ class BasicAuthBackend(AuthenticationBackend):
|
|||||||
|
|
||||||
|
|
||||||
username, _, password = decoded.partition(":")
|
username, _, password = decoded.partition(":")
|
||||||
if username == 'admin' and password == 'password':
|
user = verify_user(conn.state.db, username, password)
|
||||||
return AuthCredentials(["authenticated"]), SimpleUser('admin')
|
|
||||||
|
if user is None:
|
||||||
|
raise AuthenticationError('Invalid basic auth credentials')
|
||||||
|
|
||||||
|
conn.state.user = user
|
||||||
|
|
||||||
raise AuthenticationError('Invalid basic auth credentials')
|
|
||||||
|
|||||||
28
pillar_tool/middleware/db_connection.py
Normal file
28
pillar_tool/middleware/db_connection.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
from typing import Callable
|
||||||
|
|
||||||
|
from starlette.requests import Request
|
||||||
|
from starlette.responses import Response
|
||||||
|
|
||||||
|
from pillar_tool.db.database import get_connection
|
||||||
|
|
||||||
|
async def db_connection_middleware(request: Request, call_next: Callable) -> Response:
|
||||||
|
session = get_connection()
|
||||||
|
print("test 1")
|
||||||
|
|
||||||
|
request.state.db = session
|
||||||
|
try:
|
||||||
|
response: Response = await call_next(request)
|
||||||
|
if 200 <= response.status_code <= 299:
|
||||||
|
session.commit()
|
||||||
|
session.close()
|
||||||
|
else:
|
||||||
|
session.rollback()
|
||||||
|
session.close()
|
||||||
|
except Exception as e:
|
||||||
|
session.rollback()
|
||||||
|
session.close()
|
||||||
|
raise e
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
@ -9,6 +9,7 @@ dependencies = [
|
|||||||
"hypercorn>=0.18.0",
|
"hypercorn>=0.18.0",
|
||||||
"jinja2>=3.1.6",
|
"jinja2>=3.1.6",
|
||||||
"psycopg2>=2.9.11",
|
"psycopg2>=2.9.11",
|
||||||
|
"pycryptodome>=3.23.0",
|
||||||
"pydantic>=2.12.5",
|
"pydantic>=2.12.5",
|
||||||
"sqlalchemy>=2.0.45",
|
"sqlalchemy>=2.0.45",
|
||||||
]
|
]
|
||||||
|
|||||||
32
uv.lock
generated
32
uv.lock
generated
@ -242,6 +242,7 @@ dependencies = [
|
|||||||
{ name = "hypercorn" },
|
{ name = "hypercorn" },
|
||||||
{ name = "jinja2" },
|
{ name = "jinja2" },
|
||||||
{ name = "psycopg2" },
|
{ name = "psycopg2" },
|
||||||
|
{ name = "pycryptodome" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
{ name = "sqlalchemy" },
|
{ name = "sqlalchemy" },
|
||||||
]
|
]
|
||||||
@ -253,6 +254,7 @@ requires-dist = [
|
|||||||
{ name = "hypercorn", specifier = ">=0.18.0" },
|
{ name = "hypercorn", specifier = ">=0.18.0" },
|
||||||
{ name = "jinja2", specifier = ">=3.1.6" },
|
{ name = "jinja2", specifier = ">=3.1.6" },
|
||||||
{ name = "psycopg2", specifier = ">=2.9.11" },
|
{ name = "psycopg2", specifier = ">=2.9.11" },
|
||||||
|
{ name = "pycryptodome", specifier = ">=3.23.0" },
|
||||||
{ name = "pydantic", specifier = ">=2.12.5" },
|
{ name = "pydantic", specifier = ">=2.12.5" },
|
||||||
{ name = "sqlalchemy", specifier = ">=2.0.45" },
|
{ name = "sqlalchemy", specifier = ">=2.0.45" },
|
||||||
]
|
]
|
||||||
@ -276,6 +278,36 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/47/08/737aa39c78d705a7ce58248d00eeba0e9fc36be488f9b672b88736fbb1f7/psycopg2-2.9.11-cp314-cp314-win_amd64.whl", hash = "sha256:f10a48acba5fe6e312b891f290b4d2ca595fc9a06850fe53320beac353575578", size = 2803738, upload-time = "2025-10-10T11:10:23.196Z" },
|
{ url = "https://files.pythonhosted.org/packages/47/08/737aa39c78d705a7ce58248d00eeba0e9fc36be488f9b672b88736fbb1f7/psycopg2-2.9.11-cp314-cp314-win_amd64.whl", hash = "sha256:f10a48acba5fe6e312b891f290b4d2ca595fc9a06850fe53320beac353575578", size = 2803738, upload-time = "2025-10-10T11:10:23.196Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pycryptodome"
|
||||||
|
version = "3.23.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.12.5"
|
version = "2.12.5"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user