Files
headquarter/apps/api/src/api/config/user_config.py
T
alex 37ccaa4fdc refactor: organize API routers and services into subpackages
Service organization (19 files moved into 6 subpackages):
- services/instance/ — event_bus, health_monitor, lifecycle_hooks
- services/config/ — config_profile_resolver
- services/git/ — clone, git_operations, git_service
- services/build/ — docker_build, manifest_compiler
- services/terminal/ — terminal_manager, terminal_session
- services/shared/ — correlation, file_service, notification_service,
  permission_fixer, readiness_probe, ssh_keys, tunnel, workspace_manager

API router organization (16 files moved into 6 subpackages):
- api/tool/ — tool_instances, tool_types, tool_definitions,
  tool_types_validation, sessions (extracted from tool_instances)
- api/config/ — config_profiles, user_config
- api/workspace/ — workspaces, workspace_files, workspace_git,
  workspace_instances
- api/user/ — users, auth, ssh_keys
- api/project/ — projects, git_repositories
- api/system/ — health, events, notifications, dashboard, terminal,
  instance_proxy

Updated main.py imports and all __init__.py re-exports.
Sessions router extracted from tool_instances.py into api/tool/sessions.py.

Quality gates: py_compile passed, ruff passed.
2026-06-04 12:24:14 +02:00

99 lines
2.9 KiB
Python

import logging
import uuid
from fastapi import APIRouter, Depends
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from src.auth.dependencies import _get_user, get_current_user_id, get_db_session
from src.models import UserConfig
from src.schemas.user import UserConfigResponse, UserConfigUpdate
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/users/me", tags=["user-config"])
async def _get_or_create_config(
session: AsyncSession, user_id: uuid.UUID
) -> UserConfig:
"""Get or create user config record.
Args:
session: Database session.
user_id: UUID of the user.
Returns:
The user's config, creating a new one if it doesn't exist.
"""
result = await session.execute(
select(UserConfig).where(UserConfig.user_id == user_id)
)
config = result.scalar_one_or_none()
if config is None:
config = UserConfig(user_id=user_id, config={})
session.add(config)
await session.commit()
await session.refresh(config)
return config
@router.get(
"/config",
response_model=UserConfigResponse,
summary="Get user config",
description="Get the current user's configuration settings.",
)
async def get_user_config(
user_id: uuid.UUID = Depends(get_current_user_id),
session: AsyncSession = Depends(get_db_session),
) -> UserConfigResponse:
"""Get the current user's configuration.
Args:
user_id: ID of the authenticated user.
session: Database session.
Returns:
The user's configuration settings.
"""
_user = await _get_user(session, user_id)
config = await _get_or_create_config(session, user_id)
return UserConfigResponse.model_validate(config.config)
@router.patch(
"/config",
response_model=UserConfigResponse,
summary="Update user config",
description="Update the current user's configuration settings.",
)
async def update_user_config(
data: UserConfigUpdate,
user_id: uuid.UUID = Depends(get_current_user_id),
session: AsyncSession = Depends(get_db_session),
) -> UserConfigResponse:
"""Update the current user's configuration.
Args:
data: Configuration update data with optional fields.
user_id: ID of the authenticated user.
session: Database session.
Returns:
The updated user configuration.
"""
_user = await _get_user(session, user_id)
config = await _get_or_create_config(session, user_id)
# Merge updates
update_data = data.model_dump(exclude_unset=True)
logger.debug("Updating user config for user %s: %s", user_id, update_data)
# SQLAlchemy JSON doesn't track dict mutations, so we replace the whole dict
config.config = {**config.config, **update_data}
await session.commit()
await session.refresh(config)
logger.debug("Updated config: %s", config.config)
return UserConfigResponse.model_validate(config.config)