新增了完整的Confluence集成插件,包含以下核心功能: 1. 基础认证与配置管理,支持API Token和OAuth2两种认证方式 2. 评论去重、权限控制与提及解析 3. 知识库检索与页面内容处理 4. 评论收发、编辑删除与流式回复支持 5. 附件与页面标签管理 6. 内容属性存储与AI元数据管理 7. Webhook事件接收与处理 8. 完整的插件配置与状态检查
107 lines
3.7 KiB
Python
107 lines
3.7 KiB
Python
import logging
|
|
from pathlib import Path
|
|
|
|
from yuxi.channel.extensions.confluence.gateway import ConfluenceGateway
|
|
from yuxi.channel.extensions.confluence.types import OutboundResult
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ConfluenceAttachmentManager:
|
|
def __init__(self, gateway: ConfluenceGateway):
|
|
self._gateway = gateway
|
|
|
|
async def list_attachments(
|
|
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}/attachments",
|
|
)
|
|
return result.get("results", [])
|
|
except Exception as e:
|
|
logger.error("Failed to list attachments for page %s: %s", page_id, e)
|
|
return []
|
|
|
|
async def get_attachment(
|
|
self, attachment_id: str, account_id: str = "default",
|
|
) -> dict | None:
|
|
client = self._gateway.get_client(account_id)
|
|
if client is None:
|
|
return None
|
|
try:
|
|
return await client._request(
|
|
"GET", f"/wiki/api/v2/attachments/{attachment_id}",
|
|
)
|
|
except Exception as e:
|
|
logger.error("Failed to get attachment %s: %s", attachment_id, e)
|
|
return None
|
|
|
|
async def upload_attachment(
|
|
self,
|
|
page_id: str,
|
|
file_path: str,
|
|
filename: str | None = None,
|
|
account_id: str = "default",
|
|
) -> OutboundResult:
|
|
client = self._gateway.get_client(account_id)
|
|
if client is None:
|
|
return OutboundResult(success=False, error="Client not found")
|
|
|
|
path = Path(file_path)
|
|
if not path.exists():
|
|
return OutboundResult(success=False, error=f"File not found: {file_path}")
|
|
|
|
fname = filename or path.name
|
|
try:
|
|
result = await client._request(
|
|
"POST",
|
|
f"/wiki/api/v2/pages/{page_id}/attachments",
|
|
files={"file": (fname, path.read_bytes(), "application/octet-stream")},
|
|
)
|
|
return OutboundResult(success=True, comment_id=result.get("id", ""))
|
|
except Exception as e:
|
|
logger.error("Failed to upload attachment to page %s: %s", page_id, e)
|
|
return OutboundResult(success=False, error=str(e))
|
|
|
|
async def download_attachment(
|
|
self,
|
|
page_id: str,
|
|
filename: str,
|
|
save_path: str,
|
|
account_id: str = "default",
|
|
) -> str | None:
|
|
client = self._gateway.get_client(account_id)
|
|
if client is None:
|
|
return None
|
|
|
|
try:
|
|
url = f"/download/attachments/{page_id}/{filename}"
|
|
if client._http is None:
|
|
raise RuntimeError("Client not initialized")
|
|
resp = await client._http.get(url)
|
|
resp.raise_for_status()
|
|
Path(save_path).write_bytes(resp.content)
|
|
return save_path
|
|
except Exception as e:
|
|
logger.error("Failed to download attachment %s: %s", filename, e)
|
|
return None
|
|
|
|
async def delete_attachment(
|
|
self, attachment_id: str, account_id: str = "default",
|
|
) -> OutboundResult:
|
|
client = self._gateway.get_client(account_id)
|
|
if client is None:
|
|
return OutboundResult(success=False, error="Client not found")
|
|
try:
|
|
await client._request(
|
|
"DELETE", f"/wiki/api/v2/attachments/{attachment_id}",
|
|
)
|
|
return OutboundResult(success=True, comment_id=attachment_id)
|
|
except Exception as e:
|
|
logger.error("Failed to delete attachment %s: %s", attachment_id, e)
|
|
return OutboundResult(success=False, error=str(e))
|