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:
@@ -32,18 +32,20 @@ The cookie path restrictions prevent cross-context cookie leakage:
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
from datetime import UTC
|
||||
|
||||
from fastapi import Cookie, Depends, Request
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.exceptions import (AdminRequiredException,
|
||||
InsufficientPermissionsException,
|
||||
InvalidTokenException,
|
||||
UnauthorizedVendorAccessException,
|
||||
VendorNotFoundException)
|
||||
from app.exceptions import (
|
||||
AdminRequiredException,
|
||||
InsufficientPermissionsException,
|
||||
InvalidTokenException,
|
||||
UnauthorizedVendorAccessException,
|
||||
VendorNotFoundException,
|
||||
)
|
||||
from middleware.auth import AuthManager
|
||||
from middleware.rate_limiter import RateLimiter
|
||||
from models.database.user import User
|
||||
@@ -62,11 +64,11 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_token_from_request(
|
||||
credentials: Optional[HTTPAuthorizationCredentials],
|
||||
cookie_value: Optional[str],
|
||||
credentials: HTTPAuthorizationCredentials | None,
|
||||
cookie_value: str | None,
|
||||
cookie_name: str,
|
||||
request_path: str,
|
||||
) -> tuple[Optional[str], Optional[str]]:
|
||||
) -> tuple[str | None, str | None]:
|
||||
"""
|
||||
Extract token from Authorization header or cookie.
|
||||
|
||||
@@ -86,7 +88,7 @@ def _get_token_from_request(
|
||||
if credentials:
|
||||
logger.debug(f"Token found in Authorization header for {request_path}")
|
||||
return credentials.credentials, "header"
|
||||
elif cookie_value:
|
||||
if cookie_value:
|
||||
logger.debug(f"Token found in {cookie_name} cookie for {request_path}")
|
||||
return cookie_value, "cookie"
|
||||
|
||||
@@ -118,8 +120,8 @@ def _validate_user_token(token: str, db: Session) -> User:
|
||||
|
||||
def get_current_admin_from_cookie_or_header(
|
||||
request: Request,
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
|
||||
admin_token: Optional[str] = Cookie(None),
|
||||
credentials: HTTPAuthorizationCredentials | None = Depends(security),
|
||||
admin_token: str | None = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> User:
|
||||
"""
|
||||
@@ -205,8 +207,8 @@ def get_current_admin_api(
|
||||
|
||||
def get_current_vendor_from_cookie_or_header(
|
||||
request: Request,
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
|
||||
vendor_token: Optional[str] = Cookie(None),
|
||||
credentials: HTTPAuthorizationCredentials | None = Depends(security),
|
||||
vendor_token: str | None = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> User:
|
||||
"""
|
||||
@@ -305,8 +307,8 @@ def get_current_vendor_api(
|
||||
|
||||
def get_current_customer_from_cookie_or_header(
|
||||
request: Request,
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
|
||||
customer_token: Optional[str] = Cookie(None),
|
||||
credentials: HTTPAuthorizationCredentials | None = Depends(security),
|
||||
customer_token: str | None = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
@@ -331,7 +333,7 @@ def get_current_customer_from_cookie_or_header(
|
||||
Raises:
|
||||
InvalidTokenException: If no token or invalid token
|
||||
"""
|
||||
from datetime import datetime, timezone
|
||||
from datetime import datetime
|
||||
|
||||
from jose import JWTError, jwt
|
||||
|
||||
@@ -365,8 +367,8 @@ def get_current_customer_from_cookie_or_header(
|
||||
|
||||
# Verify token hasn't expired
|
||||
exp = payload.get("exp")
|
||||
if exp and datetime.fromtimestamp(exp, tz=timezone.utc) < datetime.now(
|
||||
timezone.utc
|
||||
if exp and datetime.fromtimestamp(exp, tz=UTC) < datetime.now(
|
||||
UTC
|
||||
):
|
||||
logger.warning(f"Expired customer token for customer_id={customer_id}")
|
||||
raise InvalidTokenException("Token has expired")
|
||||
@@ -694,10 +696,10 @@ def get_user_permissions(
|
||||
|
||||
def get_current_admin_optional(
|
||||
request: Request,
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
|
||||
admin_token: Optional[str] = Cookie(None),
|
||||
credentials: HTTPAuthorizationCredentials | None = Depends(security),
|
||||
admin_token: str | None = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> Optional[User]:
|
||||
) -> User | None:
|
||||
"""
|
||||
Get current admin user from admin_token cookie or Authorization header.
|
||||
|
||||
@@ -741,10 +743,10 @@ def get_current_admin_optional(
|
||||
|
||||
def get_current_vendor_optional(
|
||||
request: Request,
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
|
||||
vendor_token: Optional[str] = Cookie(None),
|
||||
credentials: HTTPAuthorizationCredentials | None = Depends(security),
|
||||
vendor_token: str | None = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> Optional[User]:
|
||||
) -> User | None:
|
||||
"""
|
||||
Get current vendor user from vendor_token cookie or Authorization header.
|
||||
|
||||
@@ -788,10 +790,10 @@ def get_current_vendor_optional(
|
||||
|
||||
def get_current_customer_optional(
|
||||
request: Request,
|
||||
credentials: Optional[HTTPAuthorizationCredentials] = Depends(security),
|
||||
customer_token: Optional[str] = Cookie(None),
|
||||
credentials: HTTPAuthorizationCredentials | None = Depends(security),
|
||||
customer_token: str | None = Cookie(None),
|
||||
db: Session = Depends(get_db),
|
||||
) -> Optional[User]:
|
||||
) -> User | None:
|
||||
"""
|
||||
Get current customer user from customer_token cookie or Authorization header.
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
@@ -14,9 +14,13 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.services.cart_service import cart_service
|
||||
from models.schema.cart import (AddToCartRequest, CartOperationResponse,
|
||||
CartResponse, ClearCartResponse,
|
||||
UpdateCartItemRequest)
|
||||
from models.schema.cart import (
|
||||
AddToCartRequest,
|
||||
CartOperationResponse,
|
||||
CartResponse,
|
||||
ClearCartResponse,
|
||||
UpdateCartItemRequest,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -7,7 +7,6 @@ No authentication required.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request
|
||||
from pydantic import BaseModel
|
||||
@@ -52,7 +51,7 @@ class ContentPageListItem(BaseModel):
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@router.get("/navigation", response_model=List[ContentPageListItem])
|
||||
@router.get("/navigation", response_model=list[ContentPageListItem])
|
||||
def get_navigation_pages(request: Request, db: Session = Depends(get_db)):
|
||||
"""
|
||||
Get list of content pages for navigation (footer/header).
|
||||
|
||||
@@ -8,7 +8,6 @@ Requires customer authentication for most operations.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -19,8 +18,12 @@ from app.services.customer_service import customer_service
|
||||
from app.services.order_service import order_service
|
||||
from models.database.customer import Customer
|
||||
from models.database.user import User
|
||||
from models.schema.order import (OrderCreate, OrderDetailResponse,
|
||||
OrderListResponse, OrderResponse)
|
||||
from models.schema.order import (
|
||||
OrderCreate,
|
||||
OrderDetailResponse,
|
||||
OrderListResponse,
|
||||
OrderResponse,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -8,15 +8,17 @@ No authentication required.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.database import get_db
|
||||
from app.services.product_service import product_service
|
||||
from models.schema.product import (ProductDetailResponse, ProductListResponse,
|
||||
ProductResponse)
|
||||
from models.schema.product import (
|
||||
ProductDetailResponse,
|
||||
ProductListResponse,
|
||||
ProductResponse,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -27,8 +29,8 @@ def get_product_catalog(
|
||||
request: Request,
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
search: Optional[str] = Query(None, description="Search products by name"),
|
||||
is_featured: Optional[bool] = Query(
|
||||
search: str | None = Query(None, description="Search products by name"),
|
||||
is_featured: bool | None = Query(
|
||||
None, description="Filter by featured products"
|
||||
),
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
21
app/api/v1/vendor/__init__.py
vendored
21
app/api/v1/vendor/__init__.py
vendored
@@ -13,9 +13,24 @@ IMPORTANT:
|
||||
from fastapi import APIRouter
|
||||
|
||||
# Import all sub-routers (JSON API only)
|
||||
from . import (analytics, auth, content_pages, customers, dashboard, info,
|
||||
inventory, marketplace, media, notifications, orders, payments,
|
||||
products, profile, settings, team)
|
||||
from . import (
|
||||
analytics,
|
||||
auth,
|
||||
content_pages,
|
||||
customers,
|
||||
dashboard,
|
||||
info,
|
||||
inventory,
|
||||
marketplace,
|
||||
media,
|
||||
notifications,
|
||||
orders,
|
||||
payments,
|
||||
products,
|
||||
profile,
|
||||
settings,
|
||||
team,
|
||||
)
|
||||
|
||||
# Create vendor router
|
||||
router = APIRouter()
|
||||
|
||||
43
app/api/v1/vendor/content_pages.py
vendored
43
app/api/v1/vendor/content_pages.py
vendored
@@ -9,7 +9,6 @@ Vendors can:
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel, Field
|
||||
@@ -41,10 +40,10 @@ class VendorContentPageCreate(BaseModel):
|
||||
content_format: str = Field(
|
||||
default="html", description="Content format: html or markdown"
|
||||
)
|
||||
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")
|
||||
@@ -56,31 +55,31 @@ class VendorContentPageCreate(BaseModel):
|
||||
class VendorContentPageUpdate(BaseModel):
|
||||
"""Schema for updating a vendor content page."""
|
||||
|
||||
title: Optional[str] = Field(None, max_length=200)
|
||||
content: Optional[str] = None
|
||||
content_format: Optional[str] = None
|
||||
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
|
||||
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
|
||||
@@ -88,8 +87,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
|
||||
|
||||
|
||||
# ============================================================================
|
||||
@@ -97,7 +96,7 @@ class ContentPageResponse(BaseModel):
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@router.get("/", response_model=List[ContentPageResponse])
|
||||
@router.get("/", response_model=list[ContentPageResponse])
|
||||
def list_vendor_pages(
|
||||
include_unpublished: bool = Query(False, description="Include draft pages"),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
@@ -120,7 +119,7 @@ def list_vendor_pages(
|
||||
return [page.to_dict() for page in pages]
|
||||
|
||||
|
||||
@router.get("/overrides", response_model=List[ContentPageResponse])
|
||||
@router.get("/overrides", response_model=list[ContentPageResponse])
|
||||
def list_vendor_overrides(
|
||||
include_unpublished: bool = Query(False, description="Include draft pages"),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
@@ -284,4 +283,4 @@ def delete_vendor_page(
|
||||
# Delete
|
||||
content_page_service.delete_page(db, page_id)
|
||||
|
||||
return None
|
||||
return
|
||||
|
||||
5
app/api/v1/vendor/customers.py
vendored
5
app/api/v1/vendor/customers.py
vendored
@@ -5,7 +5,6 @@ Vendor customer management endpoints.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -24,8 +23,8 @@ logger = logging.getLogger(__name__)
|
||||
def get_vendor_customers(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
search: Optional[str] = Query(None),
|
||||
is_active: Optional[bool] = Query(None),
|
||||
search: str | None = Query(None),
|
||||
is_active: bool | None = Query(None),
|
||||
vendor: Vendor = Depends(require_vendor_context()),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
2
app/api/v1/vendor/dashboard.py
vendored
2
app/api/v1/vendor/dashboard.py
vendored
@@ -11,9 +11,7 @@ from sqlalchemy.orm import Session
|
||||
from app.api.deps import get_current_vendor_api
|
||||
from app.core.database import get_db
|
||||
from app.services.stats_service import stats_service
|
||||
from middleware.vendor_context import require_vendor_context
|
||||
from models.database.user import User
|
||||
from models.database.vendor import Vendor
|
||||
|
||||
router = APIRouter(prefix="/dashboard")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
2
app/api/v1/vendor/info.py
vendored
2
app/api/v1/vendor/info.py
vendored
@@ -16,7 +16,7 @@ from sqlalchemy.orm import Session
|
||||
from app.core.database import get_db
|
||||
from app.exceptions import VendorNotFoundException
|
||||
from models.database.vendor import Vendor
|
||||
from models.schema.vendor import VendorDetailResponse, VendorResponse
|
||||
from models.schema.vendor import VendorDetailResponse
|
||||
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
18
app/api/v1/vendor/inventory.py
vendored
18
app/api/v1/vendor/inventory.py
vendored
@@ -1,6 +1,5 @@
|
||||
# app/api/v1/vendor/inventory.py
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -11,10 +10,15 @@ from app.services.inventory_service import inventory_service
|
||||
from middleware.vendor_context import require_vendor_context
|
||||
from models.database.user import User
|
||||
from models.database.vendor import Vendor
|
||||
from models.schema.inventory import (InventoryAdjust, InventoryCreate,
|
||||
InventoryListResponse, InventoryReserve,
|
||||
InventoryResponse, InventoryUpdate,
|
||||
ProductInventorySummary)
|
||||
from models.schema.inventory import (
|
||||
InventoryAdjust,
|
||||
InventoryCreate,
|
||||
InventoryListResponse,
|
||||
InventoryReserve,
|
||||
InventoryResponse,
|
||||
InventoryUpdate,
|
||||
ProductInventorySummary,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -90,8 +94,8 @@ def get_product_inventory(
|
||||
def get_vendor_inventory(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
location: Optional[str] = Query(None),
|
||||
low_stock: Optional[int] = Query(None, ge=0),
|
||||
location: str | None = Query(None),
|
||||
low_stock: int | None = Query(None, ge=0),
|
||||
vendor: Vendor = Depends(require_vendor_context()),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
14
app/api/v1/vendor/marketplace.py
vendored
14
app/api/v1/vendor/marketplace.py
vendored
@@ -5,22 +5,22 @@ Vendor context is automatically injected by middleware.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_vendor_api
|
||||
from app.core.database import get_db
|
||||
from app.services.marketplace_import_job_service import \
|
||||
marketplace_import_job_service
|
||||
from app.services.marketplace_import_job_service import marketplace_import_job_service
|
||||
from app.tasks.background_tasks import process_marketplace_import
|
||||
from middleware.decorators import rate_limit
|
||||
from middleware.vendor_context import require_vendor_context # IMPORTANT
|
||||
from models.database.user import User
|
||||
from models.database.vendor import Vendor
|
||||
from models.schema.marketplace_import_job import (MarketplaceImportJobRequest,
|
||||
MarketplaceImportJobResponse)
|
||||
from models.schema.marketplace_import_job import (
|
||||
MarketplaceImportJobRequest,
|
||||
MarketplaceImportJobResponse,
|
||||
)
|
||||
|
||||
router = APIRouter()
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -93,9 +93,9 @@ def get_marketplace_import_status(
|
||||
return marketplace_import_job_service.convert_to_response_model(job)
|
||||
|
||||
|
||||
@router.get("/imports", response_model=List[MarketplaceImportJobResponse])
|
||||
@router.get("/imports", response_model=list[MarketplaceImportJobResponse])
|
||||
def get_marketplace_import_jobs(
|
||||
marketplace: Optional[str] = Query(None, description="Filter by marketplace"),
|
||||
marketplace: str | None = Query(None, description="Filter by marketplace"),
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(50, ge=1, le=100),
|
||||
vendor: Vendor = Depends(require_vendor_context()),
|
||||
|
||||
9
app/api/v1/vendor/media.py
vendored
9
app/api/v1/vendor/media.py
vendored
@@ -5,7 +5,6 @@ Vendor media and file management endpoints.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Query, UploadFile
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -24,8 +23,8 @@ logger = logging.getLogger(__name__)
|
||||
def get_media_library(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
media_type: Optional[str] = Query(None, description="image, video, document"),
|
||||
search: Optional[str] = Query(None),
|
||||
media_type: str | None = Query(None, description="image, video, document"),
|
||||
search: str | None = Query(None),
|
||||
vendor: Vendor = Depends(require_vendor_context()),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
@@ -52,7 +51,7 @@ def get_media_library(
|
||||
@router.post("/upload")
|
||||
async def upload_media(
|
||||
file: UploadFile = File(...),
|
||||
folder: Optional[str] = Query(None, description="products, general, etc."),
|
||||
folder: str | None = Query(None, description="products, general, etc."),
|
||||
vendor: Vendor = Depends(require_vendor_context()),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
@@ -78,7 +77,7 @@ async def upload_media(
|
||||
@router.post("/upload/multiple")
|
||||
async def upload_multiple_media(
|
||||
files: list[UploadFile] = File(...),
|
||||
folder: Optional[str] = Query(None),
|
||||
folder: str | None = Query(None),
|
||||
vendor: Vendor = Depends(require_vendor_context()),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
3
app/api/v1/vendor/notifications.py
vendored
3
app/api/v1/vendor/notifications.py
vendored
@@ -5,7 +5,6 @@ Vendor notification management endpoints.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -24,7 +23,7 @@ logger = logging.getLogger(__name__)
|
||||
def get_notifications(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(50, ge=1, le=100),
|
||||
unread_only: Optional[bool] = Query(False),
|
||||
unread_only: bool | None = Query(False),
|
||||
vendor: Vendor = Depends(require_vendor_context()),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
17
app/api/v1/vendor/orders.py
vendored
17
app/api/v1/vendor/orders.py
vendored
@@ -4,9 +4,8 @@ Vendor order management endpoints.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_vendor_api
|
||||
@@ -14,9 +13,13 @@ from app.core.database import get_db
|
||||
from app.services.order_service import order_service
|
||||
from middleware.vendor_context import require_vendor_context
|
||||
from models.database.user import User
|
||||
from models.database.vendor import Vendor, VendorUser
|
||||
from models.schema.order import (OrderDetailResponse, OrderListResponse,
|
||||
OrderResponse, OrderUpdate)
|
||||
from models.database.vendor import Vendor
|
||||
from models.schema.order import (
|
||||
OrderDetailResponse,
|
||||
OrderListResponse,
|
||||
OrderResponse,
|
||||
OrderUpdate,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/orders")
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -26,8 +29,8 @@ logger = logging.getLogger(__name__)
|
||||
def get_vendor_orders(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
status: Optional[str] = Query(None, description="Filter by order status"),
|
||||
customer_id: Optional[int] = Query(None, description="Filter by customer"),
|
||||
status: str | None = Query(None, description="Filter by order status"),
|
||||
customer_id: int | None = Query(None, description="Filter by customer"),
|
||||
vendor: Vendor = Depends(require_vendor_context()),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
15
app/api/v1/vendor/products.py
vendored
15
app/api/v1/vendor/products.py
vendored
@@ -4,7 +4,6 @@ Vendor product catalog management endpoints.
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -15,9 +14,13 @@ from app.services.product_service import product_service
|
||||
from middleware.vendor_context import require_vendor_context
|
||||
from models.database.user import User
|
||||
from models.database.vendor import Vendor
|
||||
from models.schema.product import (ProductCreate, ProductDetailResponse,
|
||||
ProductListResponse, ProductResponse,
|
||||
ProductUpdate)
|
||||
from models.schema.product import (
|
||||
ProductCreate,
|
||||
ProductDetailResponse,
|
||||
ProductListResponse,
|
||||
ProductResponse,
|
||||
ProductUpdate,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/products")
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -27,8 +30,8 @@ logger = logging.getLogger(__name__)
|
||||
def get_vendor_products(
|
||||
skip: int = Query(0, ge=0),
|
||||
limit: int = Query(100, ge=1, le=1000),
|
||||
is_active: Optional[bool] = Query(None),
|
||||
is_featured: Optional[bool] = Query(None),
|
||||
is_active: bool | None = Query(None),
|
||||
is_featured: bool | None = Query(None),
|
||||
vendor: Vendor = Depends(require_vendor_context()),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
db: Session = Depends(get_db),
|
||||
|
||||
33
app/api/v1/vendor/team.py
vendored
33
app/api/v1/vendor/team.py
vendored
@@ -11,25 +11,34 @@ Implements complete team management with:
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, Request
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import (get_current_vendor_api, get_user_permissions,
|
||||
require_vendor_owner, require_vendor_permission)
|
||||
from app.api.deps import (
|
||||
get_current_vendor_api,
|
||||
get_user_permissions,
|
||||
require_vendor_owner,
|
||||
require_vendor_permission,
|
||||
)
|
||||
from app.core.database import get_db
|
||||
from app.core.permissions import VendorPermissions
|
||||
from app.services.vendor_team_service import vendor_team_service
|
||||
from models.database.user import User
|
||||
from models.database.vendor import Vendor
|
||||
from models.schema.team import (BulkRemoveRequest, BulkRemoveResponse,
|
||||
InvitationAccept, InvitationAcceptResponse,
|
||||
InvitationResponse, RoleListResponse,
|
||||
RoleResponse, TeamMemberInvite,
|
||||
TeamMemberListResponse, TeamMemberResponse,
|
||||
TeamMemberUpdate, TeamStatistics,
|
||||
UserPermissionsResponse)
|
||||
from models.schema.team import (
|
||||
BulkRemoveRequest,
|
||||
BulkRemoveResponse,
|
||||
InvitationAccept,
|
||||
InvitationAcceptResponse,
|
||||
InvitationResponse,
|
||||
RoleListResponse,
|
||||
TeamMemberInvite,
|
||||
TeamMemberListResponse,
|
||||
TeamMemberResponse,
|
||||
TeamMemberUpdate,
|
||||
TeamStatistics,
|
||||
UserPermissionsResponse,
|
||||
)
|
||||
|
||||
router = APIRouter(prefix="/team")
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -382,7 +391,7 @@ def list_roles(
|
||||
@router.get("/me/permissions", response_model=UserPermissionsResponse)
|
||||
def get_my_permissions(
|
||||
request: Request,
|
||||
permissions: List[str] = Depends(get_user_permissions),
|
||||
permissions: list[str] = Depends(get_user_permissions),
|
||||
current_user: User = Depends(get_current_vendor_api),
|
||||
):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user