import time from typing import Optional, Union from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import Session from sqlalchemy import and_, or_, select from app.db.base import DbOper from app.db.models.message import Message from app.schemas.notification import NotificationChannel from app.schemas.message import MessageType class MessageOper(DbOper): """ 消息数据管理 """ def __init__(self, db: Optional[Union[Session, AsyncSession]] = None): super().__init__(db) def add(self, channel: Optional[NotificationChannel] = None, source: Optional[str] = None, mtype: Optional[MessageType] = None, title: Optional[str] = None, text: Optional[str] = None, image: Optional[str] = None, link: Optional[str] = None, userid: Optional[str] = None, action: Optional[int] = 1, note: Optional[Union[list, dict]] = None, **kwargs) -> dict: """ 新增消息 :param channel: 消息渠道 :param source: 来源 :param mtype: 消息类型 :param title: 标题 :param text: 文本内容 :param image: 图片 :param link: 链接 :param userid: 用户ID :param action: 消息方向:0-接收息,1-发送消息 :param note: 附件json """ kwargs.update({ "channel": channel.value if channel else '', "source": source, "mtype": mtype.value if mtype else '', "title": title, "text": text, "image": image, "link": link, "userid": userid, "action": action, "reg_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), "note": note or {} }) # 从kwargs中去掉Message中没有的字段 for k in list(kwargs.keys()): if k not in Message.__table__.columns.keys(): # noqa kwargs.pop(k) message = Message(**kwargs) return self._execute_sync_write(message.create_and_to_dict) async def async_add(self, channel: Optional[NotificationChannel] = None, source: Optional[str] = None, mtype: Optional[MessageType] = None, title: Optional[str] = None, text: Optional[str] = None, image: Optional[str] = None, link: Optional[str] = None, userid: Optional[str] = None, action: Optional[int] = 1, note: Optional[Union[list, dict]] = None, **kwargs) -> Message: """ 异步新增消息 """ kwargs.update({ "channel": channel.value if channel else '', "source": source, "mtype": mtype.value if mtype else '', "title": title, "text": text, "image": image, "link": link, "userid": userid, "action": action, "reg_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), "note": note or {} }) # 从kwargs中去掉Message中没有的字段 for k in list(kwargs.keys()): if k not in Message.__table__.columns.keys(): # noqa kwargs.pop(k) return await self._stage_async_create(Message(**kwargs)) def list_by_page(self, page: int = 1, count: int = 30) -> list[Message]: """ 分页获取消息记录。 """ return self._execute_sync_query( lambda session: list(session.execute( select(Message) .order_by(Message.reg_time.desc(), Message.id.desc()) .offset((page - 1) * count) .limit(count) ).scalars().all()) ) def exists_by_source(self, source: str) -> bool: """ 判断指定来源标识的消息记录是否存在。 :param source: 消息来源唯一标识 :return: 是否存在匹配记录 """ return self._execute_sync_query( lambda session: session.execute( select(Message.id).where(Message.source == source).limit(1) ).scalars().first() is not None ) async def async_list_by_page( self, page: int = 1, count: int = 30 ) -> list[Message]: """ 分页获取消息记录。 """ async def query(session: AsyncSession) -> list[Message]: """在调用方异步会话中执行消息分页查询。""" result = await session.execute( select(Message) .order_by(Message.reg_time.desc(), Message.id.desc()) .offset((page - 1) * count) .limit(count) ) return list(result.scalars().all()) return await self._execute_async_query(query) async def async_list_sent_by_page( self, page: int = 1, count: int = 30, all_clear_before: Optional[str] = None, system_clear_before: Optional[str] = None, media_clear_before: Optional[str] = None, ) -> list[Message]: """ 分页获取系统发送的通知消息。 """ async def query(session: AsyncSession) -> list[Message]: """在调用方异步会话中执行通知消息分页查询。""" statement = select(Message).where(Message.action == 1) if all_clear_before: statement = statement.where(Message.reg_time > all_clear_before) if system_clear_before: statement = statement.where(or_( and_(Message.image.isnot(None), Message.image != ""), Message.reg_time > system_clear_before, )) if media_clear_before: statement = statement.where(or_( Message.image.is_(None), Message.image == "", Message.reg_time > media_clear_before, )) result = await session.execute( statement .order_by(Message.reg_time.desc(), Message.id.desc()) .offset((page - 1) * count) .limit(count) ) return list(result.scalars().all()) return await self._execute_async_query(query)