async (not working tbh)
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
import os
|
||||
@ -9,11 +9,11 @@ POSTGRES_DB = os.environ.get("POSTGRES_DB", "db")
|
||||
POSTGRES_HOST = os.environ.get("POSTGRES_HOST", "postgres")
|
||||
|
||||
|
||||
SQLALCHEMY_DATABASE_URL = (
|
||||
f"postgresql://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}/{POSTGRES_DB}"
|
||||
SQLALCHEMY_DATABASE_URL = f"postgresql+asyncpg://{POSTGRES_USER}:{POSTGRES_PASSWORD}@{POSTGRES_HOST}/{POSTGRES_DB}"
|
||||
|
||||
engine = create_async_engine(SQLALCHEMY_DATABASE_URL)
|
||||
async_session = sessionmaker(
|
||||
autocommit=False, class_=AsyncSession, autoflush=False, bind=engine
|
||||
)
|
||||
|
||||
engine = create_engine(SQLALCHEMY_DATABASE_URL)
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
from .db.database import SessionLocal
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from .db.database import async_session
|
||||
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
async def get_db() -> AsyncSession:
|
||||
async with async_session() as session:
|
||||
try:
|
||||
yield session
|
||||
finally:
|
||||
session.close()
|
||||
|
||||
@ -2,7 +2,7 @@ from typing import Union
|
||||
from fastapi import FastAPI, Depends
|
||||
|
||||
from .db import models
|
||||
from .db.database import SessionLocal, engine
|
||||
from .db.database import engine
|
||||
from .dependencies import get_db
|
||||
|
||||
from .views.auth.api import router as auth_router
|
||||
@ -10,13 +10,19 @@ from .views.queue.api import router as queue_router
|
||||
from .views.news.api import router as news_router
|
||||
|
||||
app = FastAPI(dependencies=[Depends(get_db)])
|
||||
models.Base.metadata.create_all(bind=engine)
|
||||
|
||||
|
||||
app.include_router(queue_router)
|
||||
app.include_router(auth_router)
|
||||
app.include_router(news_router)
|
||||
|
||||
|
||||
@app.on_event("startup")
|
||||
async def init_tables():
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(models.Base.metadata.create_all)
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def read_root():
|
||||
return {"message": "OK"}
|
||||
|
||||
@ -27,7 +27,7 @@ async def login_for_access_token(
|
||||
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
) -> schemas.Token:
|
||||
user = services.authenticate_user(db, form_data.username, form_data.password)
|
||||
user = await services.authenticate_user(db, form_data.username, form_data.password)
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
@ -46,7 +46,7 @@ async def register(
|
||||
user_data: schemas.UserRegister,
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
) -> schemas.User:
|
||||
user = services.get_user_by_username(db, user_data.username)
|
||||
user = await services.get_user_by_username(db, user_data.username)
|
||||
if user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
@ -59,7 +59,7 @@ async def register(
|
||||
detail="Passwords do not match",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
user = services.create_user(db=db, user_data=user_data)
|
||||
user = await services.create_user(db=db, user_data=user_data)
|
||||
return user
|
||||
|
||||
|
||||
|
||||
@ -27,3 +27,11 @@ class Token(BaseModel):
|
||||
|
||||
class TokenData(BaseModel):
|
||||
username: Union[str, None] = None
|
||||
|
||||
|
||||
class AnonUser(BaseModel):
|
||||
id: UUID
|
||||
name: str
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
from fastapi import status, HTTPException, Depends
|
||||
from fastapi import status, HTTPException, Depends, Header
|
||||
from fastapi.security import OAuth2PasswordBearer
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
# from sqlalchemy.orm import Session
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.future import select
|
||||
from jose import JWTError, jwt
|
||||
from typing import Annotated, Union
|
||||
from datetime import datetime, timezone, timedelta
|
||||
@ -24,16 +27,18 @@ def get_password_hash(password) -> str:
|
||||
return pwd_context.hash(password)
|
||||
|
||||
|
||||
def get_user_by_id(db: Session, user_id: uuid.uuid4) -> models.User:
|
||||
return db.query(models.User).filter(models.User.id == user_id).first()
|
||||
async def get_user_by_id(db: AsyncSession, user_id: uuid.uuid4) -> models.User:
|
||||
u = await db.execute(select(models.User).filter(models.User.id == user_id))
|
||||
return u.scalar_one_or_none()
|
||||
|
||||
|
||||
def get_user_by_username(db: Session, username: int) -> models.User:
|
||||
return db.query(models.User).filter(models.User.username == username).first()
|
||||
async def get_user_by_username(db: AsyncSession, username: int) -> models.User:
|
||||
u = await db.execute(select(models.User).filter(models.User.username == username))
|
||||
return u.scalar_one_or_none()
|
||||
|
||||
|
||||
def authenticate_user(db: Session, username: str, password: str):
|
||||
user = get_user_by_username(db, username)
|
||||
async def authenticate_user(db: AsyncSession, username: str, password: str):
|
||||
user = await get_user_by_username(db, username)
|
||||
if not user:
|
||||
return False
|
||||
if not verify_password(password, user.hashed_password):
|
||||
@ -54,20 +59,22 @@ def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None
|
||||
return encoded_jwt
|
||||
|
||||
|
||||
def create_user(db: Session, user_data: schemas.UserRegister) -> schemas.UserInDB:
|
||||
async def create_user(
|
||||
db: AsyncSession, user_data: schemas.UserRegister
|
||||
) -> schemas.UserInDB:
|
||||
user = models.User(
|
||||
username=user_data.username,
|
||||
name=user_data.name,
|
||||
hashed_password=get_password_hash(user_data.password),
|
||||
)
|
||||
db.add(user)
|
||||
db.commit()
|
||||
await db.commit()
|
||||
return schemas.UserInDB.model_validate(user)
|
||||
|
||||
|
||||
async def get_current_user(
|
||||
token: Annotated[str, Depends(oauth2_scheme)],
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
db: Annotated[AsyncSession, Depends(get_db)],
|
||||
) -> schemas.UserInDB:
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
@ -84,7 +91,7 @@ async def get_current_user(
|
||||
token_data = schemas.TokenData(username=username)
|
||||
except JWTError:
|
||||
raise credentials_exception
|
||||
user = get_user_by_username(db, username=token_data.username)
|
||||
user = await get_user_by_username(db, username=token_data.username)
|
||||
if user is None:
|
||||
raise credentials_exception
|
||||
return user
|
||||
@ -92,7 +99,7 @@ async def get_current_user(
|
||||
|
||||
async def get_current_user_or_none(
|
||||
token: Annotated[str, Depends(oauth2_scheme)],
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
db: Annotated[AsyncSession, Depends(get_db)],
|
||||
) -> Union[schemas.UserInDB, None]:
|
||||
try:
|
||||
payload = jwt.decode(
|
||||
@ -104,7 +111,7 @@ async def get_current_user_or_none(
|
||||
token_data = schemas.TokenData(username=username)
|
||||
except JWTError:
|
||||
return None
|
||||
user = get_user_by_username(db, username=token_data.username)
|
||||
user = await get_user_by_username(db, username=token_data.username)
|
||||
return user
|
||||
|
||||
|
||||
@ -114,3 +121,24 @@ async def get_current_active_user(
|
||||
if not current_user.is_active:
|
||||
raise HTTPException(status_code=400, detail="Inactive user")
|
||||
return current_user
|
||||
|
||||
|
||||
async def create_anon_user(
|
||||
db: Annotated[AsyncSession, Depends(get_db)]
|
||||
) -> schemas.AnonUser:
|
||||
u = models.AnonymousUser()
|
||||
db.add(u)
|
||||
await db.commit()
|
||||
return schemas.AnonUser.model_validate(u)
|
||||
|
||||
|
||||
async def get_anon_user(
|
||||
db: Annotated[AsyncSession, Depends(get_db)],
|
||||
device_id: Annotated[Union[str, None], Header()] = None,
|
||||
) -> schemas.AnonUser:
|
||||
if device_id:
|
||||
u = await db.execute(
|
||||
select(models.AnonymousUser).filter(models.AnonymousUser.id == device_id)
|
||||
)
|
||||
return schemas.AnonUser.model_validate(u.scalar_one_or_none())
|
||||
return await create_anon_user(db)
|
||||
|
||||
@ -39,7 +39,8 @@ async def create_news(
|
||||
current_user: Annotated[auth_schemas.User, Depends(auth_services.get_current_user)],
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
) -> schemas.NewsInDb:
|
||||
return services.create_news(news=news, current_user=current_user, db=db)
|
||||
n = await services.create_news(news=news, current_user=current_user, db=db)
|
||||
return n
|
||||
|
||||
|
||||
@router.post("/{news_id}/tap")
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from typing import Annotated
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.future import select
|
||||
from uuid import UUID
|
||||
|
||||
from ...dependencies import get_db
|
||||
@ -12,24 +13,23 @@ from ..auth import schemas as auth_schemas
|
||||
from . import schemas
|
||||
|
||||
|
||||
def get_news(
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
async def get_news(
|
||||
db: Annotated[AsyncSession, Depends(get_db)],
|
||||
) -> list[schemas.NewsInDb]:
|
||||
return [
|
||||
schemas.NewsInDb.model_validate(n)
|
||||
for n in db.query(models.News).order_by(models.News.created.desc()).all()
|
||||
]
|
||||
news = await db.execute(select(models.News).order_by(models.News.created.desc()))
|
||||
return [schemas.NewsInDb.model_validate(n) for n in news.scalars().all()]
|
||||
|
||||
|
||||
def create_news(
|
||||
async def create_news(
|
||||
news: schemas.CreateNews,
|
||||
current_user: auth_schemas.UserInDB,
|
||||
db: Session,
|
||||
db: AsyncSession,
|
||||
) -> schemas.NewsInDb:
|
||||
if current_user.username == "admin":
|
||||
n = models.News(title=news.title, content=news.content)
|
||||
db.add(n)
|
||||
db.commit()
|
||||
await db.commit()
|
||||
print(f"\n\n{n.title}\n\n", flush=True)
|
||||
return schemas.NewsInDb.model_validate(n)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
@ -38,7 +38,7 @@ def create_news(
|
||||
)
|
||||
|
||||
|
||||
def tap_news(news_id: UUID, db: Session):
|
||||
async def tap_news(news_id: UUID, db: AsyncSession):
|
||||
n = db.query(models.News).filter(models.News.id == news_id).first()
|
||||
if n:
|
||||
setattr(n, "taps", n.taps + 1)
|
||||
|
||||
@ -12,13 +12,13 @@ from ..auth import schemas as auth_schemas
|
||||
from . import schemas
|
||||
|
||||
|
||||
def get_user_queues(
|
||||
async def get_user_queues(
|
||||
current_user: Annotated[auth_schemas.User, Depends(auth_services.get_current_user)]
|
||||
) -> list[schemas.QueueInDb]:
|
||||
return [schemas.QueueInDb.model_validate(q) for q in current_user.owns_queues]
|
||||
|
||||
|
||||
def create_queue(
|
||||
async def create_queue(
|
||||
new_queue: schemas.Queue,
|
||||
current_user: auth_schemas.UserInDB,
|
||||
db: Session,
|
||||
@ -31,7 +31,7 @@ def create_queue(
|
||||
return schemas.QueueInDb.model_validate(q)
|
||||
|
||||
|
||||
def get_detailed_queue(
|
||||
async def get_detailed_queue(
|
||||
queue_id: UUID,
|
||||
db: Annotated[Session, Depends(get_db)],
|
||||
) -> schemas.QueueDetail:
|
||||
|
||||
@ -2,6 +2,6 @@ fastapi[all]
|
||||
uvicorn
|
||||
pydantic
|
||||
sqlalchemy
|
||||
psycopg2-binary
|
||||
asyncpg
|
||||
python-jose[cryptography]
|
||||
passlib[all]
|
||||
@ -8,7 +8,7 @@ export default defineConfig({
|
||||
port: 3000,
|
||||
},
|
||||
html: {
|
||||
favicon: "./static/favicon-32x32.png",
|
||||
favicon: "./static/android-chrome-512x512.png",
|
||||
title: "queueful!",
|
||||
template: "./static/index.html",
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user