Files
aiagent/backend/app/api/notifications.py
renjianbo 7ee80c74b2 feat: 集成飞书通知和机器人对话系统
- 新增通知系统 (notifications 表、服务、API)
- 新增飞书定时任务结果推送 (webhook + 应用消息)
- 新增飞书应用消息发送服务 (feishu_app_service)
- 新增飞书 WebSocket 长连接事件监听 (苹果应用)
- 新增飞书账号绑定/解绑 API
- 新增橙子飞书机器人 (独立 WS 连接,固定路由到橙子助手 Agent)
- 执行记录添加 schedule_id,用户添加飞书绑定字段

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:17:49 +08:00

116 lines
3.4 KiB
Python

"""通知 API — 列表、已读、删除"""
from __future__ import annotations
import logging
from datetime import datetime
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy.orm import Session
from app.api.auth import get_current_user
from app.core.database import get_db
from app.models.user import User
from app.services.notification_service import (
delete_notification,
get_unread_count,
get_user_notifications,
mark_all_as_read,
mark_as_read,
)
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v1/notifications", tags=["notifications"])
# ─── Pydantic Schemas ──────────────────────────────────────────────
class NotificationResponse(BaseModel):
id: str
user_id: str
title: str
content: Optional[str] = None
category: str
ref_type: Optional[str] = None
ref_id: Optional[str] = None
is_read: bool
created_at: datetime
class Config:
from_attributes = True
class UnreadCountResponse(BaseModel):
count: int
# ─── API Endpoints ─────────────────────────────────────────────────
@router.get("", response_model=List[NotificationResponse])
async def list_notifications(
unread_only: bool = Query(False, description="仅未读"),
category: Optional[str] = Query(None, description="按分类过滤"),
limit: int = Query(50, ge=1, le=200),
offset: int = Query(0, ge=0),
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取当前用户的通知列表。"""
return get_user_notifications(
db,
user_id=current_user.id,
unread_only=unread_only,
category=category,
limit=limit,
offset=offset,
)
@router.get("/unread-count", response_model=UnreadCountResponse)
async def unread_count(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""获取当前用户的未读通知数。"""
count = get_unread_count(db, current_user.id)
return {"count": count}
@router.put("/{notification_id}/read")
async def read_notification(
notification_id: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""将一条通知标记为已读。"""
result = mark_as_read(db, notification_id, current_user.id)
if not result:
raise HTTPException(status_code=404, detail="通知不存在")
return {"message": "已标记为已读"}
@router.put("/read-all")
async def read_all_notifications(
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""将所有通知标记为已读。"""
count = mark_all_as_read(db, current_user.id)
return {"message": f"已将 {count} 条通知标记为已读"}
@router.delete("/{notification_id}")
async def remove_notification(
notification_id: str,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db),
):
"""删除一条通知。"""
ok = delete_notification(db, notification_id, current_user.id)
if not ok:
raise HTTPException(status_code=404, detail="通知不存在")
return {"message": "通知已删除"}