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.
This commit is contained in:
+1
-1
@@ -176,7 +176,7 @@ Intern CODE körs med TLS och self-signed-cert (`ssl.enable=true`) — därför
|
||||
### createAssetLink (assets)
|
||||
|
||||
`collabora-bridge createAssetLink` / `nc-office assets:create` POSTar form-urlencoded
|
||||
(`path=Dokument/logotyp.png`, relativt användarens filrot) mot
|
||||
(`path=Dokument/OfficeOut/demo-asset.png`, relativt användarens filrot) mot
|
||||
`<nextcloudUrl>/apps/richdocuments/assets`. `200 {url}` = asset-URL skapad;
|
||||
`404` = filen finns inte i användarens rot (eller fel `nextcloudUrl`) — felet innehåller status + svarskropp.
|
||||
|
||||
|
||||
+512
-49
@@ -4,7 +4,7 @@
|
||||
"type": "tab",
|
||||
"label": "NC Collabora — examples",
|
||||
"disabled": false,
|
||||
"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"
|
||||
"info": "Create/edit nc-collab-config (gear): Nextcloud URL, username + app password,\nCollabora intern https://code:9980 (verifyTls av), publik URL t.ex. https://docs.domain.name.\n\nAlla kedjor utgår från filer som FINNS på denna host:\n /Dokument/Example.md, /Dokument/exempel.odt\nMall-id 230 = Invoice.odt (hämtat via templates:list — kör kedjan\n'templates:list → pick → create' om id:n skiljer).\nDestinationer landar i /Dokument/OfficeOut/ (MKCOL sker tyst).\n\nKedjor:\n 1. capabilities + discovery (urlsrc skrivs om till publik bas)\n 2. ncFileToPdf (/Dokument/Example.md)\n 3. ncFileToPng → createAssetLink (png:n skapas först i kedjan)\n 4. document:direct mot befintlig fil (PROPFIND fileId)\n 5. htmlToOffice\n 6. templates:create explicit (msg.template + msg.path)\n 7. templates:list → pick → create → extract/fill/transform/extractFields\n 8. compareVersionsPdf: två kopior skapade först via templates:create\n\nSe docs/NODES.md"
|
||||
},
|
||||
{
|
||||
"id": "nc_collab_cfg",
|
||||
@@ -12,21 +12,22 @@
|
||||
"name": "cloud.domain.name",
|
||||
"nextcloudUrl": "https://cloud.domain.name",
|
||||
"collaboraUrl": "https://code:9980",
|
||||
"collaboraPublicUrl": "https://cloud.domain.name",
|
||||
"collaboraPublicUrl": "https://docs.domain.name",
|
||||
"username": "FILL_IN_USER",
|
||||
"verifyTls": false
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_capabilities",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "1. CODE capabilities",
|
||||
"name": "1a. CODE capabilities",
|
||||
"props": [],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 150,
|
||||
"x": 160,
|
||||
"y": 80,
|
||||
"wires": [["wopi_cap"]]
|
||||
},
|
||||
@@ -37,7 +38,7 @@
|
||||
"name": "capabilities",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "capabilities",
|
||||
"x": 380,
|
||||
"x": 400,
|
||||
"y": 80,
|
||||
"wires": [["dbg_cap"]]
|
||||
},
|
||||
@@ -51,28 +52,66 @@
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "payload",
|
||||
"x": 590,
|
||||
"x": 620,
|
||||
"y": 80,
|
||||
"wires": []
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_discovery",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "1b. discovery (publik rewrite)",
|
||||
"props": [],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 170,
|
||||
"y": 140,
|
||||
"wires": [["wopi_disc"]]
|
||||
},
|
||||
{
|
||||
"id": "wopi_disc",
|
||||
"type": "collabora-wopi",
|
||||
"z": "collab_tab",
|
||||
"name": "discovery",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "discovery",
|
||||
"x": 400,
|
||||
"y": 140,
|
||||
"wires": [["dbg_disc"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_disc",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "urlsrc ska peka på publik bas",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "payload",
|
||||
"x": 640,
|
||||
"y": 140,
|
||||
"wires": []
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_pdf",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "2. NC-fil → PDF",
|
||||
"name": "2. Example.md → PDF",
|
||||
"props": [
|
||||
{
|
||||
"p": "ncPath",
|
||||
"v": "/Dokument/test.docx",
|
||||
"vt": "str"
|
||||
}
|
||||
{ "p": "ncPath", "v": "/Dokument/Example.md", "vt": "str" },
|
||||
{ "p": "destName", "v": "Example.pdf", "vt": "str" }
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 150,
|
||||
"y": 160,
|
||||
"x": 160,
|
||||
"y": 220,
|
||||
"wires": [["bridge_pdf"]]
|
||||
},
|
||||
{
|
||||
@@ -82,8 +121,8 @@
|
||||
"name": "ncFileToPdf",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "ncFileToPdf",
|
||||
"x": 380,
|
||||
"y": 160,
|
||||
"x": 400,
|
||||
"y": 220,
|
||||
"wires": [["dbg_pdf"]]
|
||||
},
|
||||
{
|
||||
@@ -96,28 +135,91 @@
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "destNcPath",
|
||||
"x": 590,
|
||||
"y": 160,
|
||||
"x": 620,
|
||||
"y": 220,
|
||||
"wires": []
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_editor",
|
||||
"id": "inj_png_asset",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "3. Open in Office",
|
||||
"name": "3. exempel.odt → PNG → asset-länk",
|
||||
"props": [
|
||||
{
|
||||
"p": "ncPath",
|
||||
"v": "/Dokument/test.docx",
|
||||
"vt": "str"
|
||||
}
|
||||
{ "p": "ncPath", "v": "/Dokument/exempel.odt", "vt": "str" },
|
||||
{ "p": "destName", "v": "demo-asset.png", "vt": "str" }
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 150,
|
||||
"y": 240,
|
||||
"x": 190,
|
||||
"y": 300,
|
||||
"wires": [["bridge_png"]]
|
||||
},
|
||||
{
|
||||
"id": "bridge_png",
|
||||
"type": "collabora-bridge",
|
||||
"z": "collab_tab",
|
||||
"name": "ncFileToPng",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "ncFileToPng",
|
||||
"x": 410,
|
||||
"y": 300,
|
||||
"wires": [["fn_asset_path"]]
|
||||
},
|
||||
{
|
||||
"id": "fn_asset_path",
|
||||
"type": "function",
|
||||
"z": "collab_tab",
|
||||
"name": "peka ncPath på nya png:en",
|
||||
"func": "if (!msg.destNcPath) { return null; }\nmsg.ncPath = msg.destNcPath;\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"noerr": 0,
|
||||
"x": 630,
|
||||
"y": 300,
|
||||
"wires": [["bridge_asset"]]
|
||||
},
|
||||
{
|
||||
"id": "bridge_asset",
|
||||
"type": "collabora-bridge",
|
||||
"z": "collab_tab",
|
||||
"name": "createAssetLink",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "createAssetLink",
|
||||
"x": 860,
|
||||
"y": 300,
|
||||
"wires": [["dbg_asset"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_asset",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "assetUrl",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "assetUrl",
|
||||
"x": 1080,
|
||||
"y": 300,
|
||||
"wires": []
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_direct",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "4. document:direct (befintlig fil)",
|
||||
"props": [
|
||||
{ "p": "ncPath", "v": "/Dokument/exempel.odt", "vt": "str" }
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 190,
|
||||
"y": 380,
|
||||
"wires": [["office_direct"]]
|
||||
},
|
||||
{
|
||||
@@ -127,8 +229,8 @@
|
||||
"name": "document:direct",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "document:direct",
|
||||
"x": 380,
|
||||
"y": 240,
|
||||
"x": 420,
|
||||
"y": 380,
|
||||
"wires": [["dbg_editor"]]
|
||||
},
|
||||
{
|
||||
@@ -141,53 +243,414 @@
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "editorUrl",
|
||||
"x": 590,
|
||||
"y": 240,
|
||||
"x": 640,
|
||||
"y": 380,
|
||||
"wires": []
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_extract",
|
||||
"id": "inj_html",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "4. Template fields",
|
||||
"name": "5. HTML → PDF",
|
||||
"props": [
|
||||
{
|
||||
"p": "ncPath",
|
||||
"v": "/Mallar/avtal.docx",
|
||||
"vt": "str"
|
||||
}
|
||||
{ "p": "payload", "v": "<!doctype html><html><body><h1>Rapport</h1><p>Skapad av Node-RED mot Collabora CODE.</p></body></html>", "vt": "str" },
|
||||
{ "p": "filename", "v": "rapport.html", "vt": "str" },
|
||||
{ "p": "format", "v": "pdf", "vt": "str" },
|
||||
{ "p": "destName", "v": "rapport-demo.pdf", "vt": "str" }
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 150,
|
||||
"y": 320,
|
||||
"wires": [["bridge_extract"]]
|
||||
"y": 460,
|
||||
"wires": [["bridge_html"]]
|
||||
},
|
||||
{
|
||||
"id": "bridge_html",
|
||||
"type": "collabora-bridge",
|
||||
"z": "collab_tab",
|
||||
"name": "htmlToOffice",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "htmlToOffice",
|
||||
"x": 410,
|
||||
"y": 460,
|
||||
"wires": [["dbg_html"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_html",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "destNcPath",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "destNcPath",
|
||||
"x": 630,
|
||||
"y": 460,
|
||||
"wires": []
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_tpl_explicit",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "6. skapa från mall 230 (Invoice)",
|
||||
"props": [
|
||||
{ "p": "template", "v": 230, "vt": "num" },
|
||||
{ "p": "path", "v": "/Dokument/OfficeOut/fran-mall", "vt": "str" },
|
||||
{ "p": "templateExtension", "v": "odt", "vt": "str" }
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 180,
|
||||
"y": 540,
|
||||
"wires": [["office_tpl_create1"]]
|
||||
},
|
||||
{
|
||||
"id": "office_tpl_create1",
|
||||
"type": "nc-office",
|
||||
"z": "collab_tab",
|
||||
"name": "templates:create (path+template)",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "templates:create",
|
||||
"x": 450,
|
||||
"y": 540,
|
||||
"wires": [["fn_created_direct"]]
|
||||
},
|
||||
{
|
||||
"id": "fn_created_direct",
|
||||
"type": "function",
|
||||
"z": "collab_tab",
|
||||
"name": "använd skapad fil",
|
||||
"func": "if (!msg.createdPath) { return null; }\nmsg.ncPath = msg.createdPath;\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"noerr": 0,
|
||||
"x": 700,
|
||||
"y": 540,
|
||||
"wires": [["office_extract_fields"]]
|
||||
},
|
||||
{
|
||||
"id": "office_extract_fields",
|
||||
"type": "nc-office",
|
||||
"z": "collab_tab",
|
||||
"name": "extractFields (fileId via PROPFIND)",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "template:extractFields",
|
||||
"x": 950,
|
||||
"y": 540,
|
||||
"wires": [["dbg_tpl_fields"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_tpl_fields",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "fields (tom lista är OK)",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "payload",
|
||||
"x": 1200,
|
||||
"y": 540,
|
||||
"wires": []
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_tpl_chain",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "7a. lista mallar",
|
||||
"props": [],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 150,
|
||||
"y": 640,
|
||||
"wires": [["office_tpl_list"]]
|
||||
},
|
||||
{
|
||||
"id": "office_tpl_list",
|
||||
"type": "nc-office",
|
||||
"z": "collab_tab",
|
||||
"name": "templates:list document",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "templates:list",
|
||||
"x": 380,
|
||||
"y": 640,
|
||||
"wires": [["fn_pick_template"]]
|
||||
},
|
||||
{
|
||||
"id": "fn_pick_template",
|
||||
"type": "function",
|
||||
"z": "collab_tab",
|
||||
"name": "pick Invoice/Letter (inte Empty)",
|
||||
"func": "const list = Array.isArray(msg.payload) ? msg.payload : (msg.payload && msg.payload.data) || [];\nconst docs = list.filter(t => t && t.type === 'document' && !/^empty/i.test(String(t.name || '')));\nconst pick = docs.find(t => /invoice/i.test(t.name)) || docs.find(t => /letter/i.test(t.name)) || docs[0];\nif (!pick) {\n throw new Error('Ingen document-mall hittad (forvantade Invoice/Letter, inte Empty) - kor templates:list forst');\n}\n// Extension fran mallens NAMN (Invoice.odt -> odt) speglar verkligt innehall;\n// 'extension'-faltet kan avvika nar NC doc_format=ooxml.\nconst nameExt = (String(pick.name || '').match(/\\.([A-Za-z0-9]+)$/) || [])[1];\nconst ext = nameExt || pick.extension || 'odt';\nmsg.templateList = list;\nmsg.template = pick.id;\nmsg.templateName = pick.name;\nmsg.templateExtension = ext;\nmsg.path = '/Dokument/OfficeOut/demo-mall.' + ext;\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"noerr": 0,
|
||||
"x": 610,
|
||||
"y": 640,
|
||||
"wires": [["office_tpl_create2"]]
|
||||
},
|
||||
{
|
||||
"id": "office_tpl_create2",
|
||||
"type": "nc-office",
|
||||
"z": "collab_tab",
|
||||
"name": "templates:create demo-mall",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "templates:create",
|
||||
"x": 850,
|
||||
"y": 640,
|
||||
"wires": [["fn_use_created"]]
|
||||
},
|
||||
{
|
||||
"id": "fn_use_created",
|
||||
"type": "function",
|
||||
"z": "collab_tab",
|
||||
"name": "prep: ncPath/fileId/fields {}",
|
||||
"func": "if (!msg.createdPath) { return null; }\nmsg.ncPath = msg.createdPath;\nmsg.fileId = undefined;\nmsg.fields = {};\nmsg.transform = {};\nmsg.destNcPath = '/Dokument/OfficeOut/demo-mall-ifylld.' + (msg.templateExtension || 'odt');\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"noerr": 0,
|
||||
"x": 1090,
|
||||
"y": 640,
|
||||
"wires": [
|
||||
["bridge_extract"],
|
||||
["office_extract2"],
|
||||
["bridge_fill"],
|
||||
["node_transform"]
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "bridge_extract",
|
||||
"type": "collabora-bridge",
|
||||
"z": "collab_tab",
|
||||
"name": "extractToPayload",
|
||||
"name": "extract struktur",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "extractToPayload",
|
||||
"x": 390,
|
||||
"y": 320,
|
||||
"wires": [["dbg_fields"]]
|
||||
"x": 1330,
|
||||
"y": 560,
|
||||
"wires": [["dbg_structure"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_fields",
|
||||
"id": "dbg_structure",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "fields / structure",
|
||||
"name": "structure",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "fields",
|
||||
"x": 610,
|
||||
"y": 320,
|
||||
"complete": "structure",
|
||||
"x": 1550,
|
||||
"y": 560,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "office_extract2",
|
||||
"type": "nc-office",
|
||||
"z": "collab_tab",
|
||||
"name": "extractFields (OCS)",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "template:extractFields",
|
||||
"x": 1320,
|
||||
"y": 620,
|
||||
"wires": [["dbg_ocs_fields"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_ocs_fields",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "OCS fields",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "payload",
|
||||
"x": 1540,
|
||||
"y": 620,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "bridge_fill",
|
||||
"type": "collabora-bridge",
|
||||
"z": "collab_tab",
|
||||
"name": "fillTemplateSave {}",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "fillTemplateSave",
|
||||
"x": 1320,
|
||||
"y": 680,
|
||||
"wires": [["dbg_fill"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_fill",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "ifylld destNcPath",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "destNcPath",
|
||||
"x": 1550,
|
||||
"y": 680,
|
||||
"wires": []
|
||||
},
|
||||
{
|
||||
"id": "node_transform",
|
||||
"type": "collabora-transform",
|
||||
"z": "collab_tab",
|
||||
"name": "transform {}",
|
||||
"config": "nc_collab_cfg",
|
||||
"x": 1310,
|
||||
"y": 740,
|
||||
"wires": [["dbg_transform"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_transform",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "transform buffer",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "contentType",
|
||||
"x": 1540,
|
||||
"y": 740,
|
||||
"wires": []
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_compare_a",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "8a. skapa kopia A",
|
||||
"props": [
|
||||
{ "p": "template", "v": 230, "vt": "num" },
|
||||
{ "p": "path", "v": "/Dokument/OfficeOut/demo-a.odt", "vt": "str" }
|
||||
],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 160,
|
||||
"y": 860,
|
||||
"wires": [["office_cmp_a"]]
|
||||
},
|
||||
{
|
||||
"id": "office_cmp_a",
|
||||
"type": "nc-office",
|
||||
"z": "collab_tab",
|
||||
"name": "templates:create A",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "templates:create",
|
||||
"x": 420,
|
||||
"y": 860,
|
||||
"wires": [["fn_to_b"]]
|
||||
},
|
||||
{
|
||||
"id": "fn_to_b",
|
||||
"type": "function",
|
||||
"z": "collab_tab",
|
||||
"name": "byt path till B",
|
||||
"func": "if (!msg.createdPath) { return null; }\nmsg.path = '/Dokument/OfficeOut/demo-b.odt';\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"noerr": 0,
|
||||
"x": 640,
|
||||
"y": 860,
|
||||
"wires": [["office_cmp_b"]]
|
||||
},
|
||||
{
|
||||
"id": "office_cmp_b",
|
||||
"type": "nc-office",
|
||||
"z": "collab_tab",
|
||||
"name": "templates:create B",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "templates:create",
|
||||
"x": 880,
|
||||
"y": 860,
|
||||
"wires": [["fn_compare_setup"]]
|
||||
},
|
||||
{
|
||||
"id": "fn_compare_setup",
|
||||
"type": "function",
|
||||
"z": "collab_tab",
|
||||
"name": "sätt A/B + dest",
|
||||
"func": "if (!msg.createdPath) { return null; }\nmsg.ncPath = '/Dokument/OfficeOut/demo-a.odt';\nmsg.compareNcPath = '/Dokument/OfficeOut/demo-b.odt';\nmsg.destNcPath = '/Dokument/OfficeOut/demo-diff.pdf';\nreturn msg;",
|
||||
"outputs": 1,
|
||||
"noerr": 0,
|
||||
"x": 1110,
|
||||
"y": 860,
|
||||
"wires": [["bridge_compare"]]
|
||||
},
|
||||
{
|
||||
"id": "bridge_compare",
|
||||
"type": "collabora-bridge",
|
||||
"z": "collab_tab",
|
||||
"name": "compareVersionsPdf",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "compareVersionsPdf",
|
||||
"x": 1350,
|
||||
"y": 860,
|
||||
"wires": [["dbg_diff"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_diff",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "diff destNcPath",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "destNcPath",
|
||||
"x": 1570,
|
||||
"y": 860,
|
||||
"wires": []
|
||||
},
|
||||
|
||||
{
|
||||
"id": "inj_pick_demo",
|
||||
"type": "inject",
|
||||
"z": "collab_tab",
|
||||
"name": "9. hitta exempelfil (pickDemoSource)",
|
||||
"props": [],
|
||||
"repeat": "",
|
||||
"crontab": "",
|
||||
"once": false,
|
||||
"topic": "",
|
||||
"x": 190,
|
||||
"y": 960,
|
||||
"wires": [["bridge_pick"]]
|
||||
},
|
||||
{
|
||||
"id": "bridge_pick",
|
||||
"type": "collabora-bridge",
|
||||
"z": "collab_tab",
|
||||
"name": "pickDemoSource",
|
||||
"config": "nc_collab_cfg",
|
||||
"operation": "pickDemoSource",
|
||||
"x": 430,
|
||||
"y": 960,
|
||||
"wires": [["dbg_pick"]]
|
||||
},
|
||||
{
|
||||
"id": "dbg_pick",
|
||||
"type": "debug",
|
||||
"z": "collab_tab",
|
||||
"name": "kandidater + vald ncPath",
|
||||
"active": true,
|
||||
"tosidebar": true,
|
||||
"console": false,
|
||||
"tostatus": false,
|
||||
"complete": "picked",
|
||||
"x": 670,
|
||||
"y": 960,
|
||||
"wires": []
|
||||
}
|
||||
]
|
||||
|
||||
+23
-1
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const { webdavGet, webdavPut, webdavPropfindFileId } = require('./webdav');
|
||||
const { webdavGet, webdavPut, webdavPropfindFileId, listUserExamples } = require('./webdav');
|
||||
const { ocsRequest } = require('./ocs');
|
||||
const { requestBuffer } = require('./http-client');
|
||||
const { convertTo, extractStructure, transformStructure } = require('./collabora');
|
||||
@@ -50,6 +50,27 @@ async function loadSourceBuffer(config, msg) {
|
||||
return file;
|
||||
}
|
||||
|
||||
// Bridge-op "pickDemoSource": slå upp en fil som FAKTISKT finns hos användaren
|
||||
// (/Dokument först, sedan /Documents) och lägg den på msg.ncPath. Endast för
|
||||
// demo/generator-flöden — ingen silent fallback inne i convert-operationer.
|
||||
async function pickDemoSource(config, msg) {
|
||||
const examples = await listUserExamples(config);
|
||||
if (!examples.length) {
|
||||
throw new Error(
|
||||
'Ingen exempelfil hittad i /Dokument eller /Documents — ladda upp en .md/.odt/.docx ' +
|
||||
'eller ange msg.ncPath manuellt.'
|
||||
);
|
||||
}
|
||||
msg.demoSources = examples.map((e) => e.ncPath);
|
||||
if (!pickMsgField(msg, 'ncPath')) {
|
||||
msg.ncPath = examples[0].ncPath;
|
||||
}
|
||||
return {
|
||||
payload: examples,
|
||||
picked: msg.ncPath
|
||||
};
|
||||
}
|
||||
|
||||
async function saveResult(config, msg, buffer, format, sourceNcPath) {
|
||||
const destNcPath = assertSafeDestination(
|
||||
resolveDestNcPath(msg, sourceNcPath, format),
|
||||
@@ -266,6 +287,7 @@ module.exports = {
|
||||
compareVersionsPdf,
|
||||
extractToPayload,
|
||||
createAssetLink,
|
||||
pickDemoSource,
|
||||
loadSourceBuffer,
|
||||
saveResult,
|
||||
resolveFileId
|
||||
|
||||
+17
-5
@@ -24,10 +24,13 @@ function parseOcsBody(bodyBuffer) {
|
||||
const json = JSON.parse(text);
|
||||
const ocs = json.ocs || json;
|
||||
const meta = ocs.meta || {};
|
||||
const statuscode = meta.statuscode ?? meta.statusCode ?? 200;
|
||||
const statuscode = Number(meta.statuscode ?? meta.statusCode ?? 200);
|
||||
if (statuscode >= 400) {
|
||||
const message = meta.message || meta.status || text.slice(0, 200);
|
||||
throw new Error(`OCS ${statuscode}: ${message}`);
|
||||
// 996 = intern serverfel, 998 = not found m.m. — inkludera alltid
|
||||
// OCS-bodyn så felet går att felsöka utan logggrävning.
|
||||
const message = meta.message || meta.status || '';
|
||||
const raw = text.slice(0, 300);
|
||||
throw new Error(`OCS ${statuscode}: ${message}${message && raw !== message ? ` (${raw})` : raw}`);
|
||||
}
|
||||
return {
|
||||
statusCode: statuscode,
|
||||
@@ -38,7 +41,7 @@ function parseOcsBody(bodyBuffer) {
|
||||
if (err.message.startsWith('OCS ')) {
|
||||
throw err;
|
||||
}
|
||||
throw new Error(`OCS-svar kunde inte parsas: ${text.slice(0, 200)}`);
|
||||
throw new Error(`OCS-svar kunde inte parsas (HTTP-body): ${text.slice(0, 200)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +80,18 @@ async function ocsRequest(config, { method = 'GET', path, query, body, headers =
|
||||
throw new Error(`OCS ${res.statusCode}: kontrollera app-lösenord`);
|
||||
}
|
||||
|
||||
// OCS-fel (996/998/…) kommer med HTTP 4xx/5xx men har parsbar meta-body —
|
||||
// försök alltid parsa först så felet innehåller OCS-meddelandet.
|
||||
const parsed = parseOcsBody(res.body);
|
||||
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
const bodyText = res.body.toString('utf8').slice(0, 200);
|
||||
throw new Error(`OCS-anrop misslyckades (HTTP ${res.statusCode}) för ${path}: ${bodyText || '<tom body>'}`);
|
||||
}
|
||||
|
||||
return {
|
||||
httpStatus: res.statusCode,
|
||||
...parseOcsBody(res.body)
|
||||
...parsed
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+6
-1
@@ -60,7 +60,12 @@ function resolveDestNcPath(msg, sourceNcPath, format) {
|
||||
if (msg.destFolder || msg.destName) {
|
||||
const folder = normalizeNcPath(msg.destFolder || DEFAULT_OUTPUT_FOLDER);
|
||||
const folderWithSlash = folder.endsWith('/') ? folder : folder + '/';
|
||||
const name = msg.destName || replaceExtension(basenameFromNcPath(sourceNcPath), format || 'bin');
|
||||
let name = msg.destName || replaceExtension(basenameFromNcPath(sourceNcPath), format || 'bin');
|
||||
// Rätt filändelse tvingas in — annars landar filer utan ändelse i NC.
|
||||
const fmt = String(format || '').toLowerCase();
|
||||
if (fmt && !new RegExp(`\\.${fmt}$`, 'i').test(name)) {
|
||||
name = replaceExtension(name, fmt);
|
||||
}
|
||||
return normalizeNcPath(folderWithSlash + name);
|
||||
}
|
||||
return defaultDestNcPath(sourceNcPath, format);
|
||||
|
||||
+82
-2
@@ -41,7 +41,11 @@ async function webdavGet(config, ncPath) {
|
||||
});
|
||||
|
||||
if (res.statusCode === 404) {
|
||||
throw new Error(`WebDAV 404: filen finns inte: ${normalizeNcPath(ncPath)}`);
|
||||
throw new Error(
|
||||
`WebDAV 404: filen finns inte: ${normalizeNcPath(ncPath)} — ` +
|
||||
'ange msg.ncPath till en fil som finns; defaults är /Dokument/Example.md ' +
|
||||
'eller en mall via templates:list (se bridge-op pickDemoSource).'
|
||||
);
|
||||
}
|
||||
if (res.statusCode === 401 || res.statusCode === 403) {
|
||||
throw new Error(`WebDAV ${res.statusCode}: kontrollera app-lösenord och användare`);
|
||||
@@ -134,6 +138,12 @@ async function webdavPropfindFileId(config, ncPath) {
|
||||
rejectUnauthorized: tlsOptions(config).rejectUnauthorized
|
||||
});
|
||||
|
||||
if (res.statusCode === 404) {
|
||||
throw new Error(
|
||||
`PROPFIND 404: ${normalizeNcPath(ncPath)} finns inte — ` +
|
||||
'ange msg.ncPath till en fil som finns (t.ex. /Dokument/Example.md).'
|
||||
);
|
||||
}
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
throw new Error(`PROPFIND misslyckades (${res.statusCode}) för ${normalizeNcPath(ncPath)}`);
|
||||
}
|
||||
@@ -146,10 +156,80 @@ async function webdavPropfindFileId(config, ncPath) {
|
||||
return parseInt(match[1], 10);
|
||||
}
|
||||
|
||||
// Discovery av riktiga defaults: PROPFIND /Dokument och /Documents (Depth 1),
|
||||
// returnera kandidater (.md/.odt/.docx) i prioritetsordning. Används BARA av
|
||||
// example-flow-generator / bridge-op pickDemoSource — aldrig inne i convert.
|
||||
async function listUserExamples(config, folders) {
|
||||
const candidates = folders || ['/Dokument', '/Documents'];
|
||||
const found = [];
|
||||
const wanted = /\.(md|odt|docx)$/i;
|
||||
|
||||
for (const folder of candidates) {
|
||||
let res;
|
||||
try {
|
||||
res = await requestBuffer({
|
||||
url: webDavUrl(config, folder),
|
||||
method: 'PROPFIND',
|
||||
headers: {
|
||||
Authorization: authHeader(config),
|
||||
Depth: '1',
|
||||
'Content-Type': 'application/xml; charset=utf-8'
|
||||
},
|
||||
body: '<?xml version="1.0" encoding="UTF-8"?><d:propfind xmlns:d="DAV:"/>',
|
||||
rejectUnauthorized: tlsOptions(config).rejectUnauthorized
|
||||
});
|
||||
} catch (err) {
|
||||
continue; // mapp finns ej — prova nästa
|
||||
}
|
||||
if (res.statusCode < 200 || res.statusCode >= 300) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const text = res.body.toString('utf8');
|
||||
const responses = text.split('<d:response>').slice(1);
|
||||
for (const chunk of responses) {
|
||||
const hrefMatch = chunk.match(/<d:href>([^<]+)<\/d:href>/i);
|
||||
if (!hrefMatch) {
|
||||
continue;
|
||||
}
|
||||
let href;
|
||||
try {
|
||||
href = decodeURIComponent(hrefMatch[1]);
|
||||
} catch {
|
||||
href = hrefMatch[1];
|
||||
}
|
||||
// href: /remote.php/dav/files/<user>/Dokument/exempel.odt → ncPath
|
||||
const marker = `/files/${config.username}/`;
|
||||
const idx = href.indexOf(marker);
|
||||
if (idx === -1) {
|
||||
continue;
|
||||
}
|
||||
const ncPath = normalizeNcPath(href.substring(idx + marker.length));
|
||||
if (!wanted.test(ncPath)) {
|
||||
continue;
|
||||
}
|
||||
const isCollection = /<d:collection\s*\/?>/i.test(chunk);
|
||||
if (isCollection) {
|
||||
continue;
|
||||
}
|
||||
found.push({ ncPath, folder: normalizeNcPath(folder), name: filenameFromPath(ncPath) });
|
||||
}
|
||||
}
|
||||
|
||||
const priority = { md: 0, odt: 1, docx: 2 };
|
||||
found.sort((a, b) => {
|
||||
const extA = a.ncPath.split('.').pop().toLowerCase();
|
||||
const extB = b.ncPath.split('.').pop().toLowerCase();
|
||||
return (priority[extA] ?? 9) - (priority[extB] ?? 9);
|
||||
});
|
||||
return found;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
webDavUrl,
|
||||
webdavGet,
|
||||
webdavPut,
|
||||
webdavPropfindFileId,
|
||||
ensureFolder
|
||||
ensureFolder,
|
||||
listUserExamples
|
||||
};
|
||||
|
||||
@@ -11,7 +11,8 @@ const OPERATIONS = {
|
||||
fillTemplateSave: bridge.fillTemplateSave,
|
||||
compareVersionsPdf: bridge.compareVersionsPdf,
|
||||
extractToPayload: bridge.extractToPayload,
|
||||
createAssetLink: bridge.createAssetLink
|
||||
createAssetLink: bridge.createAssetLink,
|
||||
pickDemoSource: bridge.pickDemoSource
|
||||
};
|
||||
|
||||
module.exports = function (RED) {
|
||||
|
||||
@@ -4,6 +4,24 @@ const { getConfig, setError, setSuccess, clearStatus } = require('../lib/utils')
|
||||
const { getCapabilities, getDiscovery } = require('../lib/collabora');
|
||||
const { requestBuffer } = require('../lib/http-client');
|
||||
|
||||
// Discovery urlsrc/favIconUrl pekar ofta på CODE:s interna host (t.ex.
|
||||
// https://172.17.0.2:9980). Om en publik bas är satt (collaboraPublicUrl)
|
||||
// skrivs hosten om så att browser/iframes inte går mot bridge-IP:t.
|
||||
function rewriteDiscoveryHosts(xml, internalBase, publicBase) {
|
||||
if (!xml || !publicBase || !internalBase) {
|
||||
return xml;
|
||||
}
|
||||
let internalOrigin;
|
||||
try {
|
||||
internalOrigin = new URL(internalBase).origin;
|
||||
} catch {
|
||||
return xml;
|
||||
}
|
||||
const escaped = internalOrigin.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const publicOrigin = String(publicBase).replace(/\/+$/, '');
|
||||
return xml.replace(new RegExp(escaped, 'g'), publicOrigin);
|
||||
}
|
||||
|
||||
module.exports = function (RED) {
|
||||
function CollaboraWopiNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
@@ -24,6 +42,8 @@ module.exports = function (RED) {
|
||||
msg.payload = await getCapabilities(cfg);
|
||||
} else if (op === 'discovery') {
|
||||
msg.payload = await getDiscovery(cfg);
|
||||
const publicBase = cfg.collaboraPublicUrl || '';
|
||||
msg.payload = rewriteDiscoveryHosts(msg.payload, cfg.collaboraUrl, publicBase);
|
||||
} else if (op === 'buildEditor') {
|
||||
const publicBase = cfg.collaboraPublicUrl || cfg.collaboraUrl;
|
||||
const wopiSrc = encodeURIComponent(msg.wopiSrc || msg.WOPISrc || '');
|
||||
|
||||
+67
-7
@@ -4,15 +4,20 @@ const { getConfig, setError, setSuccess, clearStatus, pickMsgField } = require('
|
||||
const { ocsRequest } = require('../lib/ocs');
|
||||
const bridge = require('../lib/bridge');
|
||||
const { resolveFileId } = bridge;
|
||||
const { webdavGet, webdavPut } = require('../lib/webdav');
|
||||
const { webdavGet, webdavPut, ensureFolder, webdavPropfindFileId } = require('../lib/webdav');
|
||||
const { convertTo } = require('../lib/collabora');
|
||||
const {
|
||||
resolveDestNcPath,
|
||||
assertSafeDestination,
|
||||
contentTypeForFormat,
|
||||
normalizeNcPath
|
||||
normalizeNcPath,
|
||||
DEFAULT_OUTPUT_FOLDER
|
||||
} = require('../lib/utils');
|
||||
|
||||
function hasExtension(p) {
|
||||
return /\.[^/.]+$/.test(String(p).replace(/\/+$/, ''));
|
||||
}
|
||||
|
||||
module.exports = function (RED) {
|
||||
function NcOfficeNode(config) {
|
||||
RED.nodes.createNode(this, config);
|
||||
@@ -41,16 +46,69 @@ module.exports = function (RED) {
|
||||
break;
|
||||
}
|
||||
case 'templates:create': {
|
||||
// richdocuments OCS#createFromTemplate($path, $template)
|
||||
// POST /ocs/v2.php/apps/richdocuments/api/v1/templates/new
|
||||
const template = pickMsgField(msg, 'template', 'templateId');
|
||||
if (template === undefined || template === null || template === '') {
|
||||
throw new Error('templates:create kräver msg.template (numeriskt id från templates:list)');
|
||||
}
|
||||
|
||||
let path = normalizeNcPath(
|
||||
pickMsgField(msg, 'path', 'destNcPath') ||
|
||||
msg.templatePath ||
|
||||
undefined
|
||||
);
|
||||
if (!path) {
|
||||
const name = msg.destName || msg.fileName;
|
||||
if (!name) {
|
||||
throw new Error('templates:create kräver msg.path eller msg.destFolder+msg.destName');
|
||||
}
|
||||
const folder = normalizeNcPath(msg.destFolder || DEFAULT_OUTPUT_FOLDER);
|
||||
path = normalizeNcPath((folder.endsWith('/') ? folder : folder + '/') + String(name).replace(/^\/+/, ''));
|
||||
}
|
||||
|
||||
// Ärv extension från mallen om målnamnet saknar en.
|
||||
if (!hasExtension(path)) {
|
||||
const ext = pickMsgField(msg, 'templateExtension', 'extension');
|
||||
if (ext) {
|
||||
path += '.' + String(ext).replace(/^\./, '');
|
||||
}
|
||||
}
|
||||
|
||||
// Idempotent: finns filen redan → återanvänd (ingen
|
||||
// "namn (2)"-dubblett via direct editing).
|
||||
try {
|
||||
await webdavPropfindFileId(cfg, path);
|
||||
msg.template = Number(template);
|
||||
msg.path = path;
|
||||
msg.createdPath = path;
|
||||
msg.reused = true;
|
||||
msg.payload = { path, reused: true };
|
||||
setSuccess(node, msg, 'templates:create (återanvänd)');
|
||||
send(msg);
|
||||
done();
|
||||
return;
|
||||
} catch (e) { /* finns inte — skapa nedan */ }
|
||||
|
||||
// Mallifyllning via direct editing kräver att mappen finns.
|
||||
await ensureFolder(cfg, path.substring(0, path.lastIndexOf('/')) || '/');
|
||||
|
||||
result = await ocsRequest(cfg, {
|
||||
method: 'POST',
|
||||
path: '/ocs/v2.php/apps/richdocuments/api/v1/templates/new',
|
||||
body: {
|
||||
templateId: msg.templateId,
|
||||
fileName: msg.fileName || msg.destName,
|
||||
templatePath: msg.templatePath
|
||||
path,
|
||||
template: Number(template)
|
||||
}
|
||||
});
|
||||
msg.payload = result.data;
|
||||
|
||||
msg.template = Number(template);
|
||||
msg.path = path;
|
||||
msg.createdPath = path;
|
||||
if (result.data && typeof result.data === 'object' && result.data.url) {
|
||||
msg.directEditUrl = result.data.url;
|
||||
}
|
||||
msg.payload = { ...result.data, path };
|
||||
break;
|
||||
}
|
||||
case 'template:extractFields': {
|
||||
@@ -80,11 +138,13 @@ module.exports = function (RED) {
|
||||
break;
|
||||
}
|
||||
case 'document:direct': {
|
||||
// richdocuments OCS#createDirect($fileId) binder parametern
|
||||
// per metodnamn — skicka både fileId och fileid (Number).
|
||||
const fileId = await resolveFileId(cfg, msg);
|
||||
result = await ocsRequest(cfg, {
|
||||
method: 'POST',
|
||||
path: '/ocs/v2.php/apps/richdocuments/api/v1/document',
|
||||
body: { fileid: Number(fileId) }
|
||||
body: { fileId: Number(fileId), fileid: Number(fileId) }
|
||||
});
|
||||
msg.fileId = fileId;
|
||||
msg.editorUrl = result.data?.url || result.data;
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
// discover-examples.js — slå upp filer som FAKTISKT finns hos användaren
|
||||
// och skriv ut förslag på defaults till example-flows.
|
||||
//
|
||||
// Usage:
|
||||
// NC_URL=https://cloud.domain.name NC_USER=your-user NC_PASS=app-password \
|
||||
// node scripts/discover-examples.js [COLLABORA_URL] [PUBLIC_URL]
|
||||
//
|
||||
// Kör t.ex. inne i Node-RED-containern:
|
||||
// docker exec nextcloud-node-red sh -c \
|
||||
// 'cd /data/node_modules/node-red-contrib-nextcloud-collabora && \
|
||||
// NC_URL=... NC_USER=... NC_PASS=... node scripts/discover-examples.js'
|
||||
|
||||
const { listUserExamples, webdavPropfindFileId } = require('../lib/webdav');
|
||||
const { getCapabilities } = require('../lib/collabora');
|
||||
|
||||
async function main() {
|
||||
const config = {
|
||||
nextcloudUrl: process.env.NC_URL || 'https://cloud.domain.name',
|
||||
collaboraUrl: process.argv[2] || process.env.COLLABORA_URL || 'https://code:9980',
|
||||
collaboraPublicUrl: process.argv[3] || process.env.COLLABORA_PUBLIC_URL || '',
|
||||
username: process.env.NC_USER,
|
||||
password: process.env.NC_PASS,
|
||||
verifyTls: false
|
||||
};
|
||||
if (!config.username || !config.password) {
|
||||
console.error('Set NC_USER and NC_PASS (app password)');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const examples = await listUserExamples(config);
|
||||
const primary = examples.find((e) => /\.md$/i.test(e.ncPath)) || examples[0];
|
||||
const office = examples.find((e) => /\.odt$/i.test(e.ncPath)) || primary;
|
||||
|
||||
console.log(JSON.stringify({
|
||||
sourceCandidates: examples.map((e) => e.ncPath),
|
||||
suggestedDefaults: {
|
||||
pdfSourceNcPath: primary ? primary.ncPath : '/Dokument/Example.md',
|
||||
pngSourceNcPath: office ? office.ncPath : '/Dokument/exempel.odt',
|
||||
destFolder: '/Dokument/OfficeOut/'
|
||||
},
|
||||
note: 'Mall-id:n hämtas via templates:list (nc-office). Hardkoda aldrig /Mallar/…'
|
||||
}, null, 2));
|
||||
|
||||
if (primary) {
|
||||
try {
|
||||
const fileId = await webdavPropfindFileId(config, primary.ncPath);
|
||||
console.log(`# fileId för ${primary.ncPath}: ${fileId} (document:direct kan använda msg.ncPath direkt)`);
|
||||
} catch (err) {
|
||||
console.error(`# PROPFIND fileId misslyckades: ${err.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await getCapabilities(config);
|
||||
console.log('# CODE capabilities: OK via ' + config.collaboraUrl);
|
||||
} catch (err) {
|
||||
console.error(`# CODE capabilities MISSLYCKADES via ${config.collaboraUrl}: ${err.message}`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -550,11 +550,12 @@ Integrating done — same Node-RED on port ${NODERED_PORT}
|
||||
Create config first (gear → nc-collab-config):
|
||||
Nextcloud: ${nc_url}
|
||||
Collabora: ${COLLABORA_URL} (verifyTls=false — self-signed internt)
|
||||
Public WOPI: ${nc_url}
|
||||
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
|
||||
Example flow: flows/example-flows.json — defaults /Dokument/Example.md,
|
||||
/Dokument/exempel.odt, dest /Dokument/OfficeOut/, mall-id 230 (Invoice.odt).
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user