refactor(09-05): CODE-09 purge — Phase 8 backend sub-packages (WHAT comments removed)
- api/admin/users.py: removed module docstring + 7 WHAT function docstrings - api/admin/quotas.py: removed module docstring + 2 WHAT function docstrings - api/admin/ai.py: removed module docstring + 3 WHAT inline comments; security invariant docstrings preserved - api/admin/shared.py: unchanged (all comments are WHY — constraint notes) - api/documents/upload.py: removed 4 WHAT inline comments; T-03-05/T-03-06 WHY notes preserved - api/documents/content.py: removed WHAT function docstring + WHAT inline comment - api/documents/crud.py: removed 7 WHAT inline comments; D-16 + security constraint docstrings preserved - api/auth/shared.py: removed module docstring + 1 WHAT inline comment - api/auth/tokens.py: removed module docstring + 8 WHAT function docstrings/comments; family-revocation + SEC-02 WHY notes preserved - api/auth/totp.py: removed module docstring + 2 WHAT function docstrings + 2 WHAT inline comments - api/auth/password.py: removed module docstring + 2 WHAT function docstrings + 3 WHAT inline comments - All NO-prefix anchor comments and security-invariant WHY comments preserved - pytest: 413 passed, 1 failed (pre-existing ModuleNotFoundError unrelated to purge)
This commit is contained in:
@@ -1,11 +1,3 @@
|
||||
"""Admin user-management endpoints.
|
||||
|
||||
Handles: list_users, create_user, update_user_status, initiate_password_reset,
|
||||
update_ai_config (per-user), delete_user, create_system_topic.
|
||||
|
||||
All handlers require get_current_admin (SEC-07, T-08-04-01).
|
||||
Sub-router has NO prefix — parent __init__.py carries /api/admin (D-04).
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
@@ -79,11 +71,6 @@ async def list_users(
|
||||
session: AsyncSession = Depends(get_db),
|
||||
_admin: User = Depends(get_current_admin),
|
||||
) -> dict:
|
||||
"""List all users, ordered by created_at DESC.
|
||||
|
||||
Response shape: { items: [...safe user fields...] }
|
||||
Never includes password_hash, credentials_enc, or document content (T-02-27).
|
||||
"""
|
||||
result = await session.execute(
|
||||
select(User).order_by(User.created_at.desc())
|
||||
)
|
||||
@@ -98,14 +85,6 @@ async def create_user(
|
||||
session: AsyncSession = Depends(get_db),
|
||||
_admin: User = Depends(get_current_admin),
|
||||
) -> dict:
|
||||
"""Admin creates a new user account (ADMIN-01).
|
||||
|
||||
- password_must_change=True forces the user to change their password on
|
||||
first login (T-02-32, D-06).
|
||||
- Quota row initialized at 100 MB (D-06).
|
||||
- Returns 409 if email or handle is already taken.
|
||||
"""
|
||||
# Check uniqueness
|
||||
existing_email = await session.execute(
|
||||
select(User).where(User.email == str(body.email))
|
||||
)
|
||||
@@ -172,11 +151,6 @@ async def update_user_status(
|
||||
session: AsyncSession = Depends(get_db),
|
||||
_admin: User = Depends(get_current_admin),
|
||||
) -> dict:
|
||||
"""Deactivate or reactivate a user account (ADMIN-02).
|
||||
|
||||
- Prevents deactivating the last active admin (T-02-29).
|
||||
- On deactivation: all refresh tokens are revoked (family revocation).
|
||||
"""
|
||||
user = await session.get(User, user_id)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||
@@ -237,15 +211,6 @@ async def initiate_password_reset(
|
||||
session: AsyncSession = Depends(get_db),
|
||||
_admin: User = Depends(get_current_admin),
|
||||
) -> dict:
|
||||
"""Admin initiates a password reset for a user (ADMIN-03).
|
||||
|
||||
Sends the reset email via Celery. Does NOT:
|
||||
- return a reset token (T-02-30)
|
||||
- grant admin access to the account
|
||||
- log in as the target user (ADMIN-07 — no impersonation)
|
||||
|
||||
Returns 202 immediately regardless of email delivery status.
|
||||
"""
|
||||
user = await session.get(User, user_id)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||
@@ -271,11 +236,6 @@ async def update_ai_config(
|
||||
session: AsyncSession = Depends(get_db),
|
||||
_admin: User = Depends(get_current_admin),
|
||||
) -> dict:
|
||||
"""Assign AI provider and model for a user (ADMIN-05).
|
||||
|
||||
Users cannot change their own AI provider or model (PROJECT.md Key Decision).
|
||||
Only admins have this capability.
|
||||
"""
|
||||
user = await session.get(User, user_id)
|
||||
if user is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="User not found")
|
||||
@@ -313,15 +273,6 @@ async def delete_user(
|
||||
session: AsyncSession = Depends(get_db),
|
||||
_admin: User = Depends(get_current_admin),
|
||||
) -> None:
|
||||
"""Delete a user account and clean up all their MinIO objects (SEC-09, D-19).
|
||||
|
||||
Security invariants:
|
||||
- Admin password verified via Argon2 before any deletion (T-05-11-01)
|
||||
- Cannot delete admin accounts (T-04-07-04)
|
||||
- MinIO objects are deleted BEFORE DB records are removed (SEC-09)
|
||||
- MinIO deletion is best-effort (try/except) — DB row is deleted regardless
|
||||
- Audit log written with event_type="admin.user_deleted"
|
||||
"""
|
||||
# T-05-11-01: Verify admin password before performing any destructive action.
|
||||
# Fail fast — no DB reads for the target user until the admin is confirmed.
|
||||
if not verify_password(body.admin_password, _admin.password_hash):
|
||||
@@ -414,15 +365,6 @@ async def create_system_topic(
|
||||
session: AsyncSession = Depends(get_db),
|
||||
_admin: User = Depends(get_current_admin),
|
||||
) -> dict:
|
||||
"""Create a system topic visible to all users (D-09, DOC-04).
|
||||
|
||||
System topics have user_id = NULL, making them visible to every user as
|
||||
defaults in their topic namespace. Only admins can create system topics.
|
||||
Regular users create per-user topics via POST /api/topics.
|
||||
|
||||
Deduplication: case-insensitive match within the system namespace (user_id IS NULL).
|
||||
Returns the existing system topic if one with the same name already exists.
|
||||
"""
|
||||
from services import storage # noqa: PLC0415
|
||||
|
||||
topic = await storage.create_topic(
|
||||
|
||||
Reference in New Issue
Block a user