qwen_agent/skills/developing/mineru/scripts/sinks/confluence.py
2026-06-05 14:35:17 +08:00

67 lines
2.1 KiB
Python

"""Confluence sink: create a page from the parsed Markdown via the Cloud REST API.
Confluence Cloud ingests content as *storage-format* HTML. Delivery converts the
Markdown to HTML and creates a page with the v2 REST API
(``POST /wiki/api/v2/pages``) using Basic auth (email + API token).
Local images are not attached — Confluence storage HTML references attachments by
filename, which would require a separate upload step.
"""
from __future__ import annotations
import base64
from . import _http, _md
from .base import ParsedDoc, Sink, SinkError, SinkResult, register
@register
class ConfluenceSink(Sink):
name = "confluence"
requires = (
"CONFLUENCE_BASE_URL",
"CONFLUENCE_EMAIL",
"CONFLUENCE_API_TOKEN",
"CONFLUENCE_SPACE_ID",
)
label = "Confluence Cloud page (storage HTML)"
def deliver(self, doc: ParsedDoc) -> SinkResult:
base = self.env("CONFLUENCE_BASE_URL").rstrip("/")
email = self.env("CONFLUENCE_EMAIL")
token = self.env("CONFLUENCE_API_TOKEN")
space = self.env("CONFLUENCE_SPACE_ID")
auth = base64.b64encode(f"{email}:{token}".encode("utf-8")).decode("ascii")
headers = {
"Authorization": f"Basic {auth}",
"Content-Type": "application/json",
}
html = _md.md_to_html(doc.markdown)
status, parsed = _http.request_json(
"POST",
f"{base}/wiki/api/v2/pages",
headers=headers,
payload={
"spaceId": space,
"status": "current",
"title": doc.title,
"body": {"representation": "storage", "value": html},
},
)
if status >= 400:
raise SinkError(
parsed.get("title")
or parsed.get("message")
or f"Confluence HTTP {status}"
)
webui = (parsed.get("_links") or {}).get("webui")
url = base + webui if webui else None
return SinkResult(
sink=self.name, ok=True, url=url,
detail="converted Markdown->storage HTML (local images not attached)",
)