refactor: fix user.id references and add missing docker imports (Task 3.4 prep)
- Fix user_id → user.id in tool_instances.py (4 occurrences) - Add get_container_status and get_container_logs imports Refs: repo-restructure Task 3.4
This commit is contained in:
@@ -4,111 +4,22 @@ import logging
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from src.auth.dependencies import get_current_user_id, get_db_session
|
||||
from src.models.config_folder import ConfigFolder
|
||||
from src.schemas.config_folder import (
|
||||
ConfigFolderCreate,
|
||||
ConfigFolderUpdate,
|
||||
ConfigFolderResponse,
|
||||
ProjectOverrideCreate,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/config-folders", tags=["config-folders"])
|
||||
|
||||
MAX_FOLDER_SIZE_MB = 10
|
||||
MAX_FOLDER_SIZE_BYTES = MAX_FOLDER_SIZE_MB * 1024 * 1024
|
||||
|
||||
|
||||
class ConfigFolderCreate(BaseModel):
|
||||
name: str = Field(description="Folder name (unique per user)")
|
||||
description: str | None = Field(default=None, description="Optional description")
|
||||
mount_path: str = Field(description="Default mount path in container")
|
||||
files: dict = Field(default_factory=dict, description="Files as {path: content}")
|
||||
|
||||
@field_validator("mount_path")
|
||||
@classmethod
|
||||
def validate_mount_path(cls, v: str) -> str:
|
||||
if not v.startswith("/"):
|
||||
raise ValueError("Mount path must be absolute (start with /)")
|
||||
return v
|
||||
|
||||
@field_validator("files")
|
||||
@classmethod
|
||||
def validate_files(cls, v: dict) -> dict:
|
||||
total_size = 0
|
||||
for path, content in v.items():
|
||||
# Check for path traversal
|
||||
if ".." in path or path.startswith("/"):
|
||||
raise ValueError(f"Invalid file path: {path}")
|
||||
total_size += len(content.encode("utf-8"))
|
||||
|
||||
if total_size > MAX_FOLDER_SIZE_BYTES:
|
||||
raise ValueError(f"Total folder size exceeds {MAX_FOLDER_SIZE_MB}MB limit")
|
||||
|
||||
return v
|
||||
|
||||
|
||||
class ConfigFolderUpdate(BaseModel):
|
||||
name: str | None = Field(default=None, description="Folder name")
|
||||
description: str | None = Field(default=None, description="Optional description")
|
||||
mount_path: str | None = Field(default=None, description="Default mount path")
|
||||
files: dict | None = Field(default=None, description="Files as {path: content}")
|
||||
is_active: bool | None = Field(default=None, description="Active/inactive toggle")
|
||||
|
||||
@field_validator("mount_path")
|
||||
@classmethod
|
||||
def validate_mount_path(cls, v: str | None) -> str | None:
|
||||
if v is None:
|
||||
return v
|
||||
if not v.startswith("/"):
|
||||
raise ValueError("Mount path must be absolute (start with /)")
|
||||
return v
|
||||
|
||||
@field_validator("files")
|
||||
@classmethod
|
||||
def validate_files(cls, v: dict | None) -> dict | None:
|
||||
if v is None:
|
||||
return v
|
||||
|
||||
total_size = 0
|
||||
for path, content in v.items():
|
||||
# Check for path traversal
|
||||
if ".." in path or path.startswith("/"):
|
||||
raise ValueError(f"Invalid file path: {path}")
|
||||
total_size += len(content.encode("utf-8"))
|
||||
|
||||
if total_size > MAX_FOLDER_SIZE_BYTES:
|
||||
raise ValueError(f"Total folder size exceeds {MAX_FOLDER_SIZE_MB}MB limit")
|
||||
|
||||
return v
|
||||
|
||||
|
||||
class ProjectOverrideCreate(BaseModel):
|
||||
mount_path: str | None = Field(default=None, description="Override mount path")
|
||||
files: dict = Field(default_factory=dict, description="Override files")
|
||||
|
||||
@field_validator("mount_path")
|
||||
@classmethod
|
||||
def validate_mount_path(cls, v: str | None) -> str | None:
|
||||
if v is None:
|
||||
return v
|
||||
if not v.startswith("/"):
|
||||
raise ValueError("Mount path must be absolute (start with /)")
|
||||
return v
|
||||
|
||||
|
||||
class ConfigFolderResponse(BaseModel):
|
||||
id: str
|
||||
user_id: str
|
||||
name: str
|
||||
description: str | None
|
||||
mount_path: str
|
||||
files: dict
|
||||
project_overrides: dict | None
|
||||
is_active: bool
|
||||
created_at: str
|
||||
updated_at: str
|
||||
|
||||
|
||||
@router.get("", summary="List config folders", description="Get all config folders for the current user.")
|
||||
async def list_config_folders(
|
||||
|
||||
@@ -33,7 +33,9 @@ from src.services.docker import (
|
||||
execute_compose_command,
|
||||
find_free_port,
|
||||
get_container_id,
|
||||
get_container_logs,
|
||||
get_container_name,
|
||||
get_container_status,
|
||||
recreate_tunnel,
|
||||
render_compose_template,
|
||||
start_cloudflared_tunnel,
|
||||
@@ -266,7 +268,7 @@ async def create_instance(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="config profile not found",
|
||||
)
|
||||
if config_profile.user_id != user_id:
|
||||
if config_profile.user_id != user.id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="config profile does not belong to user",
|
||||
@@ -577,7 +579,7 @@ async def start_instance(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="config profile not found",
|
||||
)
|
||||
if selected_profile.user_id != user_id:
|
||||
if selected_profile.user_id != user.id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="config profile does not belong to user",
|
||||
@@ -912,7 +914,7 @@ async def restart_instance(
|
||||
status_code=status.HTTP_404_NOT_FOUND,
|
||||
detail="config profile not found",
|
||||
)
|
||||
if stored_profile.user_id != user_id:
|
||||
if stored_profile.user_id != user.id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="config profile does not belong to user",
|
||||
@@ -1297,7 +1299,7 @@ async def proxy_to_instance(
|
||||
)
|
||||
|
||||
# Verify ownership
|
||||
if instance.owner_id != user_id:
|
||||
if instance.owner_id != user.id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail="not authorized to access this instance",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
"""Config folder request/response schemas."""
|
||||
|
||||
import uuid
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user