refactor: modernize code quality tooling with Ruff
- Replace black, isort, and flake8 with Ruff (all-in-one linter and formatter) - Add comprehensive pyproject.toml configuration - Simplify Makefile code quality targets - Configure exclusions for venv/.venv in pyproject.toml - Auto-fix 1,359 linting issues across codebase Benefits: - Much faster builds (Ruff is written in Rust) - Single tool replaces multiple tools - More comprehensive rule set (UP, B, C4, SIM, PIE, RET, Q) - All configuration centralized in pyproject.toml - Better import sorting and formatting consistency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -24,9 +24,21 @@ IMPORTANT:
|
||||
from fastapi import APIRouter
|
||||
|
||||
# Import all admin routers
|
||||
from . import (audit, auth, code_quality, content_pages, dashboard,
|
||||
marketplace, monitoring, notifications, settings, users,
|
||||
vendor_domains, vendor_themes, vendors)
|
||||
from . import (
|
||||
audit,
|
||||
auth,
|
||||
code_quality,
|
||||
content_pages,
|
||||
dashboard,
|
||||
marketplace,
|
||||
monitoring,
|
||||
notifications,
|
||||
settings,
|
||||
users,
|
||||
vendor_domains,
|
||||
vendor_themes,
|
||||
vendors,
|
||||
)
|
||||
|
||||
# Create admin router
|
||||
router = APIRouter()
|
||||
|
||||
@@ -10,7 +10,6 @@ Provides endpoints for:
|
||||
|
||||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -19,9 +18,11 @@ from app.api.deps import get_current_admin_api
|
||||
from app.core.database import get_db
|
||||
from app.services.admin_audit_service import admin_audit_service
|
||||
from models.database.user import User
|
||||
from models.schema.admin import (AdminAuditLogFilters,
|
||||
AdminAuditLogListResponse,
|
||||
AdminAuditLogResponse)
|
||||
from models.schema.admin import (
|
||||
AdminAuditLogFilters,
|
||||
AdminAuditLogListResponse,
|
||||
AdminAuditLogResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/audit")
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -29,11 +30,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
@router.get("/logs", response_model=AdminAuditLogListResponse)
|
||||
def get_audit_logs(
|
||||
admin_user_id: Optional[int] = Query(None, description="Filter by admin user"),
|
||||
action: Optional[str] = Query(None, description="Filter by action type"),
|
||||
target_type: Optional[str] = Query(None, description="Filter by target type"),
|
||||
date_from: Optional[datetime] = Query(None, description="Filter from date"),
|
||||
date_to: Optional[datetime] = Query(None, description="Filter to date"),
|
||||
admin_user_id: int | None = Query(None, description="Filter by admin user"),
|
||||
action: str | None = Query(None, description="Filter by action type"),
|
||||
target_type: str | None = Query(None, description="Filter by target type"),
|
||||
date_from: datetime | None = Query(None, description="Filter from date"),
|
||||
date_to: datetime | None = Query(None, description="Filter to date"),
|
||||
skip: int = Query(0, ge=0, description="Number of records to skip"),
|
||||
limit: int = Query(100, ge=1, le=1000, description="Maximum records to return"),
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
@@ -4,7 +4,6 @@ RESTful API for architecture validation and violation management
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -32,7 +31,7 @@ class ScanResponse(BaseModel):
|
||||
warnings: int
|
||||
duration_seconds: float
|
||||
triggered_by: str
|
||||
git_commit_hash: Optional[str]
|
||||
git_commit_hash: str | None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -49,13 +48,13 @@ class ViolationResponse(BaseModel):
|
||||
file_path: str
|
||||
line_number: int
|
||||
message: str
|
||||
context: Optional[str]
|
||||
suggestion: Optional[str]
|
||||
context: str | None
|
||||
suggestion: str | None
|
||||
status: str
|
||||
assigned_to: Optional[int]
|
||||
resolved_at: Optional[str]
|
||||
resolved_by: Optional[int]
|
||||
resolution_note: Optional[str]
|
||||
assigned_to: int | None
|
||||
resolved_at: str | None
|
||||
resolved_by: int | None
|
||||
resolution_note: str | None
|
||||
created_at: str
|
||||
|
||||
class Config:
|
||||
@@ -83,7 +82,7 @@ class AssignViolationRequest(BaseModel):
|
||||
"""Request model for assigning a violation"""
|
||||
|
||||
user_id: int = Field(..., description="User ID to assign to")
|
||||
due_date: Optional[datetime] = Field(None, description="Due date for resolution")
|
||||
due_date: datetime | None = Field(None, description="Due date for resolution")
|
||||
priority: str = Field(
|
||||
"medium", description="Priority level (low, medium, high, critical)"
|
||||
)
|
||||
@@ -123,7 +122,7 @@ class DashboardStatsResponse(BaseModel):
|
||||
by_rule: dict
|
||||
by_module: dict
|
||||
top_files: list
|
||||
last_scan: Optional[str]
|
||||
last_scan: str | None
|
||||
|
||||
|
||||
# API Endpoints
|
||||
@@ -189,17 +188,17 @@ async def list_scans(
|
||||
|
||||
@router.get("/violations", response_model=ViolationListResponse)
|
||||
async def list_violations(
|
||||
scan_id: Optional[int] = Query(
|
||||
scan_id: int | None = Query(
|
||||
None, description="Filter by scan ID (defaults to latest)"
|
||||
),
|
||||
severity: Optional[str] = Query(
|
||||
severity: str | None = Query(
|
||||
None, description="Filter by severity (error, warning)"
|
||||
),
|
||||
status: Optional[str] = Query(
|
||||
status: str | None = Query(
|
||||
None, description="Filter by status (open, assigned, resolved, ignored)"
|
||||
),
|
||||
rule_id: Optional[str] = Query(None, description="Filter by rule ID"),
|
||||
file_path: Optional[str] = Query(
|
||||
rule_id: str | None = Query(None, description="Filter by rule ID"),
|
||||
file_path: str | None = Query(
|
||||
None, description="Filter by file path (partial match)"
|
||||
),
|
||||
page: int = Query(1, ge=1, description="Page number"),
|
||||
|
||||
@@ -9,7 +9,6 @@ Platform administrators can:
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -46,17 +45,17 @@ class ContentPageCreate(BaseModel):
|
||||
max_length=50,
|
||||
description="Template name (default, minimal, modern)",
|
||||
)
|
||||
meta_description: Optional[str] = Field(
|
||||
meta_description: str | None = Field(
|
||||
None, max_length=300, description="SEO meta description"
|
||||
)
|
||||
meta_keywords: Optional[str] = Field(
|
||||
meta_keywords: str | None = Field(
|
||||
None, max_length=300, description="SEO keywords"
|
||||
)
|
||||
is_published: bool = Field(default=False, description="Publish immediately")
|
||||
show_in_footer: bool = Field(default=True, description="Show in footer navigation")
|
||||
show_in_header: bool = Field(default=False, description="Show in header navigation")
|
||||
display_order: int = Field(default=0, description="Display order (lower = first)")
|
||||
vendor_id: Optional[int] = Field(
|
||||
vendor_id: int | None = Field(
|
||||
None, description="Vendor ID (None for platform default)"
|
||||
)
|
||||
|
||||
@@ -64,32 +63,32 @@ class ContentPageCreate(BaseModel):
|
||||
class ContentPageUpdate(BaseModel):
|
||||
"""Schema for updating a content page."""
|
||||
|
||||
title: Optional[str] = Field(None, max_length=200)
|
||||
content: Optional[str] = None
|
||||
content_format: Optional[str] = None
|
||||
template: Optional[str] = Field(None, max_length=50)
|
||||
meta_description: Optional[str] = Field(None, max_length=300)
|
||||
meta_keywords: Optional[str] = Field(None, max_length=300)
|
||||
is_published: Optional[bool] = None
|
||||
show_in_footer: Optional[bool] = None
|
||||
show_in_header: Optional[bool] = None
|
||||
display_order: Optional[int] = None
|
||||
title: str | None = Field(None, max_length=200)
|
||||
content: str | None = None
|
||||
content_format: str | None = None
|
||||
template: str | None = Field(None, max_length=50)
|
||||
meta_description: str | None = Field(None, max_length=300)
|
||||
meta_keywords: str | None = Field(None, max_length=300)
|
||||
is_published: bool | None = None
|
||||
show_in_footer: bool | None = None
|
||||
show_in_header: bool | None = None
|
||||
display_order: int | None = None
|
||||
|
||||
|
||||
class ContentPageResponse(BaseModel):
|
||||
"""Schema for content page response."""
|
||||
|
||||
id: int
|
||||
vendor_id: Optional[int]
|
||||
vendor_name: Optional[str]
|
||||
vendor_id: int | None
|
||||
vendor_name: str | None
|
||||
slug: str
|
||||
title: str
|
||||
content: str
|
||||
content_format: str
|
||||
meta_description: Optional[str]
|
||||
meta_keywords: Optional[str]
|
||||
meta_description: str | None
|
||||
meta_keywords: str | None
|
||||
is_published: bool
|
||||
published_at: Optional[str]
|
||||
published_at: str | None
|
||||
display_order: int
|
||||
show_in_footer: bool
|
||||
show_in_header: bool
|
||||
@@ -97,8 +96,8 @@ class ContentPageResponse(BaseModel):
|
||||
is_vendor_override: bool
|
||||
created_at: str
|
||||
updated_at: str
|
||||
created_by: Optional[int]
|
||||
updated_by: Optional[int]
|
||||
created_by: int | None
|
||||
updated_by: int | None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
@@ -106,7 +105,7 @@ class ContentPageResponse(BaseModel):
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@router.get("/platform", response_model=List[ContentPageResponse])
|
||||
@router.get("/platform", response_model=list[ContentPageResponse])
|
||||
def list_platform_pages(
|
||||
include_unpublished: bool = Query(False, description="Include draft pages"),
|
||||
current_user: User = Depends(get_current_admin_api),
|
||||
@@ -161,9 +160,9 @@ def create_platform_page(
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@router.get("/", response_model=List[ContentPageResponse])
|
||||
@router.get("/", response_model=list[ContentPageResponse])
|
||||
def list_all_pages(
|
||||
vendor_id: Optional[int] = Query(None, description="Filter by vendor ID"),
|
||||
vendor_id: int | None = Query(None, description="Filter by vendor ID"),
|
||||
include_unpublished: bool = Query(False, description="Include draft pages"),
|
||||
current_user: User = Depends(get_current_admin_api),
|
||||
db: Session = Depends(get_db),
|
||||
@@ -256,4 +255,4 @@ def delete_page(
|
||||
if not success:
|
||||
raise HTTPException(status_code=404, detail="Content page not found")
|
||||
|
||||
return None
|
||||
return
|
||||
|
||||
@@ -4,7 +4,6 @@ Admin dashboard and statistics endpoints.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -57,7 +56,7 @@ def get_comprehensive_stats(
|
||||
)
|
||||
|
||||
|
||||
@router.get("/stats/marketplace", response_model=List[MarketplaceStatsResponse])
|
||||
@router.get("/stats/marketplace", response_model=list[MarketplaceStatsResponse])
|
||||
def get_marketplace_stats(
|
||||
db: Session = Depends(get_db),
|
||||
current_admin: User = Depends(get_current_admin_api),
|
||||
|
||||
@@ -4,7 +4,6 @@ Marketplace import job monitoring endpoints for admin.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -20,11 +19,11 @@ router = APIRouter(prefix="/marketplace-import-jobs")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@router.get("", response_model=List[MarketplaceImportJobResponse])
|
||||
@router.get("", response_model=list[MarketplaceImportJobResponse])
|
||||
def get_all_marketplace_import_jobs(
|
||||
marketplace: Optional[str] = Query(None),
|
||||
vendor_name: Optional[str] = Query(None),
|
||||
status: Optional[str] = Query(None),
|
||||
marketplace: str | None = Query(None),
|
||||
vendor_name: str | None = Query(None),
|
||||
status: str | None = Query(None),
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=100),
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
@@ -9,7 +9,6 @@ Provides endpoints for:
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -17,12 +16,13 @@ from sqlalchemy.orm import Session
|
||||
from app.api.deps import get_current_admin_api
|
||||
from app.core.database import get_db
|
||||
from models.database.user import User
|
||||
from models.schema.admin import (AdminNotificationCreate,
|
||||
AdminNotificationListResponse,
|
||||
AdminNotificationResponse,
|
||||
PlatformAlertCreate,
|
||||
PlatformAlertListResponse,
|
||||
PlatformAlertResolve, PlatformAlertResponse)
|
||||
from models.schema.admin import (
|
||||
AdminNotificationListResponse,
|
||||
PlatformAlertCreate,
|
||||
PlatformAlertListResponse,
|
||||
PlatformAlertResolve,
|
||||
PlatformAlertResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/notifications")
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -35,8 +35,8 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
@router.get("", response_model=AdminNotificationListResponse)
|
||||
def get_notifications(
|
||||
priority: Optional[str] = Query(None, description="Filter by priority"),
|
||||
is_read: Optional[bool] = Query(None, description="Filter by read status"),
|
||||
priority: str | None = Query(None, description="Filter by priority"),
|
||||
is_read: bool | None = Query(None, description="Filter by read status"),
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(50, ge=1, le=100),
|
||||
db: Session = Depends(get_db),
|
||||
@@ -87,8 +87,8 @@ def mark_all_as_read(
|
||||
|
||||
@router.get("/alerts", response_model=PlatformAlertListResponse)
|
||||
def get_platform_alerts(
|
||||
severity: Optional[str] = Query(None, description="Filter by severity"),
|
||||
is_resolved: Optional[bool] = Query(
|
||||
severity: str | None = Query(None, description="Filter by severity"),
|
||||
is_resolved: bool | None = Query(
|
||||
None, description="Filter by resolution status"
|
||||
),
|
||||
skip: int = Query(0, ge=0),
|
||||
|
||||
@@ -9,7 +9,6 @@ Provides endpoints for:
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -19,8 +18,12 @@ from app.core.database import get_db
|
||||
from app.services.admin_audit_service import admin_audit_service
|
||||
from app.services.admin_settings_service import admin_settings_service
|
||||
from models.database.user import User
|
||||
from models.schema.admin import (AdminSettingCreate, AdminSettingListResponse,
|
||||
AdminSettingResponse, AdminSettingUpdate)
|
||||
from models.schema.admin import (
|
||||
AdminSettingCreate,
|
||||
AdminSettingListResponse,
|
||||
AdminSettingResponse,
|
||||
AdminSettingUpdate,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/settings")
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -28,8 +31,8 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
@router.get("", response_model=AdminSettingListResponse)
|
||||
def get_all_settings(
|
||||
category: Optional[str] = Query(None, description="Filter by category"),
|
||||
is_public: Optional[bool] = Query(None, description="Filter by public flag"),
|
||||
category: str | None = Query(None, description="Filter by category"),
|
||||
is_public: bool | None = Query(None, description="Filter by public flag"),
|
||||
db: Session = Depends(get_db),
|
||||
current_admin: User = Depends(get_current_admin_api),
|
||||
):
|
||||
|
||||
@@ -4,7 +4,6 @@ User management endpoints for admin.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -20,7 +19,7 @@ router = APIRouter(prefix="/users")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@router.get("", response_model=List[UserResponse])
|
||||
@router.get("", response_model=list[UserResponse])
|
||||
def get_all_users(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
|
||||
@@ -10,9 +10,8 @@ Follows the architecture pattern:
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Body, Depends, Path, Query
|
||||
from fastapi import APIRouter, Body, Depends, Path
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_admin_api
|
||||
@@ -21,13 +20,15 @@ from app.exceptions import VendorNotFoundException
|
||||
from app.services.vendor_domain_service import vendor_domain_service
|
||||
from models.database.user import User
|
||||
from models.database.vendor import Vendor
|
||||
from models.schema.vendor_domain import (DomainDeletionResponse,
|
||||
DomainVerificationInstructions,
|
||||
DomainVerificationResponse,
|
||||
VendorDomainCreate,
|
||||
VendorDomainListResponse,
|
||||
VendorDomainResponse,
|
||||
VendorDomainUpdate)
|
||||
from models.schema.vendor_domain import (
|
||||
DomainDeletionResponse,
|
||||
DomainVerificationInstructions,
|
||||
DomainVerificationResponse,
|
||||
VendorDomainCreate,
|
||||
VendorDomainListResponse,
|
||||
VendorDomainResponse,
|
||||
VendorDomainUpdate,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/vendors")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -20,8 +20,11 @@ from sqlalchemy.orm import Session
|
||||
from app.api.deps import get_current_admin_api, get_db
|
||||
from app.services.vendor_theme_service import vendor_theme_service
|
||||
from models.database.user import User
|
||||
from models.schema.vendor_theme import (ThemePresetListResponse,
|
||||
VendorThemeResponse, VendorThemeUpdate)
|
||||
from models.schema.vendor_theme import (
|
||||
ThemePresetListResponse,
|
||||
VendorThemeResponse,
|
||||
VendorThemeUpdate,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/vendor-themes")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -4,7 +4,7 @@ Vendor management endpoints for admin.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
from datetime import UTC
|
||||
|
||||
from fastapi import APIRouter, Body, Depends, Path, Query
|
||||
from sqlalchemy import func
|
||||
@@ -12,18 +12,21 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_admin_api
|
||||
from app.core.database import get_db
|
||||
from app.exceptions import (ConfirmationRequiredException,
|
||||
VendorNotFoundException)
|
||||
from app.exceptions import ConfirmationRequiredException, VendorNotFoundException
|
||||
from app.services.admin_service import admin_service
|
||||
from app.services.stats_service import stats_service
|
||||
from models.database.user import User
|
||||
from models.database.vendor import Vendor
|
||||
from models.schema.stats import VendorStatsResponse
|
||||
from models.schema.vendor import (VendorCreate, VendorCreateResponse,
|
||||
VendorDetailResponse, VendorListResponse,
|
||||
VendorResponse, VendorTransferOwnership,
|
||||
VendorTransferOwnershipResponse,
|
||||
VendorUpdate)
|
||||
from models.schema.vendor import (
|
||||
VendorCreate,
|
||||
VendorCreateResponse,
|
||||
VendorDetailResponse,
|
||||
VendorListResponse,
|
||||
VendorTransferOwnership,
|
||||
VendorTransferOwnershipResponse,
|
||||
VendorUpdate,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/vendors")
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -126,9 +129,9 @@ def create_vendor_with_owner(
|
||||
def get_all_vendors_admin(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
search: Optional[str] = Query(None, description="Search by name or vendor code"),
|
||||
is_active: Optional[bool] = Query(None),
|
||||
is_verified: Optional[bool] = Query(None),
|
||||
search: str | None = Query(None, description="Search by name or vendor code"),
|
||||
is_active: bool | None = Query(None),
|
||||
is_verified: bool | None = Query(None),
|
||||
db: Session = Depends(get_db),
|
||||
current_admin: User = Depends(get_current_admin_api),
|
||||
):
|
||||
@@ -282,7 +285,7 @@ def transfer_vendor_ownership(
|
||||
- `confirm_transfer`: Must be true
|
||||
- `transfer_reason`: Optional reason for audit trail
|
||||
"""
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime
|
||||
|
||||
vendor = _get_vendor_by_identifier(db, vendor_identifier)
|
||||
vendor, old_owner, new_owner = admin_service.transfer_vendor_ownership(
|
||||
@@ -304,7 +307,7 @@ def transfer_vendor_ownership(
|
||||
"username": new_owner.username,
|
||||
"email": new_owner.email,
|
||||
},
|
||||
transferred_at=datetime.now(timezone.utc),
|
||||
transferred_at=datetime.now(UTC),
|
||||
transfer_reason=transfer_data.transfer_reason,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user