feat: add unified linting scripts and git hooks for code quality enforcement
- Introduced `lint` and `lint-fix` applications in `flake.nix` for unified linting of backend (Python) and frontend (TypeScript/Svelte) code. - Added `scripts/lint.sh` for manual linting execution. - Created `scripts/install-hooks.sh` to set up git hooks for automatic linting before commits and optional tests before pushes. - Updated `README.md` with instructions for using the new linting features and git hooks.
This commit is contained in:
@@ -1,2 +1 @@
|
||||
"""Core application modules."""
|
||||
|
||||
|
||||
@@ -90,4 +90,3 @@ def get_settings() -> Settings:
|
||||
|
||||
# Export settings instance
|
||||
settings = get_settings()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Dependency injection utilities."""
|
||||
|
||||
from typing import Annotated, Generator
|
||||
from typing import Annotated
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import Depends, HTTPException, status
|
||||
@@ -19,33 +19,32 @@ security = HTTPBearer()
|
||||
|
||||
|
||||
def get_current_user(
|
||||
credentials: HTTPAuthorizationCredentials = Depends(security),
|
||||
db: Session = Depends(get_db)
|
||||
credentials: HTTPAuthorizationCredentials = Depends(security), db: Session = Depends(get_db)
|
||||
) -> User:
|
||||
"""
|
||||
Get current authenticated user from JWT token.
|
||||
|
||||
|
||||
Args:
|
||||
credentials: HTTP Authorization Bearer token
|
||||
db: Database session
|
||||
|
||||
|
||||
Returns:
|
||||
Current authenticated user
|
||||
|
||||
|
||||
Raises:
|
||||
HTTPException: If token is invalid or user not found
|
||||
"""
|
||||
# Decode token
|
||||
token = credentials.credentials
|
||||
payload = decode_access_token(token)
|
||||
|
||||
|
||||
if payload is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid authentication credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
|
||||
# Extract user ID from token
|
||||
user_id_str: str = payload.get("sub")
|
||||
if user_id_str is None:
|
||||
@@ -54,7 +53,7 @@ def get_current_user(
|
||||
detail="Invalid token payload",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
|
||||
try:
|
||||
user_id = UUID(user_id_str)
|
||||
except ValueError:
|
||||
@@ -62,23 +61,19 @@ def get_current_user(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Invalid user ID in token",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
) from None
|
||||
|
||||
# Get user from database
|
||||
user = db.query(User).filter(User.id == user_id).first()
|
||||
|
||||
|
||||
if user is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="User not found",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
if not user.is_active:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="User account is deactivated"
|
||||
)
|
||||
|
||||
return user
|
||||
|
||||
if not user.is_active:
|
||||
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="User account is deactivated")
|
||||
|
||||
return user
|
||||
|
||||
@@ -65,4 +65,3 @@ class UnsupportedFileTypeError(WebRefException):
|
||||
def __init__(self, file_type: str, allowed_types: list[str]):
|
||||
message = f"File type '{file_type}' not supported. Allowed types: {', '.join(allowed_types)}"
|
||||
super().__init__(message, status_code=415)
|
||||
|
||||
|
||||
@@ -8,27 +8,24 @@ from app.core.config import settings
|
||||
|
||||
def setup_logging() -> None:
|
||||
"""Configure application logging."""
|
||||
|
||||
|
||||
# Get log level from settings
|
||||
log_level = getattr(logging, settings.LOG_LEVEL.upper(), logging.INFO)
|
||||
|
||||
|
||||
# Configure root logger
|
||||
logging.basicConfig(
|
||||
level=log_level,
|
||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
handlers=[
|
||||
logging.StreamHandler(sys.stdout)
|
||||
],
|
||||
handlers=[logging.StreamHandler(sys.stdout)],
|
||||
)
|
||||
|
||||
|
||||
# Set library log levels
|
||||
logging.getLogger("uvicorn").setLevel(logging.INFO)
|
||||
logging.getLogger("uvicorn.access").setLevel(logging.INFO)
|
||||
logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING)
|
||||
logging.getLogger("boto3").setLevel(logging.WARNING)
|
||||
logging.getLogger("botocore").setLevel(logging.WARNING)
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.info(f"Logging configured with level: {settings.LOG_LEVEL}")
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
||||
|
||||
from app.core.config import settings
|
||||
|
||||
@@ -26,4 +25,3 @@ def setup_middleware(app: FastAPI) -> None:
|
||||
# TrustedHostMiddleware,
|
||||
# allowed_hosts=["yourdomain.com", "*.yourdomain.com"]
|
||||
# )
|
||||
|
||||
|
||||
@@ -10,13 +10,7 @@ from pydantic import BaseModel, ConfigDict, Field
|
||||
class BaseSchema(BaseModel):
|
||||
"""Base schema with common configuration."""
|
||||
|
||||
model_config = ConfigDict(
|
||||
from_attributes=True,
|
||||
populate_by_name=True,
|
||||
json_schema_extra={
|
||||
"example": {}
|
||||
}
|
||||
)
|
||||
model_config = ConfigDict(from_attributes=True, populate_by_name=True, json_schema_extra={"example": {}})
|
||||
|
||||
|
||||
class TimestampSchema(BaseSchema):
|
||||
@@ -61,4 +55,3 @@ class PaginatedResponse(BaseSchema):
|
||||
|
||||
items: list[Any] = Field(..., description="List of items")
|
||||
pagination: PaginationSchema = Field(..., description="Pagination metadata")
|
||||
|
||||
|
||||
@@ -116,4 +116,3 @@ class StorageClient:
|
||||
|
||||
# Global storage client instance
|
||||
storage_client = StorageClient()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user