Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions pdfgui-migration/backend/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""pdfGUI Migration Backend - FastAPI Application"""

__version__ = "1.0.0"
1 change: 1 addition & 0 deletions pdfgui-migration/backend/app/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""API router configuration."""
40 changes: 40 additions & 0 deletions pdfgui-migration/backend/app/api/deps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""API dependencies."""

from uuid import UUID

from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy.orm import Session

from ..core.database import get_db
from ..core.security import decode_token
from ..models.user import User

security = HTTPBearer()


def get_current_user(
credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db)
) -> User:
"""Get current authenticated user from JWT token."""
token = credentials.credentials

payload = decode_token(token)
if not payload:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired token")

if payload.get("type") != "access":
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token type")

user_id = payload.get("sub")
if not user_id:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token payload")

user = db.query(User).filter(User.id == UUID(user_id)).first()
if not user:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found")

if not user.is_active:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="User account is disabled")

return user
14 changes: 14 additions & 0 deletions pdfgui-migration/backend/app/api/v1/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""API v1 router."""

from fastapi import APIRouter

from .endpoints import auth, datasets, files, fittings, phases, projects

api_router = APIRouter()

api_router.include_router(auth.router, prefix="/auth", tags=["auth"])
api_router.include_router(projects.router, prefix="/projects", tags=["projects"])
api_router.include_router(fittings.router, prefix="/fittings", tags=["fittings"])
api_router.include_router(phases.router, prefix="/phases", tags=["phases"])
api_router.include_router(datasets.router, prefix="/datasets", tags=["datasets"])
api_router.include_router(files.router, prefix="/files", tags=["files"])
1 change: 1 addition & 0 deletions pdfgui-migration/backend/app/api/v1/endpoints/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""API endpoints."""
68 changes: 68 additions & 0 deletions pdfgui-migration/backend/app/api/v1/endpoints/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""Authentication endpoints."""

from fastapi import APIRouter, Depends, HTTPException, Request, status
from sqlalchemy.orm import Session

from ....core.database import get_db
from ....schemas.user import Token, TokenRefresh, UserCreate, UserLogin, UserResponse
from ....services.auth_service import AuthService

router = APIRouter()


@router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
def register(user_data: UserCreate, db: Session = Depends(get_db)):
"""Register a new user."""
auth_service = AuthService(db)
try:
user = auth_service.create_user(
email=user_data.email,
password=user_data.password,
first_name=user_data.first_name,
last_name=user_data.last_name,
)
return user
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))


@router.post("/login", response_model=Token)
def login(credentials: UserLogin, request: Request, db: Session = Depends(get_db)):
"""Authenticate user and get tokens."""
auth_service = AuthService(db)
user = auth_service.authenticate(credentials.email, credentials.password)

if not user:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials")

if not user.is_active:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="User account is disabled")

tokens = auth_service.create_session(
user,
ip_address=request.client.host if request.client else None,
user_agent=request.headers.get("user-agent"),
)

return tokens


@router.post("/refresh", response_model=Token)
def refresh_token(token_data: TokenRefresh, db: Session = Depends(get_db)):
"""Refresh access token."""
auth_service = AuthService(db)
tokens = auth_service.refresh_access_token(token_data.refresh_token)

if not tokens:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid refresh token")

return tokens


@router.post("/logout")
def logout(token_data: TokenRefresh, db: Session = Depends(get_db)):
"""Logout and invalidate session."""
auth_service = AuthService(db)
success = auth_service.logout(token_data.refresh_token)

return {"success": success}
Loading
Loading