ForcePilot/backend/package/yuxi/channel/extensions/confluence/content_properties.py
Kris f943c31ce4 feat(confluence): 新增Confluence渠道插件完整实现
新增了完整的Confluence集成插件,包含以下核心功能:
1.  基础认证与配置管理,支持API Token和OAuth2两种认证方式
2.  评论去重、权限控制与提及解析
3.  知识库检索与页面内容处理
4.  评论收发、编辑删除与流式回复支持
5.  附件与页面标签管理
6.  内容属性存储与AI元数据管理
7.  Webhook事件接收与处理
8.  完整的插件配置与状态检查
2026-05-21 10:43:42 +08:00

92 lines
3.3 KiB
Python

import logging
from datetime import datetime, UTC
from yuxi.channel.extensions.confluence.gateway import ConfluenceGateway
logger = logging.getLogger(__name__)
class ContentPropertyStore:
NAMESPACE = "forcepilot_ai"
def __init__(self, gateway: ConfluenceGateway):
self._gateway = gateway
async def _get_properties(self, page_id: str, account_id: str = "default") -> list[dict]:
client = self._gateway.get_client(account_id)
if client is None:
return []
try:
result = await client._request("GET", f"/wiki/api/v2/pages/{page_id}/properties")
return result.get("results", [])
except Exception as e:
logger.error("Failed to get properties for page %s: %s", page_id, e)
return []
async def _set(
self, page_id: str, key: str, value: dict, account_id: str = "default",
) -> dict | None:
client = self._gateway.get_client(account_id)
if client is None:
return None
try:
return await client._request(
"POST",
f"/wiki/api/v2/pages/{page_id}/properties",
json={"key": key, "value": value},
)
except Exception as e:
logger.error("Failed to set property '%s' for page %s: %s", key, page_id, e)
return None
async def _delete(
self, page_id: str, property_id: str, account_id: str = "default",
) -> bool:
client = self._gateway.get_client(account_id)
if client is None:
return False
try:
await client._request(
"DELETE", f"/wiki/api/v2/pages/{page_id}/properties/{property_id}",
)
return True
except Exception as e:
logger.error("Failed to delete property %s from page %s: %s", property_id, page_id, e)
return False
async def mark_processed(self, page_id: str, processor: str, account_id: str = "default") -> dict | None:
return await self._set(
page_id,
f"{self.NAMESPACE}.{processor}.processed_at",
{"timestamp": datetime.now(tz=UTC).isoformat()},
account_id,
)
async def store_summary(self, page_id: str, summary: str, account_id: str = "default") -> dict | None:
return await self._set(
page_id,
f"{self.NAMESPACE}.summary",
{"text": summary},
account_id,
)
async def get_ai_metadata(self, page_id: str, account_id: str = "default") -> dict:
properties = await self._get_properties(page_id, account_id)
metadata = {}
for prop in properties:
key = prop.get("key", "")
if key.startswith(self.NAMESPACE):
metadata[key] = prop.get("value", {})
return metadata
async def clear_ai_metadata(self, page_id: str, account_id: str = "default") -> bool:
properties = await self._get_properties(page_id, account_id)
success = True
for prop in properties:
key = prop.get("key", "")
prop_id = prop.get("id")
if key.startswith(self.NAMESPACE) and prop_id:
if not await self._delete(page_id, prop_id, account_id):
success = False
return success