Files
dataelement--bisheng/scripts/check_export_dependencies.sh
dolphin c7d6d25d18 feat: F028 backend — workstation conversation export & import-to-knowledge
Backend implementation for F028 conversation export feature
(spec features/v2.6.0/028-conversation-export-import/).

What ships:
- SDD docs: spec.md + tasks.md (both reviewed); release-contract +
  v2.6.0 README index updated
- DTOs in workstation/domain/schemas/conversation_export.py
- Errcodes 12060-12069 in common/errcode/workstation.py
- ConversationExportService: load + turn build, 4 renderers
  (md/txt + pypandoc-docx + LibreOffice-pdf), image preprocessing
  with httpx + data: URL inline decode, filename resolver,
  import-to-knowledge with dedup rename + race-retry
- 3 endpoints: POST /api/v1/chat/messages/export,
  POST /api/v1/chat/messages/import-to-knowledge,
  GET /api/v1/knowledge/space/uploadable
- ChatMessageDao.aget_messages_by_ids (anti-IDOR (user_id, chat_id)
  compound predicate)
- KnowledgeSpaceService.list_uploadable_spaces (OpenFGA can_edit list +
  creator-owned union; admin path → tenant-scoped scan)
- libreoffice_converter: add convert_docx_to_pdf + timeout param
- 79 backend tests passing (load+turn 17, renderers 23, import 15,
  uploadable service 9, export+import API 12, uploadable API 3)
2026-05-31 11:33:03 +08:00

133 lines
3.7 KiB
Bash
Executable File

#!/usr/bin/env bash
# F028 — Conversation export dependency smoke test.
# Run inside the bisheng-backend container:
# docker exec -it bisheng-backend bash scripts/check_export_dependencies.sh
#
# Validates pandoc / LibreOffice (soffice) / Chinese fonts and runs an
# end-to-end md -> docx -> pdf round-trip to make sure the rendering toolchain
# is actually wired up. Exits non-zero on any missing or broken piece.
set -u
GREEN="\033[0;32m"
RED="\033[0;31m"
YELLOW="\033[1;33m"
NC="\033[0m"
pass() { echo -e "${GREEN}[PASS]${NC} $*"; }
fail() { echo -e "${RED}[FAIL]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
EXIT_CODE=0
echo "=== F028 export dependencies smoke test ==="
echo
# --- pandoc ---
if command -v pandoc >/dev/null 2>&1; then
PANDOC_VERSION=$(pandoc --version | head -1)
pass "pandoc available: ${PANDOC_VERSION}"
else
fail "pandoc NOT found (expected /usr/bin/pandoc, installed by base.Dockerfile line 22-27)"
EXIT_CODE=1
fi
# --- LibreOffice (soffice) ---
if command -v soffice >/dev/null 2>&1; then
SOFFICE_VERSION=$(soffice --version 2>&1 | head -1)
pass "soffice available: ${SOFFICE_VERSION}"
elif command -v libreoffice >/dev/null 2>&1; then
SOFFICE_VERSION=$(libreoffice --version 2>&1 | head -1)
pass "libreoffice available: ${SOFFICE_VERSION}"
else
fail "soffice/libreoffice NOT found (expected from base.Dockerfile line 12 apt install)"
EXIT_CODE=1
fi
# --- Chinese fonts ---
if command -v fc-list >/dev/null 2>&1; then
ZH_FONT_COUNT=$(fc-list :lang=zh 2>/dev/null | wc -l)
if [ "${ZH_FONT_COUNT}" -gt 0 ]; then
pass "Chinese fonts: ${ZH_FONT_COUNT} family/style entries detected"
fc-list :lang=zh | head -5 | sed 's/^/ /'
else
fail "fc-list returned 0 Chinese fonts (expected fonts-wqy-zenhei from base.Dockerfile line 13)"
EXIT_CODE=1
fi
else
warn "fc-list not available; skipping Chinese font check"
fi
# --- End-to-end round-trip: md -> docx -> pdf ---
echo
echo "--- End-to-end md -> docx -> pdf round-trip ---"
TMP=$(mktemp -d)
trap 'rm -rf "${TMP}"' EXIT
cat > "${TMP}/sample.md" <<'EOF'
**Admin:**
今天天气 (today weather)
---
**DeepSeek v3.2:**
# 1. 经济因素
通货膨胀与货币政策:黄金常被视为对冲通胀的工具。
| 列 A | 列 B |
| --- | --- |
| 1 | 测试中文 |
```python
def hello():
print("中文 mixed with English")
```
EOF
if pandoc -f markdown -t docx -o "${TMP}/sample.docx" "${TMP}/sample.md" 2>"${TMP}/pandoc.err"; then
DOCX_SIZE=$(wc -c < "${TMP}/sample.docx")
pass "pandoc md -> docx OK (${DOCX_SIZE} bytes)"
else
fail "pandoc md -> docx FAILED:"
cat "${TMP}/pandoc.err" | sed 's/^/ /'
EXIT_CODE=1
fi
if [ -f "${TMP}/sample.docx" ]; then
SOFFICE_BIN=$(command -v soffice || command -v libreoffice)
if [ -n "${SOFFICE_BIN}" ]; then
if "${SOFFICE_BIN}" --headless --convert-to pdf --outdir "${TMP}" "${TMP}/sample.docx" >"${TMP}/soffice.log" 2>&1; then
if [ -f "${TMP}/sample.pdf" ]; then
PDF_SIZE=$(wc -c < "${TMP}/sample.pdf")
HEAD=$(head -c 4 "${TMP}/sample.pdf")
if [ "${HEAD}" = "%PDF" ]; then
pass "soffice docx -> pdf OK (${PDF_SIZE} bytes, header %PDF)"
else
fail "soffice produced a file but it does not start with %PDF magic"
EXIT_CODE=1
fi
else
fail "soffice docx -> pdf produced no output file"
cat "${TMP}/soffice.log" | sed 's/^/ /'
EXIT_CODE=1
fi
else
fail "soffice docx -> pdf FAILED:"
cat "${TMP}/soffice.log" | sed 's/^/ /'
EXIT_CODE=1
fi
fi
fi
echo
if [ ${EXIT_CODE} -eq 0 ]; then
echo -e "${GREEN}=== ALL CHECKS PASSED — F028 export toolchain is ready ===${NC}"
else
echo -e "${RED}=== ONE OR MORE CHECKS FAILED — see [FAIL] lines above ===${NC}"
fi
exit ${EXIT_CODE}