Migrate to motor for DB interaction

This commit is contained in:
april
2023-12-28 16:31:52 -06:00
parent d791e6f062
commit 7520cb3a27
20 changed files with 739 additions and 592 deletions

View File

@@ -1,40 +1,29 @@
import logging
import sys
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi import FastAPI
from mongoengine import connect
from app.config import get_settings
from database.utils import create_admin_user
from routes import users, flights
from routes import users, flights, auth
logger = logging.getLogger("api")
logging.basicConfig(format='%(asctime)s - %(levelname)s: %(message)s', level=logging.DEBUG)
handler = logging.StreamHandler(sys.stdout)
logger.addHandler(handler)
async def connect_to_db():
# Connect to MongoDB
settings = get_settings()
try:
connected = connect(settings.db_name, host=settings.db_uri, username=settings.db_user,
password=settings.db_pwd, authentication_source=settings.db_name)
if connected:
logging.info("Connected to database %s", settings.db_name)
# Create default admin user if it doesn't exist
create_admin_user()
except ConnectionError:
logger.error("Failed to connect to MongoDB")
raise ConnectionError
@asynccontextmanager
async def lifespan(app: FastAPI):
await create_admin_user()
yield
# Initialize FastAPI
app = FastAPI()
app.include_router(users.router)
app.include_router(flights.router)
app = FastAPI(lifespan=lifespan)
@app.on_event("startup")
async def startup():
await connect_to_db()
# Add subroutes
app.include_router(users.router, tags=["Users"], prefix="/users")
app.include_router(flights.router, tags=["Flights"], prefix="/flights")
app.include_router(auth.router, tags=["Auth"], prefix="/auth")

View File

@@ -7,6 +7,7 @@ class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
db_uri: str = "localhost"
db_port: int = 27017
db_name: str = "tailfin"
db_user: str
@@ -19,6 +20,9 @@ class Settings(BaseSettings):
jwt_secret_key: str = "please-change-me"
jwt_refresh_secret_key: str = "change-me-i-beg-of-you"
tailfin_admin_username: str = "admin"
tailfin_admin_password: str = "change-me-now"
@lru_cache
def get_settings():

View File

@@ -4,21 +4,21 @@ from typing import Annotated
from fastapi import Depends, HTTPException
from fastapi.security import OAuth2PasswordBearer
from jose import jwt
from mongoengine import DoesNotExist
from pydantic import ValidationError
from app.config import get_settings, Settings
from database.models import User, TokenBlacklist
from schemas import GetSystemUserSchema, TokenPayload, AuthLevel
from database.tokens import is_blacklisted
from database.users import get_user_system_info, get_user_system_info_id
from schemas.user import TokenPayload, AuthLevel, UserDisplaySchema
reusable_oath = OAuth2PasswordBearer(
tokenUrl="/login",
tokenUrl="/auth/login",
scheme_name="JWT"
)
async def get_current_user(settings: Annotated[Settings, Depends(get_settings)],
token: str = Depends(reusable_oath)) -> GetSystemUserSchema:
token: str = Depends(reusable_oath)) -> UserDisplaySchema:
try:
payload = jwt.decode(
token, settings.jwt_secret_key, algorithms=[settings.jwt_algorithm]
@@ -30,20 +30,19 @@ async def get_current_user(settings: Annotated[Settings, Depends(get_settings)],
except (jwt.JWTError, ValidationError):
raise HTTPException(403, "Could not validate credentials", {"WWW-Authenticate": "Bearer"})
try:
TokenBlacklist.objects.get(token=token)
blacklisted = await is_blacklisted(token)
if blacklisted:
raise HTTPException(403, "Token expired", {"WWW-Authenticate": "Bearer"})
except DoesNotExist:
try:
user = User.objects.get(id=token_data.sub)
except DoesNotExist:
raise HTTPException(404, "Could not find user")
return GetSystemUserSchema(id=str(user.id), username=user.username, level=user.level, password=user.password)
user = await get_user_system_info_id(id=token_data.sub)
if user is None:
raise HTTPException(404, "Could not find user")
return user
async def get_current_user_token(settings: Annotated[Settings, Depends(get_settings)],
token: str = Depends(reusable_oath)) -> (GetSystemUserSchema, str):
token: str = Depends(reusable_oath)) -> (UserDisplaySchema, str):
try:
payload = jwt.decode(
token, settings.jwt_secret_key, algorithms=[settings.jwt_algorithm]
@@ -55,19 +54,17 @@ async def get_current_user_token(settings: Annotated[Settings, Depends(get_setti
except (jwt.JWTError, ValidationError):
raise HTTPException(403, "Could not validate credentials", {"WWW-Authenticate": "Bearer"})
try:
TokenBlacklist.objects.get(token=token)
blacklisted = await is_blacklisted(token)
if blacklisted:
raise HTTPException(403, "Token expired", {"WWW-Authenticate": "Bearer"})
except DoesNotExist:
try:
user = User.objects.get(id=token_data.sub)
except DoesNotExist:
raise HTTPException(404, "Could not find user")
return GetSystemUserSchema(id=str(user.id), username=user.username, level=user.level,
password=user.password), token
user = await get_user_system_info(id=token_data.sub)
if user is None:
raise HTTPException(404, "Could not find user")
return user
async def admin_required(user: Annotated[GetSystemUserSchema, Depends(get_current_user)]):
async def admin_required(user: Annotated[UserDisplaySchema, Depends(get_current_user)]):
if user.level < AuthLevel.ADMIN:
raise HTTPException(403, "Access unauthorized")