Files
dev 5ee179539e Example-flows + noder: defaults pekar bara på filer som finns
Flöden (flows/example-flows.json):
- Kedjor som skapar det de behöver: png→asset, templates:list→create→
  extract/fill/transform/extractFields, create A+B→compareVersionsPdf
- Defaults /Dokument/Example.md, /Dokument/exempel.odt, dest
  /Dokument/OfficeOut/, mall-id 230 (Invoice.odt via templates:list)
- Ingen referens till /Mallar/avtal.docx, avtal-ny.docx eller logotyp.png
- Debug-noder med tostatus=false (undviker TypeError-length i status)

Noder:
- nc-office templates:create: skickar path+template (richdocuments-
  kontrakt), ärver extension från mallen, MKCOL av mapp, idempotent
  (återanvänd existerande fil i stället för 'namn (2)') — fixar OCS 400
- nc-office document:direct: fileId camelCase (+fileid), 996-fel
  inkluderar nu OCS-body i felmeddelandet
- collabora-wopi discovery: rewrite urlsrc/favIconUrl till
  collaboraPublicUrl så iframe inte går mot CODE bridge-IP
- webdavGet/PROPFIND 404: feltext med föreslagen åtgärd
- resolveDestNcPath: tvingar rätt filändelse (.pdf/.png/…)
- Nytt: listUserExamples (PROPFIND /Dokument+/Documents) +
  bridge-op pickDemoSource; scripts/discover-examples.js

Verifierat mot cloud.domain.name (your-user): capabilities, discovery-
rewrite, pdf/png, asset-länk, mall-skapa+extract/fill/transform,
compare A/B→pdf, document:direct, htmlToOffice — ALL PASS.
2026-08-22 22:50:47 +02:00

564 lines
21 KiB
Bash
Executable File

#!/usr/bin/env bash
# integrate-into-nodered.sh — add Collabora nodes to EXISTING nextcloud-node-red (:1880)
# Called by install.sh / bootstrap-install.sh (default mode).
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PKG_SRC="${PKG_SRC:-$(cd "${SCRIPT_DIR}/.." && pwd)}"
NODERED_DIR="${NODERED_DIR:-/home/ncdeploy/nextcloud-node-red}"
NODERED_CONTAINER="${NODERED_CONTAINER:-nextcloud-node-red}"
NODERED_PORT="${NODERED_PORT:-1880}"
CODE_CONTAINER="${CODE_CONTAINER:-code}"
COLLABORA_IP="${COLLABORA_IP:-}"
NEXTCLOUD_URL="${NEXTCLOUD_URL:-https://cloud.domain.name}"
MARKER="nextcloud-collabora-nodered"
log() { printf '[integrate] %s\n' "$*"; }
warn() { printf '[integrate] WARNING: %s\n' "$*" >&2; }
die() { printf '[integrate] ERROR: %s\n' "$*" >&2; exit 1; }
run_as_root() {
if [ "$(id -u)" -eq 0 ]; then
"$@"
elif command -v sudo >/dev/null 2>&1; then
sudo "$@"
else
die "sudo/root required for: $*"
fi
}
runtime_user() {
if [ -n "${INSTALL_USER:-}" ]; then
echo "${INSTALL_USER}"
elif id ncdeploy >/dev/null 2>&1; then
echo "ncdeploy"
else
id -un
fi
}
# Docker build context — .dockerignore + rättigheter (undviker permission denied)
DOCKERIGNORE_MARKER="nextcloud-collabora-nodered"
patch_dockerignore() {
local di="${NODERED_DIR}/.dockerignore"
local snippet="${PKG_SRC}/integrate/dockerignore.snippet"
if [ ! -f "${di}" ]; then
log "Creating .dockerignore"
touch "${di}"
fi
if ! grep -q "${DOCKERIGNORE_MARKER}" "${di}" 2>/dev/null; then
log "Patching .dockerignore (exclude unreadable local artifacts)"
{
echo ""
echo "# ${DOCKERIGNORE_MARKER}"
if [ -f "${snippet}" ]; then
cat "${snippet}"
else
echo "nodes/odds-scraper/odds-scraper"
echo ".git"
echo ".vscode"
echo "**/*.deb"
echo "winboat*"
echo "**/node_modules"
fi
} >> "${di}"
fi
# Dynamiskt: alla filer under nodes/ som inte ens root kan läsa → ignorera
local unreadable
while IFS= read -r relpath; do
[ -n "${relpath}" ] || continue
if ! grep -qxF "${relpath}" "${di}" 2>/dev/null; then
log " + .dockerignore: ${relpath} (unreadable)"
echo "${relpath}" >> "${di}"
fi
done < <(run_as_root find "${NODERED_DIR}/nodes" -type f ! -readable -printf 'nodes/%P\n' 2>/dev/null || true)
}
fix_nodered_build_permissions() {
local user group
user="$(runtime_user)"
group="$(id -gn "${user}" 2>/dev/null || echo "${user}")"
if [ ! -d "${NODERED_DIR}/nodes" ]; then
return 0
fi
log "Fixing ownership and read permissions for ${NODERED_DIR} (content unchanged)"
run_as_root chown -R "${user}:${group}" "${NODERED_DIR}"
run_as_root find "${NODERED_DIR}/nodes" -type d -exec chmod u+rwx,go+rx {} + 2>/dev/null || true
run_as_root find "${NODERED_DIR}/nodes" -type f -exec chmod u+rw,go+r {} + 2>/dev/null || true
# Binärer som ska vara körbara
run_as_root find "${NODERED_DIR}/nodes" -type f \( -name "*.sh" -o -name "odds-scraper" \) -exec chmod u+rx,go+rx {} + 2>/dev/null || true
}
# Simulera Docker build context — måste lyckas innan build
verify_build_context() {
local di="${NODERED_DIR}/.dockerignore"
local errfile
errfile="$(mktemp)"
log "Verifying Docker build context..."
patch_dockerignore
if ! run_as_root tar -cf /dev/null \
--exclude-from="${di}" \
-C "${NODERED_DIR}" . 2>"${errfile}"; then
warn "Build context error:"
sed 's/^/[integrate] /' "${errfile}" >&2 || true
# Sista utväg: tvinga bort kända problemfil
if [ -f "${NODERED_DIR}/nodes/odds-scraper/odds-scraper" ]; then
echo "nodes/odds-scraper/odds-scraper" >> "${di}"
log "Forced nodes/odds-scraper/odds-scraper into .dockerignore"
fi
if ! run_as_root tar -cf /dev/null \
--exclude-from="${di}" \
-C "${NODERED_DIR}" . 2>"${errfile}"; then
rm -f "${errfile}"
die "Build context still unreadable after .dockerignore — see ${di}"
fi
fi
rm -f "${errfile}"
log "Build context OK"
}
compose_cmd() {
if docker compose version >/dev/null 2>&1; then
echo "docker compose"
else
echo "docker-compose"
fi
}
# Alltid root för compose build — samma användare som kan läsa hela trädet + .dockerignore
compose_run() {
local compose
compose="$(compose_cmd)"
cd "${NODERED_DIR}"
run_as_root env DOCKER_BUILDKIT=1 ${compose} "$@"
}
code_bridge_ip() {
docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{if eq $k "bridge"}}{{$v.IPAddress}}{{end}}{{end}}' "${CODE_CONTAINER}" 2>/dev/null
}
# Host-LAN-IP för extra_hosts (detektera; fallback 192.168.1.10)
detect_host_lan_ip() {
local ip=""
if command -v hostname >/dev/null 2>&1; then
ip="$(hostname -I 2>/dev/null | tr ' ' '\n' \
| grep -E '^(192\.168|10)\.[0-9]+\.[0-9]+\.[0-9]+$' | head -n1 || true)"
fi
if [ -z "${ip}" ] && command -v ip >/dev/null 2>&1; then
ip="$(ip -4 addr show scope global 2>/dev/null | awk '/inet /{print $2}' | cut -d/ -f1 \
| grep -E '^(192\.168|10)\.' | head -n1 || true)"
fi
if [ -z "${ip}" ]; then
warn "Kunde inte detektera host-LAN-IP — fallback 192.168.1.10"
ip="192.168.1.10"
fi
HOST_LAN_IP="${ip}"
log "Host-LAN-IP: ${HOST_LAN_IP}"
}
# Skriv NC_HOST_IP i nextcloud-node-red/.env så compose-substitutionen plockar upp den
write_nodered_env_ip() {
local envfile="${NODERED_DIR}/.env"
local existing=""
if [ -f "${envfile}" ]; then
existing="$(grep -E '^NC_HOST_IP=[[:alnum:].:]+' "${envfile}" 2>/dev/null | tail -n1 | cut -d= -f2 || true)"
fi
if [ -n "${existing}" ]; then
log "${envfile} har redan NC_HOST_IP=${existing} — behåller"
HOST_LAN_IP="${existing}"
return 0
fi
if [ -f "${envfile}" ] && grep -q '^NC_HOST_IP=' "${envfile}" 2>/dev/null; then
run_as_root sed -i "s|^NC_HOST_IP=.*|NC_HOST_IP=${HOST_LAN_IP}|" "${envfile}"
else
run_as_root bash -c "echo 'NC_HOST_IP=${HOST_LAN_IP}' >> '${envfile}'"
fi
log "NC_HOST_IP=${HOST_LAN_IP} → ${envfile}"
}
detect_code_ip() {
local ip
ip="$(code_bridge_ip)"
if [ -n "${ip}" ]; then
COLLABORA_IP="${ip}"
log "CODE bridge-IP: ${COLLABORA_IP} (container ${CODE_CONTAINER})"
return 0
fi
if [ -n "${COLLABORA_IP}" ]; then
warn "Could not read bridge IP — using COLLABORA_IP=${COLLABORA_IP}"
return 0
fi
die "CODE bridge IP missing — set COLLABORA_IP or ensure ${CODE_CONTAINER} runs on Docker bridge"
}
detect_nodered_dir() {
if [ -d "${NODERED_DIR}" ] && [ -f "${NODERED_DIR}/Dockerfile" ]; then
return 0
fi
local from_compose
from_compose="$(docker inspect -f '{{index .Config.Labels "com.docker.compose.project.working_dir"}}' "${NODERED_CONTAINER}" 2>/dev/null || true)"
if [ -n "${from_compose}" ] && [ -f "${from_compose}/Dockerfile" ]; then
NODERED_DIR="${from_compose}"
log "Node-RED directory from compose label: ${NODERED_DIR}"
return 0
fi
for candidate in \
"/home/ncdeploy/nextcloud-node-red" \
"/opt/nextcloud-node-red"; do
if [ -f "${candidate}/Dockerfile" ]; then
NODERED_DIR="${candidate}"
log "Node-RED directory found: ${NODERED_DIR}"
return 0
fi
done
die "NODERED_DIR missing or invalid — set path to existing nextcloud-node-red (Dockerfile + entrypoint.sh)"
}
resolve_paths() {
if [ -f "${PKG_SRC}/.env" ]; then
set -a
# shellcheck disable=SC1091
. "${PKG_SRC}/.env"
set +a
fi
if [ "$(id -u)" -eq 0 ] && [ -d "/home/ncdeploy/nextcloud-node-red" ]; then
NODERED_DIR="${NODERED_DIR:-/home/ncdeploy/nextcloud-node-red}"
PKG_SRC="${PKG_SRC:-/home/ncdeploy/nextcloud-collabora-nodered}"
fi
detect_nodered_dir
detect_code_ip
detect_host_lan_ip
write_nodered_env_ip
}
stop_sidecar_if_any() {
if docker ps -a --format '{{.Names}}' | grep -qx "nextcloud-collabora-nodered"; then
warn "Stopping stray sidecar container nextcloud-collabora-nodered (should not exist)"
docker stop nextcloud-collabora-nodered 2>/dev/null || true
docker rm nextcloud-collabora-nodered 2>/dev/null || true
fi
}
preflight() {
[ -d "${PKG_SRC}" ] || die "Package source missing: ${PKG_SRC}"
[ -f "${PKG_SRC}/package.json" ] || die "package.json missing in ${PKG_SRC}"
[ -d "${NODERED_DIR}" ] || die "nextcloud-node-red missing: ${NODERED_DIR}"
[ -f "${NODERED_DIR}/Dockerfile" ] || die "Dockerfile missing in ${NODERED_DIR}"
[ -f "${NODERED_DIR}/entrypoint.sh" ] || die "entrypoint.sh missing in ${NODERED_DIR}"
if ! docker ps --format '{{.Names}}' | grep -qx "${NODERED_CONTAINER}"; then
die "Container '${NODERED_CONTAINER}' is not running — start existing nextcloud-node-red first"
fi
if ! docker ps --format '{{.Names}}' | grep -qx "${CODE_CONTAINER}"; then
die "CODE container '${CODE_CONTAINER}' is not running"
fi
}
assert_package_layout() {
local dest="$1"
local missing=0
if [ ! -f "${dest}/package.json" ]; then
warn "Missing: ${dest}/package.json"
missing=1
fi
if [ ! -d "${dest}/lib" ] || [ -z "$(ls -A "${dest}/lib" 2>/dev/null)" ]; then
warn "Missing or empty: ${dest}/lib/"
missing=1
fi
if [ ! -d "${dest}/nodes" ] || [ -z "$(ls -A "${dest}/nodes" 2>/dev/null)" ]; then
warn "Missing or empty: ${dest}/nodes/"
missing=1
fi
if [ "${missing}" -ne 0 ]; then
die "Wrong package layout after copy — expected package.json + lib/ + nodes/ under ${dest}"
fi
}
copy_node_package() {
local dest="${NODERED_DIR}/nodes/nextcloud-collabora"
log "Copying package → ${dest} (lib/ + nodes/, not flat)"
rm -rf "${dest}"
mkdir -p "${dest}/lib" "${dest}/nodes"
cp -a "${PKG_SRC}/package.json" "${dest}/"
cp -a "${PKG_SRC}/lib/." "${dest}/lib/"
cp -a "${PKG_SRC}/nodes/." "${dest}/nodes/"
if [ -d "${PKG_SRC}/locales" ] && [ -n "$(ls -A "${PKG_SRC}/locales" 2>/dev/null)" ]; then
mkdir -p "${dest}/locales"
cp -a "${PKG_SRC}/locales/." "${dest}/locales/"
fi
assert_package_layout "${dest}"
log "Package layout OK: ${dest}/{package.json,lib/,nodes/}"
}
patch_dockerfile() {
local df="${NODERED_DIR}/Dockerfile"
if grep -q "${MARKER}" "${df}"; then
log "Dockerfile already patched"
return 0
fi
log "Patching Dockerfile"
cat >> "${df}" <<'EOF'
# nextcloud-collabora-nodered — Collabora/Office-noder (WebDAV + CODE REST)
RUN mkdir -p /opt/nextcloud-nodes/node-red-contrib-nextcloud-collabora
COPY nodes/nextcloud-collabora/package.json /opt/nextcloud-nodes/node-red-contrib-nextcloud-collabora/
COPY nodes/nextcloud-collabora/lib /opt/nextcloud-nodes/node-red-contrib-nextcloud-collabora/lib
COPY nodes/nextcloud-collabora/nodes /opt/nextcloud-nodes/node-red-contrib-nextcloud-collabora/nodes
RUN cd /opt/nextcloud-nodes/node-red-contrib-nextcloud-collabora && npm install --omit=dev
EOF
}
patch_entrypoint() {
local ep="${NODERED_DIR}/entrypoint.sh"
# Rensa trasig tidigare patch (rå cp-rader utan install_nodes)
if grep -q 'cp -a /opt/nextcloud-nodes/node-red-contrib-nextcloud-collabora' "${ep}"; then
log "Removing broken collabora patch from entrypoint.sh"
sed -i '/cp -a \/opt\/nextcloud-nodes\/node-red-contrib-nextcloud-collabora/d' "${ep}"
fi
if grep -q 'install_nodes.*Nextcloud Collabora' "${ep}"; then
log "entrypoint.sh already patched (Collabora install_nodes)"
return 0
fi
log "Patching entrypoint.sh (install_nodes for Collabora)"
if grep -q 'install_nodes.*Nextcloud OCS' "${ep}"; then
sed -i '/install_nodes.*Nextcloud OCS/a\
install_nodes "/opt/nextcloud-nodes/node-red-contrib-nextcloud-collabora" "/data/node_modules/node-red-contrib-nextcloud-collabora" "Nextcloud Collabora"' "${ep}"
elif grep -q 'install_nodes.*Odds Scraper' "${ep}"; then
sed -i '/install_nodes.*Odds Scraper/a\
install_nodes "/opt/nextcloud-nodes/node-red-contrib-nextcloud-collabora" "/data/node_modules/node-red-contrib-nextcloud-collabora" "Nextcloud Collabora"' "${ep}"
else
cat >> "${ep}" <<'EOF'
# nextcloud-collabora-nodered
install_nodes "/opt/nextcloud-nodes/node-red-contrib-nextcloud-collabora" "/data/node_modules/node-red-contrib-nextcloud-collabora" "Nextcloud Collabora"
EOF
fi
}
# Krav: docker network connect <nodered-nät> code — ignorerar already connected
connect_code_network() {
local net
net="$(docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{printf "%s\n" $k}}{{end}}' "${NODERED_CONTAINER}" 2>/dev/null \
| grep -v '^bridge$' | head -n1)"
[ -n "${net}" ] || die "No Node-RED compose network on ${NODERED_CONTAINER}"
if docker network inspect "${net}" --format '{{range .Containers}}{{.Name}} {{end}}' 2>/dev/null | grep -qw "${CODE_CONTAINER}"; then
log "Already connected: ${CODE_CONTAINER} on ${net}"
return 0
fi
log "Connecting ${CODE_CONTAINER} → ${net}"
if ! docker network connect "${net}" "${CODE_CONTAINER}" 2>/dev/null; then
if docker network inspect "${net}" --format '{{range .Containers}}{{.Name}} {{end}}' 2>/dev/null | grep -qw "${CODE_CONTAINER}"; then
log "Already connected (race): ${CODE_CONTAINER} on ${net}"
else
warn "Could not connect ${CODE_CONTAINER} → ${net} — COLLABORA_URL fallar tillbaka till CODE-IP"
fi
fi
}
compose_service_name() {
local svc
svc="$(docker inspect -f '{{index .Config.Labels "com.docker.compose.service"}}' "${NODERED_CONTAINER}" 2>/dev/null || true)"
echo "${svc:-node-red}"
}
# Recreate utan 'docker compose down' — volymer (node-red-data) bevaras.
# ExtraHosts måste vara ifyllda efteråt.
recreate_nodered_service() {
local service extra
service="$(compose_service_name)"
log "Recreating ${service} (--no-deps --force-recreate, volymer bevaras)..."
if ! compose_run up -d --no-deps --force-recreate "${service}"; then
warn "force-recreate misslyckades — rm + up --no-deps (volymen node-red-data ligger kvar)"
run_as_root docker rm -f "${NODERED_CONTAINER}" 2>/dev/null || true
compose_run up -d --no-deps "${service}"
fi
for _ in $(seq 1 10); do
extra="$(docker inspect -f '{{len .HostConfig.ExtraHosts}}' "${NODERED_CONTAINER}" 2>/dev/null || echo 0)"
[ "${extra}" != "0" ] && break
sleep 1
done
if [ -z "${extra:-0}" ] || [ "${extra}" = "0" ]; then
die "ExtraHosts är [] på ${NODERED_CONTAINER} efter recreate — kontrollera extra_hosts i ${NODERED_DIR}/docker-compose.yml"
fi
log "ExtraHosts (${extra}): $(docker inspect -f '{{json .HostConfig.ExtraHosts}}' "${NODERED_CONTAINER}")"
}
# COLLABORA_URL: intern CODE kör HTTPS (ssl.enable=true, self-signed) —
# https://code:9980 primärt, fallback https://<CODE-IP>:9980.
# http://code:9980 failar när CODE har SSL påslaget.
# Aldrig 127.0.0.1/host.docker.internal — CODE kör inte på Node-RED-värden.
resolve_collabora_url() {
local url="${COLLABORA_URL:-https://code:9980}"
case "${url}" in
http://*|http://127.0.0.1:*|http://localhost:*|http://host.docker.internal:*|\
https://127.0.0.1:*|https://localhost:*|https://host.docker.internal:*|"")
warn "Otillåten COLLABORA_URL '${url}' — tvingar https://code:9980"
url="https://code:9980"
;;
esac
# Fallback till CODE-IP om 'code' inte kan resolvas från nod-containern
if ! docker exec "${NODERED_CONTAINER}" getent hosts code >/dev/null 2>&1; then
local ip
ip="$(docker inspect -f '{{range $k,$v := .NetworkSettings.Networks}}{{$v.IPAddress}} {{end}}' "${CODE_CONTAINER}" 2>/dev/null | awk '{print $1}')"
[ -n "${ip}" ] || ip="${COLLABORA_IP:-}"
if [ -n "${ip}" ]; then
warn "'code' inte resolvbart från ${NODERED_CONTAINER} — fallback https://${ip}:9980"
url="https://${ip}:9980"
else
die "Varken 'code'-DNS eller CODE-IP tillgänglig — kan inte sätta COLLABORA_URL"
fi
fi
COLLABORA_URL="${url}"
log "COLLABORA_URL=${COLLABORA_URL}"
}
# Node-RED-containern på default bridge — krävs för att nå https://code:9980.
# Körs EFTER container-up: recreate nollställer manuella network connect.
# Ignorerar "already connected".
connect_nodered_bridge() {
log "Connecting ${NODERED_CONTAINER} → bridge"
local out rc=0
out="$(docker network connect bridge "${NODERED_CONTAINER}" 2>&1)" || rc=$?
if [ "${rc}" -eq 0 ]; then
log "Connected: ${NODERED_CONTAINER} on bridge"
elif printf '%s' "${out}" | grep -qi 'already exists\|already connected'; then
log "Already connected: ${NODERED_CONTAINER} on bridge"
else
warn "docker network connect bridge ${NODERED_CONTAINER} misslyckades: ${out}"
fi
}
rebuild_nodered() {
log "Rebuilding ${NODERED_CONTAINER} (same instance, port ${NODERED_PORT})..."
fix_nodered_build_permissions
verify_build_context
if [ "${FORCE_REBUILD:-0}" = "1" ]; then
compose_run build --no-cache
else
compose_run build
fi
recreate_nodered_service
}
wait_nodered() {
log "Waiting for Node-RED :${NODERED_PORT}..."
for i in $(seq 1 30); do
if curl -sf "http://127.0.0.1:${NODERED_PORT}" >/dev/null 2>&1; then
log "Node-RED responding at http://127.0.0.1:${NODERED_PORT}"
return 0
fi
sleep 2
done
warn "Node-RED did not respond within 60 s"
}
verify_code_from_nodered() {
# Krav 7: getent i containern != 127.0.0.1/127.0.1.1 + curl mot CODE och Nextcloud
local fail=0 h ip_out
for h in cloud.domain.name docs.domain.name host.docker.internal code; do
ip_out="$(docker exec "${NODERED_CONTAINER}" getent hosts "${h}" 2>/dev/null | awk '{print $1}' | head -n1 || true)"
if [ -z "${ip_out}" ]; then
warn "getent ${h}: INGET SVAR"; fail=1
elif [ "${ip_out#127.}" != "${ip_out}" ] || [ "${ip_out}" = "::1" ]; then
warn "getent ${h}: loopback (${ip_out}) — extra_hosts/translering trasig"; fail=1
else
log "getent ${h}: ${ip_out}"
fi
done
# Verifiera enligt serverns verklighet: CODE kör HTTPS internt,
# https://code:9980 ska ge HTTP 200 från Node-RED på bridge.
local code_status
code_status="$(docker exec "${NODERED_CONTAINER}" \
curl -sk -o /dev/null -w '%{http_code}' https://code:9980/hosting/capabilities 2>/dev/null || echo 000)"
if [ "${code_status}" = "200" ]; then
log "OK: CODE nås från Node-RED: https://code:9980/hosting/capabilities (HTTP 200)"
else
warn "CODE inte nåbar: https://code:9980/hosting/capabilities (HTTP ${code_status})"
warn "Kör: docker network connect bridge ${NODERED_CONTAINER} — http://code:9980 failar, CODE kräver HTTPS"
fail=1
fi
if docker exec "${NODERED_CONTAINER}" curl -sfk https://cloud.domain.name/status.php >/dev/null 2>&1; then
log "OK: Nextcloud nås från Node-RED: https://cloud.domain.name/status.php"
else
warn "Nextcloud inte nåbar från Node-RED via https://cloud.domain.name/status.php"
fail=1
fi
return "${fail}"
}
main() {
resolve_paths
log "Integrating Collabora nodes into existing nextcloud-node-red"
log "Package: ${PKG_SRC}"
log "Node-RED: ${NODERED_DIR} (container ${NODERED_CONTAINER})"
stop_sidecar_if_any
preflight
copy_node_package
patch_dockerfile
patch_entrypoint
rebuild_nodered
connect_nodered_bridge
connect_code_network
resolve_collabora_url
wait_nodered
if ! verify_code_from_nodered; then
warn "Verifiering hade fel — se varningarna ovan"
fi
local host_ip nc_url
host_ip="$(hostname -I 2>/dev/null | awk '{print $1}' || echo "127.0.0.1")"
nc_url="${NEXTCLOUD_URL:-https://cloud.domain.name}"
cat <<EOF
Integrating done — same Node-RED on port ${NODERED_PORT}
UI: http://${host_ip}:${NODERED_PORT}
Palette: "nextcloud collabora" (6 nodes + config)
Create config first (gear → nc-collab-config):
Nextcloud: ${nc_url}
Collabora: ${COLLABORA_URL} (verifyTls=false — self-signed internt)
Public WOPI: https://docs.domain.name (collaboraPublicUrl — rewrite av discovery urlsrc)
Auth: username + app password
Try: collabora-wopi (capabilities) → collabora-bridge (ncFileToPdf)
Example flow: flows/example-flows.json — defaults /Dokument/Example.md,
/Dokument/exempel.odt, dest /Dokument/OfficeOut/, mall-id 230 (Invoice.odt).
EOF
}
main "$@"