chore: retire demo technical debt
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""Memory management APIs."""
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.core.deps import require_user
|
||||
@@ -13,10 +13,12 @@ from app.services.memory_service import MemoryType
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
class MemoryItemResponse(BaseModel):
|
||||
"""Memory item response."""
|
||||
|
||||
id: str
|
||||
class MemoryItemResponse(BaseModel):
|
||||
"""Memory item response."""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
type: str
|
||||
value: dict
|
||||
base_weight: float
|
||||
@@ -24,11 +26,8 @@ class MemoryItemResponse(BaseModel):
|
||||
created_at: str
|
||||
last_used_at: str | None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class MemoryListResponse(BaseModel):
|
||||
|
||||
class MemoryListResponse(BaseModel):
|
||||
"""Memory list response."""
|
||||
|
||||
memories: list[MemoryItemResponse]
|
||||
|
||||
@@ -4,7 +4,7 @@ from datetime import date
|
||||
from typing import Literal
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -42,6 +42,8 @@ class ChildProfileUpdate(BaseModel):
|
||||
class ChildProfileResponse(BaseModel):
|
||||
"""Profile response."""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
name: str
|
||||
avatar_url: str | None
|
||||
@@ -53,9 +55,6 @@ class ChildProfileResponse(BaseModel):
|
||||
stories_count: int
|
||||
total_reading_time: int
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class ChildProfileListResponse(BaseModel):
|
||||
"""Profile list response."""
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from datetime import time
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -26,15 +26,14 @@ class PushConfigUpsert(BaseModel):
|
||||
class PushConfigResponse(BaseModel):
|
||||
"""Push config response."""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
child_profile_id: str
|
||||
push_time: time | None
|
||||
push_days: list[int]
|
||||
enabled: bool
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class PushConfigListResponse(BaseModel):
|
||||
"""Push config list response."""
|
||||
|
||||
@@ -4,7 +4,7 @@ from datetime import datetime, timezone
|
||||
from typing import Literal
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -34,6 +34,8 @@ class ReadingEventCreate(BaseModel):
|
||||
class ReadingEventResponse(BaseModel):
|
||||
"""Reading event response."""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
child_profile_id: str
|
||||
story_id: int | None
|
||||
@@ -41,9 +43,6 @@ class ReadingEventResponse(BaseModel):
|
||||
reading_time: int
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
@router.post(
|
||||
"/reading-events",
|
||||
|
||||
@@ -247,10 +247,8 @@ async def generate_storybook_api(
|
||||
return await story_service.generate_storybook_service(request, user.id, db)
|
||||
|
||||
|
||||
# ==================== Missing Endpoints (Issue #5) ====================
|
||||
|
||||
@router.get("/stories", response_model=list[StoryListItem])
|
||||
async def list_stories(
|
||||
@router.get("/stories", response_model=list[StoryListItem])
|
||||
async def list_stories(
|
||||
limit: int = 20,
|
||||
offset: int = 0,
|
||||
user: User = Depends(require_user),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
from typing import Any
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@@ -42,6 +42,8 @@ class AchievementCreate(BaseModel):
|
||||
class StoryUniverseResponse(BaseModel):
|
||||
"""Universe response."""
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: str
|
||||
child_profile_id: str
|
||||
name: str
|
||||
@@ -50,9 +52,6 @@ class StoryUniverseResponse(BaseModel):
|
||||
world_settings: dict[str, Any]
|
||||
achievements: list[dict[str, Any]]
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
class StoryUniverseListResponse(BaseModel):
|
||||
"""Universe list response."""
|
||||
|
||||
@@ -86,10 +86,10 @@ class Settings(BaseSettings):
|
||||
description="Socket timeout in seconds for Sentinel clients",
|
||||
)
|
||||
|
||||
# Admin console
|
||||
enable_admin_console: bool = False
|
||||
admin_username: str = "admin"
|
||||
admin_password: str = "admin123" # 建议通过环境变量覆盖
|
||||
# Admin console
|
||||
enable_admin_console: bool = False
|
||||
admin_username: str = "admin"
|
||||
admin_password: str = ""
|
||||
|
||||
# CORS
|
||||
cors_origins: list[str] = Field(default_factory=lambda: ["http://localhost:5173"])
|
||||
@@ -101,11 +101,17 @@ class Settings(BaseSettings):
|
||||
missing.append("SECRET_KEY")
|
||||
if not self.database_url:
|
||||
missing.append("DATABASE_URL")
|
||||
if self.redis_sentinel_enabled and not self.redis_sentinel_nodes.strip():
|
||||
missing.append("REDIS_SENTINEL_NODES")
|
||||
if missing:
|
||||
raise ValueError(f"Missing required settings: {', '.join(missing)}")
|
||||
return self
|
||||
if self.redis_sentinel_enabled and not self.redis_sentinel_nodes.strip():
|
||||
missing.append("REDIS_SENTINEL_NODES")
|
||||
if missing:
|
||||
raise ValueError(f"Missing required settings: {', '.join(missing)}")
|
||||
if self.enable_admin_console:
|
||||
weak_admin_passwords = {"", "admin", "admin123", "password", "change-me"}
|
||||
if not self.debug and self.admin_password in weak_admin_passwords:
|
||||
raise ValueError(
|
||||
"ADMIN_PASSWORD must be set to a strong value when admin console is enabled"
|
||||
)
|
||||
return self
|
||||
|
||||
@property
|
||||
def redis_sentinel_hosts(self) -> list[tuple[str, int]]:
|
||||
|
||||
@@ -794,9 +794,7 @@ async def generate_generation_service(
|
||||
)
|
||||
|
||||
|
||||
# ==================== Missing Endpoints Logic (for Issue #5) ====================
|
||||
|
||||
async def list_stories(
|
||||
async def list_stories(
|
||||
user_id: str,
|
||||
limit: int,
|
||||
offset: int,
|
||||
|
||||
Reference in New Issue
Block a user