feat(api+testing): select member by email

- Reorganized folder structure so routes live in the same folder
- Set up pytest fixtures for future use
This commit is contained in:
2024-03-01 20:14:20 -05:00
parent b64030617c
commit 49c83fa287
10 changed files with 72 additions and 14 deletions

View File

@@ -4,8 +4,7 @@ import redis.asyncio as redis
from fastapi import FastAPI
from fastapi_limiter import FastAPILimiter
from src.neo_neo_todo.control import control
from src.neo_neo_todo.sessions import sessions
from src.neo_neo_todo.routes import control, sessions
from src.neo_neo_todo.utils.database import pool

View File

@@ -1,6 +1,10 @@
from dataclasses import dataclass
from datetime import datetime
from psycopg import sql
from psycopg.rows import class_row
from psycopg_pool import AsyncConnectionPool
@dataclass
class Member:
@@ -9,3 +13,26 @@ class Member:
password_hash: str
created: datetime
email_verified: datetime | None
async def select_member_by_email(db: AsyncConnectionPool, email: str) -> Member | None:
"""
Find exactly one email match in users list in PostgreSQL database
"""
async with db.connection() as conn:
async with conn.cursor(row_factory=class_row(Member)) as curr:
query = sql.SQL(
"""
SELECT id, email, password_hash, created, email_verified
FROM members
WHERE LOWER(email) = LOWER(%s);
"""
)
await curr.execute(query, (email,))
print(query.as_string(conn))
member = await curr.fetchone()
return None if member is None else member

View File

@@ -1,5 +1,4 @@
from fastapi import APIRouter
from starlette.requests import Request
router = APIRouter(
prefix="/control",
@@ -8,5 +7,5 @@ router = APIRouter(
@router.get("/ping")
async def ping(request: Request):
async def ping():
return {"ping": "pong"}

View File

@@ -1,6 +1,5 @@
from fastapi import APIRouter, Depends
from fastapi_limiter.depends import RateLimiter
from starlette.requests import Request
from src.neo_neo_todo.models.session import LoginData
@@ -11,7 +10,7 @@ router = APIRouter(
@router.post("", dependencies=[Depends(RateLimiter(times=100, seconds=600))])
async def login(request: Request, login_data: LoginData):
async def login(login_data: LoginData):
"""
Login to the todo app