diff --git a/.env.example b/.env.example index 8c288c0..0bc38a1 100644 --- a/.env.example +++ b/.env.example @@ -1,23 +1,23 @@ -# Miljövariabler för install.sh / integrate-into-nodered.sh -# Kopiera till .env och justera per VM. +# Environment for install.sh / integrate-into-nodered.sh +# Copy to .env and adjust per VM. -# Nextcloud (visas i exempelflöden och dokumentation — påverkar inte själva nodkoden) +# Nextcloud (used in example flows and install hints — does not change node code) NEXTCLOUD_URL=https://cloud.domain.name NEXTCLOUD_PUBLIC_URL=https://cloud.domain.name -# Collabora CODE — IP detekteras automatiskt från Docker bridge om du utelämnar COLLABORA_IP +# Collabora CODE — bridge IP auto-detected if COLLABORA_IP is empty CODE_CONTAINER=code COLLABORA_IP= COLLABORA_URL= -# Befintlig Node-RED-installation (integrate-läge) +# Existing Node-RED install (integrate mode) NODERED_DIR= NODERED_CONTAINER=nextcloud-node-red NODERED_PORT=1880 INSTALL_USER= -# Sidecar-läge (ej standard) +# Sidecar mode (not default) NC_HOST=cloud.domain.name NC_HOST_IP= TZ=Europe/Stockholm -NODERED_CREDENTIAL_SECRET=byt-den-här-hemligheten-vid-produktion +NODERED_CREDENTIAL_SECRET=change-this-secret-in-production diff --git a/README.md b/README.md index a0818e8..4217169 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,81 @@ # nextcloud-collabora-nodered -Collabora/Nextcloud Office-noder för **befintlig** `nextcloud-node-red` på port **1880**. +Collabora / Nextcloud Office nodes for your **existing** `nextcloud-node-red` on port **1880**. -Skapar **ingen** ny Node-RED-container. +Does **not** create a new Node-RED container. -## Standard: integrate (inte sidecar) +## Default: integrate (not sidecar) -**INSTALL_MODE=integrate** (default) patchar och bygger om befintlig `nextcloud-node-red` på **:1880**. -Ingen ny container, ingen port 1881. Sidecar kräver uttryckligen `INSTALL_MODE=sidecar`. +**INSTALL_MODE=integrate** (default) patches and rebuilds the existing `nextcloud-node-red` on **:1880**. +No extra container, no port 1881. Sidecar only if you explicitly set `INSTALL_MODE=sidecar`. -## Installation (cloud / valfri VM) +## Quick install ```bash curl -fsSL https://git.domain.name/your-user/nextcloud-collabora-nodered/raw/branch/main/bootstrap-install.sh | sudo -u ncdeploy bash ``` -Det skriptet: -1. Klonar detta repo till `/home/ncdeploy/nextcloud-collabora-nodered` -2. Kopierar noder till `/home/ncdeploy/nextcloud-node-red/nodes/nextcloud-collabora/` -3. Patchar `Dockerfile` + `entrypoint.sh` i nextcloud-node-red -4. Bygger om **samma** `nextcloud-node-red`-image och startar om containern -5. Ansluter `nextcloud-node-red` till Docker `bridge` så CODE (`172.17.0.2:9980`) nås +That script: +1. Clones this repo +2. Copies nodes into your `nextcloud-node-red` tree +3. Patches `Dockerfile` + `entrypoint.sh` +4. Rebuilds the **same** image and restarts the container +5. Connects Node-RED to Docker `bridge` so CODE is reachable -## Uppdatera noder +## Update nodes ```bash -cd /home/ncdeploy/nextcloud-collabora-nodered +cd /path/to/nextcloud-collabora-nodered git pull ./install.sh ``` -## Manuell integration +## Manual integration ```bash -cd /home/ncdeploy/nextcloud-collabora-nodered -NODERED_DIR=/home/ncdeploy/nextcloud-node-red ./scripts/integrate-into-nodered.sh +NODERED_DIR=/path/to/nextcloud-node-red ./scripts/integrate-into-nodered.sh ``` -## Sidecar :1881 (ej rekommenderat) +## Sidecar :1881 (not recommended) -Endast om du uttryckligen vill separat instans: +Only if you explicitly want a separate instance: ```bash INSTALL_MODE=sidecar docker compose --profile sidecar up -d --build ``` -## Noder +## Nodes -Palett: **nextcloud collabora** — sex noder i samma lila, alla kopplade till **nc-collab-config** (kugghjul, inte flödesnod). +Palette: **nextcloud collabora** — six nodes in the same purple, all wired to **nc-collab-config** (gear icon, not a flow node). `nc-collab-config` · `collabora-bridge` · `nc-office` · `collabora-convert` · `collabora-extract` · `collabora-transform` · `collabora-wopi` -Full förklaring och exempel: **[docs/NODES.md](docs/NODES.md)** · importera **[flows/example-flows.json](flows/example-flows.json)** +Full guide and examples: **[docs/NODES.md](docs/NODES.md)** · import **[flows/example-flows.json](flows/example-flows.json)** -## Installera på valfri Nextcloud-VM +## Install on any Nextcloud VM -Kopiera `.env.example` → `.env` och sätt minst `NEXTCLOUD_URL`. Resten detekteras: +Copy `.env.example` → `.env` and set at least `NEXTCLOUD_URL`. The rest is auto-detected: -| Variabel | Default / auto | +| Variable | Default / auto | |----------|----------------| -| `NODERED_DIR` | compose-label eller `/home/ncdeploy/nextcloud-node-red` | +| `NODERED_DIR` | compose label or common paths | | `CODE_CONTAINER` | `code` | -| `COLLABORA_IP` | bridge-IP via `docker inspect` | +| `COLLABORA_IP` | bridge IP via `docker inspect` | | `NODERED_CONTAINER` | `nextcloud-node-red` | | `NODERED_PORT` | `1880` | ```bash -cd /home/ncdeploy/nextcloud-collabora-nodered -cp .env.example .env # justera NEXTCLOUD_URL per VM +cp .env.example .env # set NEXTCLOUD_URL for your VM git pull -./install.sh # root/sudo för docker compose +./install.sh # needs root/sudo for docker compose ``` ## Repo https://git.domain.name/your-user/nextcloud-collabora-nodered -## Dokumentation +## Documentation -- [docs/NODES.md](docs/NODES.md) -- [docs/INFRASTRUCTURE.md](docs/INFRASTRUCTURE.md) +- [docs/NODES.md](docs/NODES.md) — node reference and examples +- [docs/NODES.md](docs/NODES.md) — node reference and examples +- [docs/INFRASTRUCTURE.md](docs/INFRASTRUCTURE.md) — server layout diff --git a/bootstrap-install.sh b/bootstrap-install.sh index 077d8e6..c357688 100644 --- a/bootstrap-install.sh +++ b/bootstrap-install.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash -# bootstrap-install.sh — klona från Gitea och integrera i befintlig nextcloud-node-red +# bootstrap-install.sh — clone from Gitea and integrate into existing nextcloud-node-red # -# Skapar INTE ny Node-RED-container. Patchar /home/ncdeploy/nextcloud-node-red och bygger om. +# Does NOT create a new Node-RED container. Patches nextcloud-node-red and rebuilds. # -# One-liner (kör som ncdeploy, INTE root): +# One-liner (run as install user, NOT root): # curl -fsSL https://git.domain.name/your-user/nextcloud-collabora-nodered/raw/branch/main/bootstrap-install.sh | sudo -u ncdeploy bash # -# Om git "dubious ownership" (root ägde repot): +# If git "dubious ownership" (root owned the repo): # sudo bash scripts/fix-repo-ownership.sh # set -euo pipefail @@ -34,11 +34,11 @@ SKIP_APT="${SKIP_APT:-0}" SKIP_DOCKER_INSTALL="${SKIP_DOCKER_INSTALL:-1}" log() { printf '[bootstrap] %s\n' "$*"; } -warn() { printf '[bootstrap] VARNING: %s\n' "$*" >&2; } -die() { printf '[bootstrap] FEL: %s\n' "$*" >&2; exit 1; } +warn() { printf '[bootstrap] WARNING: %s\n' "$*" >&2; } +die() { printf '[bootstrap] 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 krävs"; fi + if [ "$(id -u)" -eq 0 ]; then "$@"; elif command -v sudo >/dev/null 2>&1; then sudo "$@"; else die "sudo required"; fi } runtime_user() { @@ -58,7 +58,7 @@ reexec_as_install_user() { local user user="$(runtime_user)" if [ "$(id -un)" = "root" ] && [ "${user}" != "root" ] && [ -z "${BOOTSTRAP_REEXEC:-}" ]; then - log "Kör om som ${user} (inte root)..." + log "Re-running as ${user} (not root)..." export BOOTSTRAP_REEXEC=1 export INSTALL_DIR NODERED_DIR INSTALL_MODE GIT_REPO_URL GIT_BRANCH exec sudo -u "${user}" -H env \ @@ -80,7 +80,7 @@ fix_repo_ownership() { [ -d "${INSTALL_DIR}" ] || return 0 owner="$(stat -c '%U' "${INSTALL_DIR}" 2>/dev/null || echo "")" if [ -n "${owner}" ] && [ "${owner}" != "${user}" ]; then - log "Repo ägs av ${owner} — sätter ägare ${user}:${group}" + log "Repo owned by ${owner} — setting owner ${user}:${group}" run_as_root chown -R "${user}:${group}" "${INSTALL_DIR}" fi } @@ -98,7 +98,7 @@ ensure_git_safe_directory() { install_apt_packages() { [ "${SKIP_APT}" = "1" ] && return 0 command -v apt-get >/dev/null 2>&1 || return 0 - log "Installerar git, curl, rsync..." + log "Installing git, curl, rsync..." run_as_root apt-get update -qq run_as_root apt-get install -y -qq git curl ca-certificates rsync } @@ -106,7 +106,7 @@ install_apt_packages() { install_docker() { [ "${SKIP_DOCKER_INSTALL}" = "1" ] && return 0 command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1 && return 0 - log "Installerar Docker..." + log "Installing Docker..." curl -fsSL https://get.docker.com | run_as_root sh } @@ -115,13 +115,13 @@ clone_or_update_repo() { ensure_git_safe_directory if [ -d "${INSTALL_DIR}/.git" ]; then - log "Uppdaterar ${INSTALL_DIR}..." + log "Updating ${INSTALL_DIR}..." git -C "${INSTALL_DIR}" fetch origin git -C "${INSTALL_DIR}" checkout "${GIT_BRANCH}" - git -C "${INSTALL_DIR}" pull --ff-only origin "${GIT_BRANCH}" || warn "git pull misslyckades" + git -C "${INSTALL_DIR}" pull --ff-only origin "${GIT_BRANCH}" || warn "git pull failed" return 0 fi - log "Klonar ${GIT_REPO_URL} → ${INSTALL_DIR}" + log "Cloning ${GIT_REPO_URL} → ${INSTALL_DIR}" mkdir -p "$(dirname "${INSTALL_DIR}")" git clone --branch "${GIT_BRANCH}" --depth 1 "${GIT_REPO_URL}" "${INSTALL_DIR}" fix_repo_ownership @@ -129,25 +129,25 @@ clone_or_update_repo() { } preflight() { - command -v docker >/dev/null 2>&1 || die "Docker saknas" + command -v docker >/dev/null 2>&1 || die "Docker not found" docker ps --format '{{.Names}}' | grep -qx "${NODERED_CONTAINER}" \ - || die "'${NODERED_CONTAINER}' körs inte — detta skript integrerar i befintlig Node-RED, skapar ingen ny" + || die "'${NODERED_CONTAINER}' is not running — this script integrates into existing Node-RED, does not create a new one" docker ps --format '{{.Names}}' | grep -qx "${CODE_CONTAINER}" \ - || die "'${CODE_CONTAINER}' (Collabora) körs inte" - [ -d "${NODERED_DIR}" ] || die "nextcloud-node-red-katalog saknas: ${NODERED_DIR}" - log "OK: ${NODERED_CONTAINER} + ${CODE_CONTAINER} körs" + || die "'${CODE_CONTAINER}' (Collabora) is not running" + [ -d "${NODERED_DIR}" ] || die "nextcloud-node-red directory missing: ${NODERED_DIR}" + log "OK: ${NODERED_CONTAINER} + ${CODE_CONTAINER} running" } main() { reexec_as_install_user - log "bootstrap v${VERSION} — läge: ${INSTALL_MODE} (befintlig Node-RED :${NODERED_PORT})" - log "Användare: $(id -un)" + log "bootstrap v${VERSION} — mode: ${INSTALL_MODE} (existing Node-RED :${NODERED_PORT})" + log "User: $(id -un)" log "Repo → ${INSTALL_DIR}" - log "Integrera → ${NODERED_DIR}" + log "Integrate → ${NODERED_DIR}" if [ "$(id -u)" -eq 0 ] && [ "$(runtime_user)" = "root" ]; then - warn "Körs som root — rekommenderat: curl ... | sudo -u ncdeploy bash" + warn "Running as root — recommended: curl ... | sudo -u ncdeploy bash" fi install_apt_packages @@ -168,13 +168,13 @@ main() { cat <:9980` (verifyTls=false) | +| Browser editor / WOPI | `collaboraPublicUrl` — usually same as Nextcloud proxy | + +## Gitea (optional) + +- https://git.domain.name/your-user/nextcloud-collabora-nodered +- SSH git on port 2222 if configured diff --git a/docs/NODES.md b/docs/NODES.md index 5163290..dfda6de 100644 --- a/docs/NODES.md +++ b/docs/NODES.md @@ -1,71 +1,71 @@ -# Noder — nextcloud collabora +# Nodes — nextcloud collabora -Sex flödesnoder i paletten + en config. Alla sex pekar på samma **nc-collab-config** (kugghjul, inte i paletten). Utan config händer inget. +Six flow nodes in the palette plus one config node. All six point at the same **nc-collab-config** (gear menu, not in the palette). Without config, nothing works. ## Backends -| Backend | Typisk adress | Roll | -|---------|---------------|------| -| Nextcloud | `https://cloud.domain.name` | Filer (WebDAV) + Office-API (OCS) | -| Collabora CODE | `https://172.17.0.2:9980` | Konvertering (`/cool/...`) på Docker bridge | +| Backend | Typical URL | Role | +|---------|-------------|------| +| Nextcloud | `https://cloud.example.com` | Files (WebDAV) + Office API (OCS) | +| Collabora CODE | `https://172.17.0.2:9980` | Conversion (`/cool/...`) on Docker bridge | -Auth: **användarnamn + app-lösenord**. Inte kontolösen. +Auth: **username + app password**. Not your account password. -Standardutdata om du inte anger sökväg: `/Dokument/OfficeOut/` +Default output folder if you omit a path: `/Dokument/OfficeOut/` (or set your own via `destNcPath`). --- -## Så hänger de ihop +## How they fit together ``` -nc-collab-config (URL + app-lösen) +nc-collab-config (URLs + app password) │ ┌────┼────┬────────────┐ ▼ ▼ ▼ ▼ collabora-* nc-office collabora-wopi collabora-bridge -(direkt CODE) (NC OCS) (health/WOPI) (kedjor + sparar) +(direct CODE) (NC OCS) (health/WOPI) (pipelines + save) ``` -**Tumregel** +**Rules of thumb** -- PDF i Nextcloud → `collabora-bridge` **ncFileToPdf** -- Fylla mall i NC → **fillTemplateSave** eller `nc-office template:fillFields` -- Öppna i webbläsaren → `nc-office` **document:direct** -- Bara byta format i minnet → `collabora-convert` -- Se fältnamn → `collabora-extract` eller bridge **extractToPayload** -- Kolla att CODE lever → `collabora-wopi` **capabilities** +- PDF in Nextcloud → `collabora-bridge` **ncFileToPdf** +- Fill template in NC → **fillTemplateSave** or `nc-office template:fillFields` +- Open in browser → `nc-office` **document:direct** +- Convert in memory only → `collabora-convert` +- List field names → `collabora-extract` or bridge **extractToPayload** +- Check CODE is alive → `collabora-wopi` **capabilities** --- -## Gemensamma fält i msg +## Common `msg` fields -| Fält | Betydelse | -|------|-----------| -| `ncPath` | Sökväg i användarens filer, t.ex. `/Dokument/avtal.docx` | -| `fileId` | NC fil-id (slås upp från ncPath om saknas) | -| `payload` | Rådata redan i flödet (Buffer eller HTML) | +| Field | Meaning | +|-------|---------| +| `ncPath` | Path in the user's files, e.g. `/Documents/contract.docx` | +| `fileId` | Nextcloud numeric file id (resolved from `ncPath` if missing) | +| `payload` | Raw data already in the flow (Buffer or HTML string) | | `format` | pdf, png, docx, html, … | -| `destNcPath` | Exakt målsökväg | -| `destFolder` / `destName` | Mapp + namn (default `/Dokument/OfficeOut/`) | -| `fields` / `transform` | JSON att skriva in i mall | -| `templateNcPath` | Extra mall till convert | -| `compareNcPath` | Gammal version för diff-PDF | -| `operation` | Överstyr dropdown på noden | +| `destNcPath` | Exact destination path | +| `destFolder` / `destName` | Folder + name (default folder `/Dokument/OfficeOut/`) | +| `fields` / `transform` | JSON to merge into a template | +| `templateNcPath` | Extra template file for convert | +| `compareNcPath` | Older version for diff PDF | +| `operation` | Overrides the node dropdown | -Fel → `msg.error` + röd nod. Flödet dör inte tyst. +Errors go to `msg.error` and turn the node red. The flow does not fail silently. --- ## 1. collabora-convert -Gör om fil till annat format via CODE. Sparar **inte** i Nextcloud — utdata i `msg.payload` (Buffer). +Convert a file to another format via CODE. Does **not** save to Nextcloud — output is `msg.payload` (Buffer). -**In:** `msg.payload` eller WebDAV GET `msg.ncPath`. Valfritt `templateNcPath`, `compareNcPath`, `format`. +**In:** `msg.payload` or WebDAV GET `msg.ncPath`. Optional `templateNcPath`, `compareNcPath`, `format`. -**Ut:** `payload`, `filename`, `format`, `contentType`, `statusCode`. +**Out:** `payload`, `filename`, `format`, `contentType`, `statusCode`. ``` -inject { ncPath: "/Dokument/avtal.docx", format: "pdf" } +inject { ncPath: "/Documents/contract.docx", format: "pdf" } → collabora-convert → debug ``` @@ -73,12 +73,12 @@ inject { ncPath: "/Dokument/avtal.docx", format: "pdf" } ## 2. collabora-extract -Lista struktur (content controls, fält …). JSON ut, ingen fil. +List structure inside a document (content controls, fields, etc.). JSON out, no file. -**In:** samma källa som convert. Filter: nod eller `msg.filter` (default `contentcontrol`). +**In:** same as convert. Filter: node dropdown or `msg.filter` (default `contentcontrol`). ``` -inject { ncPath: "/Mallar/avtal.docx" } +inject { ncPath: "/Templates/contract.docx" } → collabora-extract → function → collabora-transform ``` @@ -86,50 +86,50 @@ inject { ncPath: "/Mallar/avtal.docx" } ## 3. collabora-transform -Skriv värden i dokument via CODE. Kräver `msg.fields` eller `msg.transform`. +Write values into a document via CODE. Requires `msg.fields` or `msg.transform`. ``` -msg.ncPath = "/Mallar/avtal.docx" -msg.fields = { "Kund": "AB Exempel", "Datum": "2026-08-22" } +msg.ncPath = "/Templates/contract.docx" +msg.fields = { "Customer": "ACME Ltd", "Date": "2026-08-22" } → collabora-transform ``` -Spara själv efteråt om filen ska ligga i NC. +Save yourself afterwards if the file should live in Nextcloud. --- ## 4. collabora-wopi -Hälsokoll och WOPI — inte konvertering. +Health checks and WOPI helpers — not conversion. -| Operation | Syfte | -|-----------|--------| -| `capabilities` | Första test att CODE svarar | -| `discovery` | mime → editor-URL | +| Operation | Purpose | +|-----------|---------| +| `capabilities` | First test that CODE responds | +| `discovery` | mime → editor URL | | `buildEditor` | `wopiSrc` + `token` → `editorUrl` | -| `checkFileInfo` / `getFile` | Felsökning | +| `checkFileInfo` / `getFile` | Debugging | -Publik editor-URL går via Nextcloud (`collaboraPublicUrl`), inte intern IP. +Public editor URLs go through Nextcloud (`collaboraPublicUrl`), not the internal CODE IP. --- ## 5. nc-office -Nextcloud richdocuments OCS — mallar, fält, editor-URL, assets. +Nextcloud richdocuments OCS — templates, fields, editor URL, assets. -| Operation | Kort | -|-----------|------| -| `templates:list` | Lista mallar | -| `templates:create` | Ny fil från mall | -| `template:extractFields` | Fält-JSON via NC | -| `template:fillFields` | Fyll + spara i NC | -| `document:direct` | `editorUrl` för inloggad användare | -| `document:public` | Samma med shareToken | -| `files:convert` | NC → NC konvertering | -| `assets:create` | Infogningslänk till öppen editor | +| Operation | Summary | +|-----------|---------| +| `templates:list` | List templates | +| `templates:create` | New file from template | +| `template:extractFields` | Field JSON via NC | +| `template:fillFields` | Fill + save in NC | +| `document:direct` | `editorUrl` for logged-in user | +| `document:public` | Same with `shareToken` | +| `files:convert` | NC → NC conversion | +| `assets:create` | One-shot insert URL for open editor | ``` -inject { ncPath: "/Dokument/avtal.docx" } +inject { ncPath: "/Documents/contract.docx" } → nc-office (document:direct) → debug editorUrl ``` @@ -137,38 +137,38 @@ inject { ncPath: "/Dokument/avtal.docx" } ## 6. collabora-bridge -Färdiga pipelines — det mesta i vardagsflöden. +Ready-made pipelines — what you'll use most day to day. -| Operation | Gör | -|-----------|-----| -| `ncFileToPdf` | NC-fil → PDF i OfficeOut | -| `ncFileToPng` | Förhandsvisning | -| `ncFileToHtml` | HTML-export | +| Operation | Does | +|-----------|------| +| `ncFileToPdf` | NC file → PDF in OfficeOut | +| `ncFileToPng` | Preview PNG | +| `ncFileToHtml` | HTML export | | `htmlToOffice` | HTML → docx/pdf … | -| `fillTemplateSave` | Mall + fält → spara i NC | -| `compareVersionsPdf` | Diff-PDF | -| `extractToPayload` | Fält-JSON i msg | -| `createAssetLink` | assetUrl | +| `fillTemplateSave` | Template + fields → save in NC | +| `compareVersionsPdf` | Diff PDF | +| `extractToPayload` | Field JSON in msg | +| `createAssetLink` | `assetUrl` | ``` -inject { ncPath: "/Dokument/avtal.docx" } +inject { ncPath: "/Documents/contract.docx" } → collabora-bridge (ncFileToPdf) → debug destNcPath ``` -Efter bridge kan du koppla dina befintliga OCS-noder (Talk, Mail, dela länk): först PDF i `/Dokument/OfficeOut/`, sedan dela. +Chain your existing OCS nodes (Talk, Mail, share link) after bridge: PDF lands in `/Dokument/OfficeOut/`, then share or send. --- ## Config: nc-collab-config -Skapas under kugghjul i Node-RED. Alla sex noder väljer samma config-instans. +Create under the gear icon in Node-RED. All six flow nodes pick the same config instance. -| Fält | Exempel | -|------|---------| -| nextcloudUrl | `https://cloud.domain.name` | -| collaboraUrl | `https://172.17.0.2:9980` (bridge-IP, verifyTls=false) | -| collaboraPublicUrl | `https://cloud.domain.name` | -| username + app-lösenord | Nextcloud-inloggning | +| Field | Example | +|-------|---------| +| nextcloudUrl | `https://cloud.example.com` | +| collaboraUrl | `https://172.17.0.2:9980` (bridge IP, verifyTls=false) | +| collaboraPublicUrl | `https://cloud.example.com` | +| username + app password | Nextcloud login | -IP för CODE detekteras vid `./install.sh` — se `.env.example`. +CODE IP is detected when you run `./install.sh` — see `.env.example`. diff --git a/flows/example-flows.json b/flows/example-flows.json index e089e7b..4aa016e 100644 --- a/flows/example-flows.json +++ b/flows/example-flows.json @@ -2,9 +2,9 @@ { "id": "collab_tab", "type": "tab", - "label": "NC Collabora — exempel", + "label": "NC Collabora — examples", "disabled": false, - "info": "Skapa nc-collab-config först (kugghjul). Byt FILL_IN_USER och app-lösenord.\n\n1. capabilities — CODE lever?\n2. ncFileToPdf — PDF i OfficeOut\n3. document:direct — editorUrl\n\nSe docs/NODES.md" + "info": "Create nc-collab-config first (gear menu). Set FILL_IN_USER and app password.\n\n1. capabilities — is CODE up?\n2. ncFileToPdf — PDF in OfficeOut\n3. document:direct — editorUrl\n\nSee docs/NODES.md" }, { "id": "nc_collab_cfg", @@ -104,7 +104,7 @@ "id": "inj_editor", "type": "inject", "z": "collab_tab", - "name": "3. Öppna i Office", + "name": "3. Open in Office", "props": [ { "p": "ncPath", @@ -149,7 +149,7 @@ "id": "inj_extract", "type": "inject", "z": "collab_tab", - "name": "4. Fält i mall", + "name": "4. Template fields", "props": [ { "p": "ncPath", diff --git a/install.sh b/install.sh index f05c5c9..11a4708 100755 --- a/install.sh +++ b/install.sh @@ -1,17 +1,17 @@ #!/usr/bin/env bash -# install.sh — integrera Collabora-noder i befintlig nextcloud-node-red (:1880) +# install.sh — integrate Collabora nodes into existing nextcloud-node-red (:1880) # -# Standard: INSTALL_MODE=integrate (ingen ny container, ingen port 1881) -# Sidecar (endast om du uttryckligen vill): INSTALL_MODE=sidecar +# Default: INSTALL_MODE=integrate (no new container, no port 1881) +# Sidecar (only if you explicitly want it): INSTALL_MODE=sidecar # -# Miljövariabler (valfria — .env i reporoten laddas automatiskt): -# NODERED_DIR Sökväg till befintlig nextcloud-node-red (auto-detekteras om tom) -# NODERED_CONTAINER Docker-namn, default nextcloud-node-red +# Environment (optional — .env in repo root is loaded automatically): +# NODERED_DIR Path to existing nextcloud-node-red (auto-detected if empty) +# NODERED_CONTAINER Docker name, default nextcloud-node-red # NODERED_PORT default 1880 -# CODE_CONTAINER Docker-namn för Collabora CODE, default code -# COLLABORA_IP CODE:s bridge-IP (auto-detekteras om tom) -# NEXTCLOUD_URL t.ex. https://cloud.domain.name (hints i slutet) -# INSTALL_USER filägare vid chown, default ncdeploy +# CODE_CONTAINER Collabora CODE container name, default code +# COLLABORA_IP CODE bridge IP (auto-detected if empty) +# NEXTCLOUD_URL e.g. https://cloud.example.com (shown in install summary) +# INSTALL_USER file owner for chown, default ncdeploy # FORCE_REBUILD=1 docker compose build --no-cache # set -euo pipefail @@ -21,7 +21,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" INSTALL_DIR="${INSTALL_DIR:-$SCRIPT_DIR}" INSTALL_MODE="${INSTALL_MODE:-integrate}" -# Ladda .env om den finns (inga hemligheter krävs här) +# Load .env if present (no secrets required here) if [ -f "${INSTALL_DIR}/.env" ]; then set -a # shellcheck disable=SC1091 @@ -39,25 +39,25 @@ NEXTCLOUD_URL="${NEXTCLOUD_URL:-https://cloud.domain.name}" [ -n "${NEXTCLOUD_URL}" ] || NEXTCLOUD_URL="https://cloud.domain.name" log() { printf '[install] %s\n' "$*"; } -die() { printf '[install] FEL: %s\n' "$*" >&2; exit 1; } +die() { printf '[install] ERROR: %s\n' "$*" >&2; exit 1; } -log "nextcloud-collabora-nodered v${VERSION} (läge: ${INSTALL_MODE})" +log "nextcloud-collabora-nodered v${VERSION} (mode: ${INSTALL_MODE})" if [ "${INSTALL_MODE}" = "sidecar" ]; then - log "Sidecar-läge — varning: standard är integrate (befintlig :1880)" - require_cmd() { command -v "$1" >/dev/null 2>&1 || die "Saknar: $1"; } + log "Sidecar mode — note: default is integrate (existing :1880)" + require_cmd() { command -v "$1" >/dev/null 2>&1 || die "Missing: $1"; } require_cmd docker COMPOSE="docker compose" docker compose version >/dev/null 2>&1 || COMPOSE="docker-compose" cd "${INSTALL_DIR}" - [ -f docker-compose.yml ] || die "docker-compose.yml saknas" + [ -f docker-compose.yml ] || die "docker-compose.yml not found" [ -f .env ] || cp .env.example .env if ! docker ps --format '{{.Names}}' | grep -qx "${CODE_CONTAINER}"; then - die "CODE-container '${CODE_CONTAINER}' körs inte" + die "CODE container '${CODE_CONTAINER}' is not running" fi ${COMPOSE} build ${COMPOSE} up -d - log "Sidecar startad på :1881 (ej rekommenderat om :1880 redan kör)" + log "Sidecar started on :1881 (not recommended if :1880 already runs)" exit 0 fi @@ -73,4 +73,4 @@ PKG_SRC="${INSTALL_DIR}" \ INSTALL_USER="${INSTALL_USER:-}" \ bash "${SCRIPT_DIR}/scripts/integrate-into-nodered.sh" -log "Klart." +log "Done." diff --git a/nodes/collabora-bridge.html b/nodes/collabora-bridge.html index 74fc670..61e6c09 100644 --- a/nodes/collabora-bridge.html +++ b/nodes/collabora-bridge.html @@ -18,7 +18,7 @@ diff --git a/nodes/collabora-convert.html b/nodes/collabora-convert.html index fb47aa6..ca16e2d 100644 --- a/nodes/collabora-convert.html +++ b/nodes/collabora-convert.html @@ -19,7 +19,7 @@ diff --git a/nodes/collabora-extract.html b/nodes/collabora-extract.html index 7cb616c..c753eaa 100644 --- a/nodes/collabora-extract.html +++ b/nodes/collabora-extract.html @@ -18,7 +18,7 @@ diff --git a/nodes/collabora-transform.html b/nodes/collabora-transform.html index 4695d39..f50433f 100644 --- a/nodes/collabora-transform.html +++ b/nodes/collabora-transform.html @@ -17,7 +17,7 @@ diff --git a/nodes/collabora-wopi.html b/nodes/collabora-wopi.html index 5ad7558..7903537 100644 --- a/nodes/collabora-wopi.html +++ b/nodes/collabora-wopi.html @@ -18,7 +18,7 @@ diff --git a/nodes/nc-office.html b/nodes/nc-office.html index f6a9f47..e2d6f9f 100644 --- a/nodes/nc-office.html +++ b/nodes/nc-office.html @@ -18,7 +18,7 @@ diff --git a/scripts/fix-docker-build-context.sh b/scripts/fix-docker-build-context.sh index 8115f48..b25a7bb 100644 --- a/scripts/fix-docker-build-context.sh +++ b/scripts/fix-docker-build-context.sh @@ -25,4 +25,4 @@ EOF fi tar -cf /dev/null --exclude-from="${DI}" -C "${NODERED_DIR}" . \ - && echo "[fix] Build context OK — kör ./install.sh" + && echo "[fix] Build context OK — run ./install.sh" diff --git a/scripts/fix-repo-ownership.sh b/scripts/fix-repo-ownership.sh index 3376575..33d6d33 100644 --- a/scripts/fix-repo-ownership.sh +++ b/scripts/fix-repo-ownership.sh @@ -1,9 +1,9 @@ #!/usr/bin/env bash -# Snabbfix om git "dubious ownership" efter root-kloning +# Quick fix if git reports "dubious ownership" after root clone set -euo pipefail DIR="${1:-/home/ncdeploy/nextcloud-collabora-nodered}" USER="${2:-ncdeploy}" echo "chown ${USER} ${DIR}" chown -R "${USER}:${USER}" "${DIR}" sudo -u "${USER}" git config --global --add safe.directory "${DIR}" -echo "Klart. Kör: cd ${DIR} && ./install.sh" +echo "Done. Run: cd ${DIR} && ./install.sh" diff --git a/scripts/integrate-into-nodered.sh b/scripts/integrate-into-nodered.sh index b96b54b..0d8729e 100755 --- a/scripts/integrate-into-nodered.sh +++ b/scripts/integrate-into-nodered.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# integrate-into-nodered.sh — lägg Collabora-noder i BEFINTLIG nextcloud-node-red (:1880) -# Anropas av install.sh / bootstrap-install.sh (standardläge). +# 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)" @@ -14,8 +14,8 @@ NEXTCLOUD_URL="${NEXTCLOUD_URL:-https://cloud.domain.name}" MARKER="nextcloud-collabora-nodered" log() { printf '[integrate] %s\n' "$*"; } -warn() { printf '[integrate] VARNING: %s\n' "$*" >&2; } -die() { printf '[integrate] FEL: %s\n' "$*" >&2; exit 1; } +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 @@ -23,7 +23,7 @@ run_as_root() { elif command -v sudo >/dev/null 2>&1; then sudo "$@" else - die "sudo/root krävs för: $*" + die "sudo/root required for: $*" fi } @@ -45,12 +45,12 @@ patch_dockerignore() { local snippet="${PKG_SRC}/integrate/dockerignore.snippet" if [ ! -f "${di}" ]; then - log "Skapar .dockerignore" + log "Creating .dockerignore" touch "${di}" fi if ! grep -q "${DOCKERIGNORE_MARKER}" "${di}" 2>/dev/null; then - log "Patchar .dockerignore (exkluderar oläsbara lokala artefakter)" + log "Patching .dockerignore (exclude unreadable local artifacts)" { echo "" echo "# ${DOCKERIGNORE_MARKER}" @@ -72,7 +72,7 @@ patch_dockerignore() { while IFS= read -r relpath; do [ -n "${relpath}" ] || continue if ! grep -qxF "${relpath}" "${di}" 2>/dev/null; then - log " + .dockerignore: ${relpath} (oläsbar)" + 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) @@ -87,7 +87,7 @@ fix_nodered_build_permissions() { return 0 fi - log "Fixar ägande och läsrättigheter för ${NODERED_DIR} (innehåll orört)" + 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 @@ -102,24 +102,24 @@ verify_build_context() { local errfile errfile="$(mktemp)" - log "Verifierar Docker build context..." + 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-fel:" + 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 "Tvingade nodes/odds-scraper/odds-scraper in i .dockerignore" + 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 oläsbar efter .dockerignore — se ${di}" + die "Build context still unreadable after .dockerignore — see ${di}" fi fi rm -f "${errfile}" @@ -155,10 +155,10 @@ detect_code_ip() { return 0 fi if [ -n "${COLLABORA_IP}" ]; then - warn "Kunde inte läsa bridge-IP — använder COLLABORA_IP=${COLLABORA_IP}" + warn "Could not read bridge IP — using COLLABORA_IP=${COLLABORA_IP}" return 0 fi - die "CODE bridge-IP saknas — sätt COLLABORA_IP eller kontrollera att ${CODE_CONTAINER} kör på Docker bridge" + die "CODE bridge IP missing — set COLLABORA_IP or ensure ${CODE_CONTAINER} runs on Docker bridge" } detect_nodered_dir() { @@ -170,7 +170,7 @@ detect_nodered_dir() { 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-katalog från compose-label: ${NODERED_DIR}" + log "Node-RED directory from compose label: ${NODERED_DIR}" return 0 fi @@ -179,12 +179,12 @@ detect_nodered_dir() { "/opt/nextcloud-node-red"; do if [ -f "${candidate}/Dockerfile" ]; then NODERED_DIR="${candidate}" - log "Node-RED-katalog hittad: ${NODERED_DIR}" + log "Node-RED directory found: ${NODERED_DIR}" return 0 fi done - die "NODERED_DIR saknas eller ogiltig — sätt sökväg till befintlig nextcloud-node-red (Dockerfile + entrypoint.sh)" + die "NODERED_DIR missing or invalid — set path to existing nextcloud-node-red (Dockerfile + entrypoint.sh)" } resolve_paths() { @@ -206,24 +206,24 @@ resolve_paths() { stop_sidecar_if_any() { if docker ps -a --format '{{.Names}}' | grep -qx "nextcloud-collabora-nodered"; then - warn "Stoppar felaktig sidecar-container nextcloud-collabora-nodered (skulle inte skapas)" + 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 "Paketkälla saknas: ${PKG_SRC}" - [ -f "${PKG_SRC}/package.json" ] || die "package.json saknas i ${PKG_SRC}" - [ -d "${NODERED_DIR}" ] || die "nextcloud-node-red saknas: ${NODERED_DIR}" - [ -f "${NODERED_DIR}/Dockerfile" ] || die "Dockerfile saknas i ${NODERED_DIR}" - [ -f "${NODERED_DIR}/entrypoint.sh" ] || die "entrypoint.sh saknas i ${NODERED_DIR}" + [ -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}' körs inte — starta befintlig nextcloud-node-red först" + 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}' körs inte" + die "CODE container '${CODE_CONTAINER}' is not running" fi } @@ -232,25 +232,25 @@ assert_package_layout() { local missing=0 if [ ! -f "${dest}/package.json" ]; then - warn "Saknas: ${dest}/package.json" + warn "Missing: ${dest}/package.json" missing=1 fi if [ ! -d "${dest}/lib" ] || [ -z "$(ls -A "${dest}/lib" 2>/dev/null)" ]; then - warn "Saknas eller tom: ${dest}/lib/" + warn "Missing or empty: ${dest}/lib/" missing=1 fi if [ ! -d "${dest}/nodes" ] || [ -z "$(ls -A "${dest}/nodes" 2>/dev/null)" ]; then - warn "Saknas eller tom: ${dest}/nodes/" + warn "Missing or empty: ${dest}/nodes/" missing=1 fi if [ "${missing}" -ne 0 ]; then - die "Paketlayout fel efter kopiering — förväntat package.json + lib/ + nodes/ under ${dest}" + 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 "Kopierar paket → ${dest} (lib/ + nodes/, inte platt)" + log "Copying package → ${dest} (lib/ + nodes/, not flat)" rm -rf "${dest}" mkdir -p "${dest}/lib" "${dest}/nodes" @@ -265,16 +265,16 @@ copy_node_package() { fi assert_package_layout "${dest}" - log "Paketlayout OK: ${dest}/{package.json,lib/,nodes/}" + log "Package layout OK: ${dest}/{package.json,lib/,nodes/}" } patch_dockerfile() { local df="${NODERED_DIR}/Dockerfile" if grep -q "${MARKER}" "${df}"; then - log "Dockerfile redan patchad" + log "Dockerfile already patched" return 0 fi - log "Patchar Dockerfile" + log "Patching Dockerfile" cat >> "${df}" <<'EOF' # nextcloud-collabora-nodered — Collabora/Office-noder (WebDAV + CODE REST) @@ -291,16 +291,16 @@ patch_entrypoint() { # 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 "Rensar trasig collabora-patch i entrypoint.sh" + 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 redan patchad (Collabora install_nodes)" + log "entrypoint.sh already patched (Collabora install_nodes)" return 0 fi - log "Patchar entrypoint.sh (install_nodes för Collabora)" + 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}" @@ -317,16 +317,16 @@ EOF } connect_code_network() { - log "Ansluter ${NODERED_CONTAINER} till Docker bridge (CODE)" + log "Connecting ${NODERED_CONTAINER} to Docker bridge (CODE)" if docker network inspect bridge --format '{{range .Containers}}{{.Name}} {{end}}' 2>/dev/null | grep -q "${NODERED_CONTAINER}"; then - log "Redan ansluten till bridge" + log "Already connected to bridge" else - docker network connect bridge "${NODERED_CONTAINER}" 2>/dev/null || warn "Kunde inte ansluta bridge — kontrollera manuellt" + docker network connect bridge "${NODERED_CONTAINER}" 2>/dev/null || warn "Could not connect bridge — check manually" fi } rebuild_nodered() { - log "Bygger om ${NODERED_CONTAINER} (samma instans, port ${NODERED_PORT})..." + log "Rebuilding ${NODERED_CONTAINER} (same instance, port ${NODERED_PORT})..." fix_nodered_build_permissions verify_build_context if [ "${FORCE_REBUILD:-0}" = "1" ]; then @@ -338,36 +338,36 @@ rebuild_nodered() { } wait_nodered() { - log "Väntar på Node-RED :${NODERED_PORT}..." + 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 svarar på http://127.0.0.1:${NODERED_PORT}" + log "Node-RED responding at http://127.0.0.1:${NODERED_PORT}" return 0 fi sleep 2 done - warn "Node-RED svarade inte inom 60 s" + warn "Node-RED did not respond within 60 s" } verify_code_from_nodered() { local code_ip code_ip="$(code_bridge_ip)" [ -n "${code_ip}" ] || code_ip="${COLLABORA_IP}" - # CODE lyssnar på HTTPS internt (HTTP ger tom svar) + # CODE listens on HTTPS internally (HTTP returns empty reply) local url="https://${code_ip}:9980/hosting/capabilities" - log "Testar CODE från ${NODERED_CONTAINER}: ${url}" + log "Testing CODE from ${NODERED_CONTAINER}: ${url}" if docker exec "${NODERED_CONTAINER}" curl -sfk "${url}" >/dev/null 2>&1; then - log "OK: CODE nås från befintlig Node-RED-container" + log "OK: CODE reachable from Node-RED container" else - warn "CODE nås inte — kör: docker network connect bridge ${NODERED_CONTAINER}" + warn "CODE not reachable — run: docker network connect bridge ${NODERED_CONTAINER}" warn "nc-collab-config collaboraUrl=https://${code_ip}:9980 (verifyTls=false)" fi } main() { resolve_paths - log "Integrerar Collabora-noder i befintlig nextcloud-node-red" - log "Paket: ${PKG_SRC}" + 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 @@ -388,18 +388,18 @@ main() { cat <