Добавлены уведомления
This commit is contained in:
@@ -50,6 +50,8 @@ from app.integrations import (
|
||||
S3Client,
|
||||
SafetyClient,
|
||||
)
|
||||
from app.notification_routes import router as notification_router
|
||||
from app.notification_service import synchronize_source_tokens
|
||||
from app.realtime import RealtimeFanout
|
||||
from app.schemas import (
|
||||
AttachmentCompleteRequest,
|
||||
@@ -128,6 +130,7 @@ async def lifespan(app: FastAPI):
|
||||
try:
|
||||
async with app.state.db.sessions() as db:
|
||||
app.state.snapshot = await load_settings(db)
|
||||
await synchronize_source_tokens(db)
|
||||
except Exception:
|
||||
structlog.get_logger().warning("settings.warmup_failed")
|
||||
settings_task = asyncio.create_task(refresh_settings_cache(app))
|
||||
@@ -153,6 +156,7 @@ app = FastAPI(
|
||||
redoc_url=None,
|
||||
lifespan=lifespan,
|
||||
)
|
||||
app.include_router(notification_router)
|
||||
log = structlog.get_logger()
|
||||
|
||||
|
||||
@@ -243,7 +247,7 @@ async def request_context(request: Request, call_next: Any) -> Response:
|
||||
response.headers["Access-Control-Allow-Headers"] = (
|
||||
"Authorization,Content-Type,Idempotency-Key,X-Request-ID,X-Ux-Session-Id"
|
||||
)
|
||||
response.headers["Access-Control-Allow-Methods"] = "GET,POST,OPTIONS"
|
||||
response.headers["Access-Control-Allow-Methods"] = "GET,POST,DELETE,OPTIONS"
|
||||
response.headers["Vary"] = "Origin"
|
||||
response.headers["X-Request-ID"] = request_id
|
||||
response.headers["X-Content-Type-Options"] = "nosniff"
|
||||
@@ -416,7 +420,7 @@ async def ready(request: Request, db: Session):
|
||||
try:
|
||||
await db.execute(text("SELECT 1"))
|
||||
revision = await db.scalar(text("SELECT version_num FROM han_app.alembic_version LIMIT 1"))
|
||||
if revision != "0005_otp_settings":
|
||||
if revision != "0008_notifications_v1":
|
||||
raise RuntimeError("unexpected database revision")
|
||||
await load_settings(db)
|
||||
components["postgres"] = "ok"
|
||||
@@ -498,6 +502,14 @@ async def app_config(request: Request, response: Response, settings: SnapshotDep
|
||||
"allowed_mime_types": settings.strings("chat.attachments.allowed_mime_types"),
|
||||
"max_size_mb": settings.integer("chat.attachments.max_size_mb"),
|
||||
},
|
||||
"notification": {
|
||||
"carousel_autoplay_enabled": settings.boolean(
|
||||
"notification.carousel.autoplay_enabled"
|
||||
),
|
||||
"carousel_autoplay_interval_ms": settings.integer(
|
||||
"notification.carousel.autoplay_interval_ms"
|
||||
),
|
||||
},
|
||||
"ux": {"idle_timeout_minutes": settings.integer("ux.session.idle_timeout_minutes")},
|
||||
}
|
||||
|
||||
@@ -1062,6 +1074,7 @@ async def realtime(websocket: WebSocket):
|
||||
await websocket.close(code=4400)
|
||||
return
|
||||
ids = {uuid.UUID(value) for value in payload.get("dialog_ids", [])[:100]}
|
||||
notifications = bool(payload.get("notifications", False))
|
||||
count = await db.scalar(
|
||||
select(func.count(Dialog.id)).where(
|
||||
Dialog.id.in_(ids),
|
||||
@@ -1076,10 +1089,16 @@ async def realtime(websocket: WebSocket):
|
||||
event_task.cancel()
|
||||
if event_stream:
|
||||
await event_stream.aclose()
|
||||
event_stream = websocket.app.state.realtime.events(ids)
|
||||
event_stream = websocket.app.state.realtime.events(
|
||||
ids, user.id, notifications
|
||||
)
|
||||
event_task = asyncio.create_task(anext(event_stream))
|
||||
await websocket.send_json(
|
||||
{"type": "subscribed", "dialog_ids": [str(value) for value in ids]}
|
||||
{
|
||||
"type": "subscribed",
|
||||
"dialog_ids": [str(value) for value in ids],
|
||||
"notifications": notifications,
|
||||
}
|
||||
)
|
||||
except (AuthError, DomainError, ValueError):
|
||||
await websocket.close(code=4401)
|
||||
|
||||
Reference in New Issue
Block a user