mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-01 13:37:24 +08:00
refactor(schemas): 统一 message/notification 命名边界,旧名收敛至兼容映射表
- notification 域:渠道能力(MessageChannel→NotificationChannel、ChannelCapability* 迁入 notification.py) - message 域:消息收发(Notification→Message、NotificationType→MessageType、CommingMessage→IncomingMessage、NotificationHistoryItem→MessageHistoryItem、NotificationClear*→MessageClear*) - Agent 工具契约:send_notification_message→send_message、notification_callback→message_callback - 源码不保留旧名物理别名,旧导入经 app/runtime/compat/manifest.py SYMBOL_ALIASES 惰性解析 - API 路径与持久化键冻结不变,前端零改动 - 新增兼容守护测试与 docs/rules/07 命名边界规范
This commit is contained in:
@@ -5,12 +5,12 @@ from app.application.messaging.agent import register_channel_admin_resolver, res
|
||||
from app.runtime.log import logger
|
||||
from app.modules import _ModuleBase, _MessageBase
|
||||
from app.modules.feishu.feishu import Feishu
|
||||
from app.schemas import CommingMessage, MessageChannel, MessageResponse, Notification
|
||||
from app.schemas import IncomingMessage, NotificationChannel, MessageResponse, Message
|
||||
from app.schemas.types import ModuleType
|
||||
|
||||
|
||||
register_channel_admin_resolver(
|
||||
MessageChannel.Feishu,
|
||||
NotificationChannel.Feishu,
|
||||
lambda config: resolve_config_principal_ids(
|
||||
config, "FEISHU_ADMINS", "FEISHU_OPEN_ID"
|
||||
),
|
||||
@@ -20,7 +20,7 @@ register_channel_admin_resolver(
|
||||
class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
def init_module(self) -> None:
|
||||
super().init_service(service_name=Feishu.__name__.lower(), service_type=Feishu)
|
||||
self._channel = MessageChannel.Feishu
|
||||
self._channel = NotificationChannel.Feishu
|
||||
|
||||
@staticmethod
|
||||
def get_name() -> str:
|
||||
@@ -31,8 +31,8 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
return ModuleType.Notification
|
||||
|
||||
@staticmethod
|
||||
def get_subtype() -> MessageChannel:
|
||||
return MessageChannel.Feishu
|
||||
def get_subtype() -> NotificationChannel:
|
||||
return NotificationChannel.Feishu
|
||||
|
||||
@staticmethod
|
||||
def get_priority() -> int:
|
||||
@@ -61,7 +61,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
|
||||
@staticmethod
|
||||
def _resolve_message_target(
|
||||
message: Notification,
|
||||
message: Message,
|
||||
) -> Tuple[Optional[str], Optional[str], Optional[str]]:
|
||||
"""解析发送目标:交互式回复优先回到原会话(群聊@回复必须回原群),其次 open_id,最后回退 user_id 或 chat_id。"""
|
||||
userid = str(message.userid).strip() if message.userid else None
|
||||
@@ -94,7 +94,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
|
||||
def message_parser(
|
||||
self, source: str, body: Any, form: Any, args: Any
|
||||
) -> Optional[CommingMessage]:
|
||||
) -> Optional[IncomingMessage]:
|
||||
client_config = self.get_config(source)
|
||||
if not client_config:
|
||||
return None
|
||||
@@ -103,7 +103,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
return None
|
||||
return client.parse_message(body)
|
||||
|
||||
def post_message(self, message: Notification, **kwargs) -> None:
|
||||
def post_message(self, message: Message, **kwargs) -> None:
|
||||
for conf in self.get_configs().values():
|
||||
if not self.check_message(message, conf.name):
|
||||
continue
|
||||
@@ -156,7 +156,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
original_message_id=str(message.original_message_id) if message.original_message_id else None,
|
||||
)
|
||||
|
||||
def post_medias_message(self, message: Notification, medias: List[MediaInfo]) -> None:
|
||||
def post_medias_message(self, message: Message, medias: List[MediaInfo]) -> None:
|
||||
for conf in self.get_configs().values():
|
||||
if not self.check_message(message, conf.name):
|
||||
continue
|
||||
@@ -171,7 +171,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
receive_id_type=receive_id_type,
|
||||
)
|
||||
|
||||
def post_torrents_message(self, message: Notification, torrents: List[Context]) -> None:
|
||||
def post_torrents_message(self, message: Message, torrents: List[Context]) -> None:
|
||||
for conf in self.get_configs().values():
|
||||
if not self.check_message(message, conf.name):
|
||||
continue
|
||||
@@ -188,7 +188,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
|
||||
def edit_message(
|
||||
self,
|
||||
channel: MessageChannel,
|
||||
channel: NotificationChannel,
|
||||
source: str,
|
||||
message_id: Union[str, int],
|
||||
chat_id: Union[str, int],
|
||||
@@ -214,7 +214,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
return True
|
||||
return False
|
||||
|
||||
def send_direct_message(self, message: Notification) -> Optional[MessageResponse]:
|
||||
def send_direct_message(self, message: Message) -> Optional[MessageResponse]:
|
||||
for conf in self.get_configs().values():
|
||||
if not self.check_message(message, conf.name):
|
||||
continue
|
||||
@@ -285,7 +285,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
return MessageResponse(
|
||||
message_id=result.get("message_id"),
|
||||
chat_id=result.get("chat_id"),
|
||||
channel=MessageChannel.Feishu,
|
||||
channel=NotificationChannel.Feishu,
|
||||
source=conf.name,
|
||||
metadata=result.get("metadata"),
|
||||
success=True,
|
||||
@@ -395,7 +395,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
|
||||
def mark_message_processing_started(
|
||||
self,
|
||||
channel: MessageChannel,
|
||||
channel: NotificationChannel,
|
||||
source: str,
|
||||
userid: Optional[Union[str, int]] = None,
|
||||
message_id: Optional[Union[str, int]] = None,
|
||||
@@ -431,7 +431,7 @@ class FeishuModule(_ModuleBase, _MessageBase[Feishu]):
|
||||
|
||||
def mark_message_processing_finished(
|
||||
self,
|
||||
channel: MessageChannel,
|
||||
channel: NotificationChannel,
|
||||
source: str,
|
||||
userid: Optional[Union[str, int]] = None,
|
||||
message_id: Optional[Union[str, int]] = None,
|
||||
|
||||
@@ -55,8 +55,8 @@ from app.domain.context import Context, MediaInfo
|
||||
from app.db.oper.user import UserOper
|
||||
from app.application.messaging.agent import matches_channel_admin
|
||||
from app.runtime.log import logger
|
||||
from app.schemas import CommingMessage, Notification
|
||||
from app.schemas.types import MessageChannel, NotificationType
|
||||
from app.schemas import IncomingMessage, Message
|
||||
from app.schemas.types import NotificationChannel, MessageType
|
||||
from app.adapters.network.http import RequestUtils
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ class Feishu:
|
||||
if not self._admins:
|
||||
return False
|
||||
return not matches_channel_admin(
|
||||
MessageChannel.Feishu,
|
||||
NotificationChannel.Feishu,
|
||||
{
|
||||
"FEISHU_ADMINS": ",".join(self._admins),
|
||||
"FEISHU_OPEN_ID": self._default_open_id,
|
||||
@@ -299,8 +299,8 @@ class Feishu:
|
||||
|
||||
@staticmethod
|
||||
def _parse_message_content(message) -> Tuple[
|
||||
str, Optional[List[CommingMessage.MessageImage]], Optional[List[str]], Optional[
|
||||
List[CommingMessage.MessageAttachment]]]:
|
||||
str, Optional[List[IncomingMessage.MessageImage]], Optional[List[str]], Optional[
|
||||
List[IncomingMessage.MessageAttachment]]]:
|
||||
"""从飞书事件消息体中提取文本、图片、音频和文件引用。"""
|
||||
raw_content = getattr(message, "content", None)
|
||||
if not raw_content:
|
||||
@@ -323,9 +323,9 @@ class Feishu:
|
||||
image_key = str(content.get("image_key") or "").strip()
|
||||
if image_key:
|
||||
if message_id:
|
||||
images = [CommingMessage.MessageImage(ref=f"feishu://image/{message_id}/{image_key}")]
|
||||
images = [IncomingMessage.MessageImage(ref=f"feishu://image/{message_id}/{image_key}")]
|
||||
else:
|
||||
images = [CommingMessage.MessageImage(ref=f"feishu://image/{image_key}")]
|
||||
images = [IncomingMessage.MessageImage(ref=f"feishu://image/{image_key}")]
|
||||
elif message_type in {"audio", "media", "file"}:
|
||||
file_key = str(content.get("file_key") or "").strip()
|
||||
file_name = str(content.get("file_name") or "").strip() or None
|
||||
@@ -336,7 +336,7 @@ class Feishu:
|
||||
else:
|
||||
resource_path = f"{message_id}/{file_key}" if message_id else file_key
|
||||
files = [
|
||||
CommingMessage.MessageAttachment(
|
||||
IncomingMessage.MessageAttachment(
|
||||
ref=f"feishu://file/{resource_path}/{file_name or 'attachment'}",
|
||||
name=file_name,
|
||||
)
|
||||
@@ -397,7 +397,7 @@ class Feishu:
|
||||
def _parse_post_message_content(
|
||||
content: dict,
|
||||
message_id: Optional[str] = None,
|
||||
) -> Tuple[str, Optional[List[CommingMessage.MessageImage]]]:
|
||||
) -> Tuple[str, Optional[List[IncomingMessage.MessageImage]]]:
|
||||
"""从飞书富文本消息中提取可转发的文本和图片引用。"""
|
||||
post_body = Feishu._resolve_post_message_body(content)
|
||||
if not post_body:
|
||||
@@ -421,9 +421,9 @@ class Feishu:
|
||||
image_key = str(element.get("image_key") or "").strip()
|
||||
if element.get("tag") == "img" and image_key:
|
||||
if message_id:
|
||||
images.append(CommingMessage.MessageImage(ref=f"feishu://image/{message_id}/{image_key}"))
|
||||
images.append(IncomingMessage.MessageImage(ref=f"feishu://image/{message_id}/{image_key}"))
|
||||
else:
|
||||
images.append(CommingMessage.MessageImage(ref=f"feishu://image/{image_key}"))
|
||||
images.append(IncomingMessage.MessageImage(ref=f"feishu://image/{image_key}"))
|
||||
element_text = Feishu._parse_post_element_text(element)
|
||||
if element_text:
|
||||
row_parts.append(element_text)
|
||||
@@ -648,7 +648,7 @@ class Feishu:
|
||||
if self._ws_thread and self._ws_thread.is_alive():
|
||||
self._ws_thread.join(timeout=5)
|
||||
|
||||
def parse_message(self, body: Any) -> Optional[CommingMessage]:
|
||||
def parse_message(self, body: Any) -> Optional[IncomingMessage]:
|
||||
"""解析飞书转发到消息入口的 JSON 报文。"""
|
||||
try:
|
||||
message = json.loads(body) if isinstance(body, (str, bytes, bytearray)) else body
|
||||
@@ -685,13 +685,13 @@ class Feishu:
|
||||
receive_id_type="open_id" if open_id else "user_id",
|
||||
)
|
||||
return None
|
||||
return CommingMessage(
|
||||
channel=MessageChannel.Feishu,
|
||||
return IncomingMessage(
|
||||
channel=NotificationChannel.Feishu,
|
||||
source=self._name,
|
||||
userid=userid,
|
||||
username=username,
|
||||
is_channel_admin=matches_channel_admin(
|
||||
MessageChannel.Feishu,
|
||||
NotificationChannel.Feishu,
|
||||
{
|
||||
"FEISHU_ADMINS": ",".join(self._admins),
|
||||
"FEISHU_OPEN_ID": self._default_open_id,
|
||||
@@ -707,7 +707,7 @@ class Feishu:
|
||||
)
|
||||
|
||||
text = (message.get("text") or "").strip()
|
||||
images = CommingMessage.MessageImage.normalize_list(message.get("images"))
|
||||
images = IncomingMessage.MessageImage.normalize_list(message.get("images"))
|
||||
audio_refs = None
|
||||
if isinstance(message.get("audio_refs"), list):
|
||||
audio_refs = [str(item).strip() for item in message.get("audio_refs") if str(item).strip()] or None
|
||||
@@ -716,7 +716,7 @@ class Feishu:
|
||||
normalized_files = []
|
||||
for item in message.get("files"):
|
||||
if isinstance(item, dict) and item.get("ref"):
|
||||
normalized_files.append(CommingMessage.MessageAttachment(**item))
|
||||
normalized_files.append(IncomingMessage.MessageAttachment(**item))
|
||||
files = normalized_files or None
|
||||
|
||||
if not text and not images and not audio_refs and not files:
|
||||
@@ -731,13 +731,13 @@ class Feishu:
|
||||
)
|
||||
return None
|
||||
|
||||
return CommingMessage(
|
||||
channel=MessageChannel.Feishu,
|
||||
return IncomingMessage(
|
||||
channel=NotificationChannel.Feishu,
|
||||
source=self._name,
|
||||
userid=userid,
|
||||
username=username,
|
||||
is_channel_admin=matches_channel_admin(
|
||||
MessageChannel.Feishu,
|
||||
NotificationChannel.Feishu,
|
||||
{
|
||||
"FEISHU_ADMINS": ",".join(self._admins),
|
||||
"FEISHU_OPEN_ID": self._default_open_id,
|
||||
@@ -1739,7 +1739,7 @@ class Feishu:
|
||||
|
||||
def send_notification(
|
||||
self,
|
||||
message: Notification,
|
||||
message: Message,
|
||||
userid: Optional[str] = None,
|
||||
chat_id: Optional[str] = None,
|
||||
receive_id_type: Optional[str] = None,
|
||||
@@ -1747,7 +1747,7 @@ class Feishu:
|
||||
) -> Optional[dict]:
|
||||
"""发送通知消息,优先使用交互卡片承载按钮。"""
|
||||
is_streaming_agent_text = (
|
||||
message.mtype == NotificationType.Agent
|
||||
message.mtype == MessageType.Agent
|
||||
and not message.buttons
|
||||
and not message.link
|
||||
)
|
||||
@@ -1942,7 +1942,7 @@ class Feishu:
|
||||
|
||||
def send_medias_message(
|
||||
self,
|
||||
message: Notification,
|
||||
message: Message,
|
||||
medias: List[MediaInfo],
|
||||
userid: Optional[str] = None,
|
||||
chat_id: Optional[str] = None,
|
||||
@@ -1956,7 +1956,7 @@ class Feishu:
|
||||
image = media.get_message_image()
|
||||
title = getattr(media, "title_year", None) or getattr(media, "title", None) or "未知媒体"
|
||||
lines.append(f"{index}. {title}")
|
||||
proxy_message = Notification(
|
||||
proxy_message = Message(
|
||||
title=message.title,
|
||||
text="\n".join(lines),
|
||||
image=image,
|
||||
@@ -1974,7 +1974,7 @@ class Feishu:
|
||||
|
||||
def send_torrents_message(
|
||||
self,
|
||||
message: Notification,
|
||||
message: Message,
|
||||
torrents: List[Context],
|
||||
userid: Optional[str] = None,
|
||||
chat_id: Optional[str] = None,
|
||||
@@ -1986,7 +1986,7 @@ class Feishu:
|
||||
torrent_info = getattr(torrent, "torrent_info", None)
|
||||
title = getattr(torrent_info, "title", None) or getattr(torrent_info, "site_name", None) or "未知种子"
|
||||
lines.append(f"{index}. {title}")
|
||||
proxy_message = Notification(
|
||||
proxy_message = Message(
|
||||
title=message.title,
|
||||
text="\n".join(lines),
|
||||
link=message.link,
|
||||
|
||||
Reference in New Issue
Block a user