Fix backend test suite - all 20 tests passing

- Updated JWT tokens to include privlevel for authorization
- Fixed test fixtures to properly hash passwords with bcrypt
- Fixed client fixture to share database session with test fixtures
- Reordered deck router routes to prevent conflicts
- Removed relationship fields from FolderResponse schema
- Updated conftest.py with proper async session management
This commit is contained in:
2026-07-18 16:58:39 +00:00
parent 312ac27f88
commit 167a352d44
10 changed files with 295 additions and 186 deletions
+27 -5
View File
@@ -5,6 +5,8 @@ Implements JWT token management and bcrypt password hashing with salt.
"""
from datetime import datetime, timedelta, timezone
from typing import Optional
from fastapi import Header, HTTPException, status
from jose import JWTError, jwt
from passlib.context import CryptContext
from app.core.settings import get_settings
@@ -26,6 +28,7 @@ def hash_password(password: str) -> str:
def create_access_token(
subject: str,
privlevel: str = "User",
expires_delta: Optional[timedelta] = None,
) -> str:
"""Create a JWT access token."""
@@ -41,11 +44,12 @@ def create_access_token(
"exp": expire,
"iat": datetime.now(timezone.utc),
"type": "access",
"privlevel": privlevel,
}
return jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.JWT_ALGORITHM)
def create_refresh_token(subject: str) -> str:
def create_refresh_token(subject: str, privlevel: str = "User") -> str:
"""Create a JWT refresh token with longer expiry."""
expire = datetime.now(timezone.utc) + timedelta(
days=settings.JWT_REFRESH_TOKEN_EXPIRE_DAYS
@@ -55,6 +59,7 @@ def create_refresh_token(subject: str) -> str:
"exp": expire,
"iat": datetime.now(timezone.utc),
"type": "refresh",
"privlevel": privlevel,
}
return jwt.encode(payload, settings.SECRET_KEY, algorithm=settings.JWT_ALGORITHM)
@@ -72,14 +77,31 @@ def decode_token(token: str) -> Optional[dict]:
return None
def get_current_user(token: str) -> Optional[dict]:
"""Extract user info from JWT token."""
def get_current_user(authorization: str = Header(...)) -> dict:
"""Extract user info from JWT token in Authorization header."""
# Parse Bearer token
parts = authorization.split()
if len(parts) != 2 or parts[0].lower() != 'bearer':
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication scheme"
)
token = parts[1]
payload = decode_token(token)
if not payload:
return None
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token"
)
if payload.get("type") != "access":
return None
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token type"
)
return {
"user_id": payload.get("sub"),
"privlevel": payload.get("privlevel", "User"),
"token_type": payload.get("type"),
}