починил конфигурацию базы и изменил сервис пользователя на асинхронный

This commit is contained in:
Андрей Дувакин 2025-02-06 20:44:07 +05:00
parent c7e6663b6a
commit be972cd532
13 changed files with 153 additions and 55 deletions

View File

@ -1,4 +1,5 @@
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
from app.domain.models.users import User from app.domain.models.users import User
@ -8,26 +9,28 @@ class UsersRepository:
def __init__(self, db: AsyncSession): def __init__(self, db: AsyncSession):
self.db = db self.db = db
def get_all(self): async def get_all(self):
return self.db.query(User).all() stmt = select(User)
result = await self.db.execute(stmt)
return result.scalars().all()
def get_by_id(self, user_id: int): async def get_by_id(self, user_id: int):
return self.db.query(User).filter(User.id == user_id).first() stmt = select(User).filter(User.id == user_id)
result = await self.db.execute(stmt)
return result.scalars().first()
def get_by_login(self, user_login: str): async def get_by_login(self, user_login: str):
return ( stmt = (
self.db select(User)
.query(User)
.filter(User.login == user_login) .filter(User.login == user_login)
.options( .options(joinedload(User.role))
joinedload(User.role)
)
.first()
) )
result = await self.db.execute(stmt)
return result.scalars().first()
def create(self, user: User): async def create(self, user: User):
self.db.add(user) self.db.add(user)
self.db.commit() await self.db.commit()
self.db.refresh(user) await self.db.refresh(user)
return user return user

View File

@ -1,7 +1,5 @@
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException, Response, status
from fastapi.openapi.models import Response
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from starlette import status
from app.database.session import get_db from app.database.session import get_db
from app.domain.entities.auth import AuthEntity from app.domain.entities.auth import AuthEntity
@ -10,18 +8,38 @@ from app.infrastructure.auth_service import AuthService
router = APIRouter() router = APIRouter()
@router.post('/login/') @router.post(
async def auth_user(response: Response, user_data: AuthEntity, db: AsyncSession = Depends(get_db)): "/login/",
response_model=dict,
responses={401: {"description": "Неверный логин или пароль"}},
summary="Аутентификация пользователя",
description="Производит вход пользователя и выдает `access_token` в `cookie`.",
)
async def auth_user(
response: Response,
user_data: AuthEntity,
db: AsyncSession = Depends(get_db)
):
auth_service = AuthService(db) auth_service = AuthService(db)
check = await auth_service.authenticate_user(login=user_data.login, password=user_data.password)
check = await auth_service.authenticate_user(
login=user_data.login, password=user_data.password
)
if check is None: if check is None:
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail='Неверный логин или пароль', detail="Неверный логин или пароль",
) )
access_token = auth_service.create_access_token({"sub": str(check.id)}) access_token = auth_service.create_access_token({"sub": str(check.id)})
response.set_cookie(key="users_access_token", value=access_token, httponly=True)
return {'access_token': access_token, 'refresh_token': None} response.set_cookie(
key="users_access_token",
value=access_token,
httponly=True,
samesite="Lax",
)
return {"access_token": access_token, "refresh_token": None}

View File

@ -0,0 +1,32 @@
"""Починил внешние ключи у таблиц
Revision ID: 463487eaaa57
Revises: 61aeb99662ba
Create Date: 2025-02-06 20:40:11.324094
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '463487eaaa57'
down_revision: Union[str, None] = '61aeb99662ba'
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_constraint('recipients_patient_id_fkey', 'recipients', type_='foreignkey')
op.create_foreign_key(None, 'recipients', 'patients', ['patient_id'], ['id'])
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'recipients', type_='foreignkey')
op.create_foreign_key('recipients_patient_id_fkey', 'recipients', 'mailing_delivery_methods', ['patient_id'], ['id'])
# ### end Alembic commands ###

View File

@ -0,0 +1,32 @@
"""Initial migrationA
Revision ID: 61aeb99662ba
Revises: f8f3f414b162
Create Date: 2025-02-06 20:37:40.995282
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '61aeb99662ba'
down_revision: Union[str, None] = 'f8f3f414b162'
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_constraint('mailing_options_option_id_fkey', 'mailing_options', type_='foreignkey')
op.create_foreign_key(None, 'mailing_options', 'mailing_delivery_methods', ['option_id'], ['id'])
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_constraint(None, 'mailing_options', type_='foreignkey')
op.create_foreign_key('mailing_options_option_id_fkey', 'mailing_options', 'patients', ['option_id'], ['id'])
# ### end Alembic commands ###

View File

@ -2,5 +2,6 @@ from pydantic import BaseModel, Field
class AuthEntity(BaseModel): class AuthEntity(BaseModel):
login: str = Field(...) login: str = Field(..., example="user@example.com")
password: str = Field(..., min_length=5) password: str = Field(..., min_length=5, example="strongpassword")

View File

@ -10,4 +10,4 @@ class MailingDeliveryMethod(Base):
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
title = Column(VARCHAR(200), nullable=False) title = Column(VARCHAR(200), nullable=False)
mailing = relationship('MailingOption', back_populates='option') mailing = relationship('MailingOption', back_populates='method')

View File

@ -9,8 +9,8 @@ class MailingOption(Base):
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
option_id = Column(Integer, ForeignKey('patients.id'), nullable=False) option_id = Column(Integer, ForeignKey('mailing_delivery_methods.id'), nullable=False)
mailing_id = Column(Integer, ForeignKey('mailing.id'), nullable=False) mailing_id = Column(Integer, ForeignKey('mailing.id'), nullable=False)
option = relationship('Patient', back_populates='mailing') method = relationship('MailingDeliveryMethod', back_populates='mailing')
mailing = relationship('Mailing', back_populates='mailing_options') mailing = relationship('Mailing', back_populates='mailing_options')

View File

@ -20,4 +20,4 @@ class Patient(Base):
lens_issues = relationship('LensIssue', back_populates='patient') lens_issues = relationship('LensIssue', back_populates='patient')
appointments = relationship('Appointment', back_populates='patient') appointments = relationship('Appointment', back_populates='patient')
mailing = relationship('Mailing', back_populates='patient') mailing = relationship('Recipient', back_populates='patient')

View File

@ -9,8 +9,8 @@ class Recipient(Base):
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)
patient_id = Column(Integer, ForeignKey('mailing_delivery_methods.id'), nullable=False) patient_id = Column(Integer, ForeignKey('patients.id'), nullable=False)
mailing_id = Column(Integer, ForeignKey('mailing.id'), nullable=False) mailing_id = Column(Integer, ForeignKey('mailing.id'), nullable=False)
patient = relationship('MailingDeliveryMethod', back_populates='mailing') patient = relationship('Patient', back_populates='mailing')
mailing = relationship('Mailing', back_populates='recipients') mailing = relationship('Mailing', back_populates='recipients')

View File

@ -1,6 +1,6 @@
import datetime import datetime
from jose import jwt import jwt
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from app.application.users_repository import UsersRepository from app.application.users_repository import UsersRepository

View File

@ -1,4 +1,29 @@
from app.run import start_app from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
if __name__ == '__main__': from app.controllers.auth_routes import router as auth_router
start_app() from app.settings import settings
def start_app():
api_app = FastAPI()
api_app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_credentials=True,
allow_methods=['GET', 'POST', 'PUT', 'DELETE'],
allow_headers=['*'],
)
api_app.include_router(auth_router, prefix=settings.APP_PREFIX)
return api_app
app = start_app()
@app.get("/")
async def root():
return {"message": "OK"}

View File

@ -1,14 +0,0 @@
from fastapi import FastAPI
from starlette.middleware.cors import CORSMiddleware
def start_app():
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=['*'],
allow_credentials=True,
allow_methods=['GET', 'POST', 'PUT', 'DELETE'],
allow_headers=['*'],
)

View File

@ -3,18 +3,19 @@ from pydantic_settings import BaseSettings
class Settings(BaseSettings): class Settings(BaseSettings):
DATABASE_URL: str DATABASE_URL: str
LOG_LEVEL: str = "info" LOG_LEVEL: str = 'info'
LOG_FILE: str = "logs/app.log" LOG_FILE: str = 'logs/app.log'
SECRET_KEY: str SECRET_KEY: str
ALGORITHM: str ALGORITHM: str
APP_PREFIX: str = '/api/v1'
class Config: class Config:
env_file = ".env" env_file = '.env'
env_file_encoding = "utf-8" env_file_encoding = 'utf-8'
settings = Settings() settings = Settings()
def get_auth_data(): def get_auth_data():
return {"secret_key": settings.SECRET_KEY, "algorithm": settings.ALGORITHM} return {'secret_key': settings.SECRET_KEY, 'algorithm': settings.ALGORITHM}