- 新增通知系统 (notifications 表、服务、API) - 新增飞书定时任务结果推送 (webhook + 应用消息) - 新增飞书应用消息发送服务 (feishu_app_service) - 新增飞书 WebSocket 长连接事件监听 (苹果应用) - 新增飞书账号绑定/解绑 API - 新增橙子飞书机器人 (独立 WS 连接,固定路由到橙子助手 Agent) - 执行记录添加 schedule_id,用户添加飞书绑定字段 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
129 lines
3.4 KiB
Python
129 lines
3.4 KiB
Python
"""通知服务 — 创建与查询系统通知"""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import datetime
|
|
from typing import List, Optional
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.models.notification import Notification
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def create_notification(
|
|
db: Session,
|
|
user_id: str,
|
|
title: str,
|
|
content: Optional[str] = None,
|
|
category: str = "system",
|
|
ref_type: Optional[str] = None,
|
|
ref_id: Optional[str] = None,
|
|
) -> Notification:
|
|
"""创建一条通知。
|
|
|
|
Args:
|
|
db: 数据库会话
|
|
user_id: 接收用户 ID
|
|
title: 通知标题
|
|
content: 通知正文(可选)
|
|
category: 分类,如 schedule / alert / system
|
|
ref_type: 关联对象类型
|
|
ref_id: 关联对象 ID
|
|
|
|
Returns:
|
|
创建的 Notification ORM 对象
|
|
"""
|
|
notification = Notification(
|
|
user_id=user_id,
|
|
title=title,
|
|
content=content,
|
|
category=category,
|
|
ref_type=ref_type,
|
|
ref_id=ref_id,
|
|
)
|
|
db.add(notification)
|
|
db.flush()
|
|
logger.info("通知已创建: user=%s title=%s category=%s", user_id, title, category)
|
|
return notification
|
|
|
|
|
|
def get_user_notifications(
|
|
db: Session,
|
|
user_id: str,
|
|
unread_only: bool = False,
|
|
category: Optional[str] = None,
|
|
limit: int = 50,
|
|
offset: int = 0,
|
|
) -> List[Notification]:
|
|
"""获取用户的通知列表(按创建时间倒序)。
|
|
|
|
Args:
|
|
db: 数据库会话
|
|
user_id: 用户 ID
|
|
unread_only: 仅未读
|
|
category: 按分类过滤
|
|
limit: 分页大小
|
|
offset: 分页偏移
|
|
|
|
Returns:
|
|
通知列表
|
|
"""
|
|
query = db.query(Notification).filter(Notification.user_id == user_id)
|
|
|
|
if unread_only:
|
|
query = query.filter(Notification.is_read == False) # noqa: E712
|
|
if category:
|
|
query = query.filter(Notification.category == category)
|
|
|
|
return query.order_by(Notification.created_at.desc()).offset(offset).limit(limit).all()
|
|
|
|
|
|
def get_unread_count(db: Session, user_id: str) -> int:
|
|
"""获取用户未读通知数。"""
|
|
return (
|
|
db.query(Notification)
|
|
.filter(Notification.user_id == user_id, Notification.is_read == False) # noqa: E712
|
|
.count()
|
|
)
|
|
|
|
|
|
def mark_as_read(db: Session, notification_id: str, user_id: str) -> Optional[Notification]:
|
|
"""将指定通知标记为已读。"""
|
|
notification = (
|
|
db.query(Notification)
|
|
.filter(Notification.id == notification_id, Notification.user_id == user_id)
|
|
.first()
|
|
)
|
|
if not notification:
|
|
return None
|
|
notification.is_read = True
|
|
db.flush()
|
|
return notification
|
|
|
|
|
|
def mark_all_as_read(db: Session, user_id: str) -> int:
|
|
"""将用户所有通知标记为已读。返回更新的条数。"""
|
|
count = (
|
|
db.query(Notification)
|
|
.filter(Notification.user_id == user_id, Notification.is_read == False) # noqa: E712
|
|
.update({"is_read": True})
|
|
)
|
|
db.flush()
|
|
return count
|
|
|
|
|
|
def delete_notification(db: Session, notification_id: str, user_id: str) -> bool:
|
|
"""删除一条通知。"""
|
|
notification = (
|
|
db.query(Notification)
|
|
.filter(Notification.id == notification_id, Notification.user_id == user_id)
|
|
.first()
|
|
)
|
|
if not notification:
|
|
return False
|
|
db.delete(notification)
|
|
db.flush()
|
|
return True
|