130cc840c7
按管理员将 Servers 页搜索记录存入 admin_ui_preferences,换设备登录仍可恢复;首次自动迁移 localStorage。 Co-authored-by: Cursor <cursoragent@cursor.com>
56 lines
1.7 KiB
Python
56 lines
1.7 KiB
Python
"""Admin UI preference repository — per-admin JSON blobs (search history, etc.)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from server.domain.models import AdminUiPreference
|
|
|
|
|
|
def _utcnow() -> datetime:
|
|
return datetime.now(timezone.utc).replace(tzinfo=None)
|
|
|
|
|
|
class AdminUiPreferenceRepositoryImpl:
|
|
def __init__(self, session: AsyncSession):
|
|
self.session = session
|
|
|
|
async def get(self, admin_id: int, context: str) -> dict | None:
|
|
result = await self.session.execute(
|
|
select(AdminUiPreference).where(
|
|
AdminUiPreference.admin_id == admin_id,
|
|
AdminUiPreference.context == context,
|
|
)
|
|
)
|
|
row = result.scalar_one_or_none()
|
|
if not row or not isinstance(row.payload, dict):
|
|
return None
|
|
return dict(row.payload)
|
|
|
|
async def upsert(self, admin_id: int, context: str, payload: dict) -> dict:
|
|
result = await self.session.execute(
|
|
select(AdminUiPreference).where(
|
|
AdminUiPreference.admin_id == admin_id,
|
|
AdminUiPreference.context == context,
|
|
)
|
|
)
|
|
row = result.scalar_one_or_none()
|
|
now = _utcnow()
|
|
if row:
|
|
row.payload = payload
|
|
row.updated_at = now
|
|
else:
|
|
self.session.add(
|
|
AdminUiPreference(
|
|
admin_id=admin_id,
|
|
context=context,
|
|
payload=payload,
|
|
updated_at=now,
|
|
)
|
|
)
|
|
await self.session.commit()
|
|
return payload
|