From fce938b0c2327a92920eecb7a7271bf90cacd20b Mon Sep 17 00:00:00 2001 From: root Date: Thu, 16 Jul 2026 12:12:31 +0000 Subject: [PATCH] fix: unique keyHash in download URL path + 2s reload delay for save callback --- .../433a0593-d3cf-414e-8763-ab5f87cbc75c.docx | Bin 40669 -> 40674 bytes renderer/carbone-templates/registry.json | 2 +- renderer/onlyoffice-service.js | 38 +++++++++++++++--- static/carbone.js | 4 +- static/index.html | 4 +- 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/renderer/carbone-templates/433a0593-d3cf-414e-8763-ab5f87cbc75c.docx b/renderer/carbone-templates/433a0593-d3cf-414e-8763-ab5f87cbc75c.docx index ef2e2993a0b191c59e42912f66b7454c6c27e1d8..234f0709ec1e72445e2b8f7468ec0488836b717a 100644 GIT binary patch delta 2227 zcmZ9O2{e@Z8^>qHBs3c#)+w`yRFNFd0+O-iuq2-o0ZOn$Ydz^647ufzjoM)mEPj6OfBEE?L!is=YAB`i z!hd#(hj7Ukvh`fGMg<`4LL^ktXN*HN4x(};WNL!kBt7g%jowWObwPTAX z|DfLv^2qekqH$oWrYHObi(6k>*_cX%U~5kv^R!7Ly*ou$f+lAjE@fmc?Fv|T(UH?% zi+P$M$^Jw3NfX?qg7F9Ht?{ba)&3z^ybXQ`en!HtNB6wjd`BpTqLaU&sqsFHO&oS? zdKO{Dh7FW!MpX`5x5qtFh*rFRJX6S|hhixp+cjX)Q1gVj+i1<8C2y@2`sxva0)!MQNld`Xd&PefMUJ3)wWHMHW2d(5MceFhbBFZ)l8fH^ z*$AqB@;`9l%es0oR}FW?kkhqg@;{plMyPlmm8~84*sT~wj)m3WkCQM#DEJJP6{hFn z_YRj$3b+C^|Au8%55-Oor8`9iCf|stXL$!+u8Jw!OuOM*u1{vex8tnmh)t6|C3v;( zcW8{mxNzBS<$!hDn*uZ~z{}mV?#;O6+r+E;pK?((j)uNydfi+?qey@QF(Z-4%5e(M z>@ZU&XkJzy5I?6%DeZ4mOK6+BXF7&05b)8zKG8T*^FjG*s~E;ES=XnMxaT!f?yK%H zO+v1gp56a5?~~wsg0$EMF`Z-`?Xs`8xO==I?+8XTIgDB~=Ut|I19{r)d7bEm@LJ*} zF|St+?|bi4?^Jm97)7qU@pydFLs{G)rLhT7`jOQePvrcyTs>@sl=Qv5wm5CS1Z}M2 z@z_1VbC)`gd9TYCi5wb<8zhe4Vx8ng+6Jk2 z7V%@F^G+D2i|7cmmbmNugj`?Gahy4~y%WupTgCY#oaz3JgVGVw&aGiR%ICar$EEh= zRQ(uJEAX4B%X;U!TZ)_quhuTq#myg>v{@MJn!9Nm;uweMr97`s%5lfDQd2#-%bx-P z^i_53(DMKzbC48IoU&b~A1deHP1V?qvu$N^H`p+&v1ANE>ZA{ze{nWrR%_#w3jDwN zCZk@Z*~WP|H{Icwmj@4Wrh6Lflqa?};{98PgWYqM49==Ay>i{Pyyn&WGO$p->gf$c zwMu_)`;gPZ^g5;d;6Q`P_uBZ|T`c=st(y=1Xm+QEI{!R1NsMb38U9yM9s|i*jFAOgP8)VIHS;9*$O0MLfEux)C5&oq+=sh zpI~M67m; zY?!n2;;o|;t<3IQIW`40hJAM;*E&Bif|S*h#6nY#c^es8d3n_y+E|=1b%~OH*{l@G z37|#RFe>psdS@-SPNc4>{4+QOc!P7r??5rLGvgi~I3|-WlXu1>e~v$>fFfB5I9|2~ z_({%ygTXup6ZF3zw}9bUlmwU{m?E2#Sy%w@=P45>qo!0PvhY3ZH{|9b=kTPQn9v4= zdXF~y*Jzj&GDlQE^YbQ$%sIt9>dp7sD?akNmxA%5fo-1w>J91XQ{w>YTp-oNE%G*QXEx+#`S$D$e&%>K1 z0-T7c&gJ>sO8%0Nacb)Yte|upq&7;Es^sxhe#s)m5LQ_I0wc`N7bI*W?hBvELMrz5 z6)=X!(0_T{MLz!!`GVQBeAn8WGK8|M8WguA=D9lGkuRfS5^K)nC@9X#m}lw>sUXj( zMw`(AIY)8W?S+QNxrgf+G3c{v3mNm=7sP~-n-ce283#Nisz=4++hJ`nJzdvY4F{+zArwO9D8X8NAK zOMO@0-i4cyqKDkF^P#`*F+)1Uy9bZY5bgupd`;8NEBMnaCuV=)!BJf#lN*$lq--_C zS38`$GO?Lv@I@Ex6TU6}|HWpq@-OWa)|xsA7Elck*g@UGFCeNGrNhDUR$a3M6jfKUizFCPT52fPvRjE6j12k_-P|B_ygfVKhjauqOTHxDd;sd6+DLz3-tm(@!?jLoG}g7`Xv(P;iw{ zHwZliN4^hfr$MzA%MKlgDs0#BAd>xekL-j1Zbo(rZtcd6Xj1S;MgZt1R|NADuX)U= zzz$@>bH*ZV>Si6W_SsBcO6+fW=qAt>vOG+3?>JRCOOldL;XfZviTK#W-|8?H?0y;& z-tDQ~4|O3$>I4VGiPhv`P;FBEc^~{>^DT%tX0F8zVV&GKc%jk)qd_Ponrt~Aq;Z&b z|I&9?(*}K@H6>Nzpp&K6?EDAf)nG%1vH;XZk;Sd@z?LX1DpxVLF+H&pzRmpLx=G<$ z2}WUDVu7tJi&LIZ5FPG?=#Pl2Bt3yn@byM2sncyTx~VvDP}Ffd184bAcQLP;IjMy_ zJr({Dx=vT__Fxy}Y|4$$o)TgzE_F1j^K_bK zd`$E(?`$bzII0OK7yJEBlyi`T&6>vapN~W@TiyQRbGv^3kM?$C#Yl#;q_{>8hW|x_ z^Rmxt(~DU{{h92$nrbiTZ2ENgn$1FrAcn&&*@mV}> zHjzm`V&3#&%uC%A)}HT~4s{9Xhz4n{y;ZX@YN+m#RmvMnmhHCsL^u98a{hXsL3(}b zVCOdxJIoUIWEGG;+Vur9ih1z7E52)9ZR;ndR^uX1ILH1{OuId?zFMjNlCK-e$*pc! zmY~(Tl3>N5U@2OX@1>W$K{WKp(H~q@dt#z!%X@yHW7Y0-Yw`-uw}T+wbQOsA1JicX zX}z?LfqAQk4bz_{giKnZ!pqVIzF2?8_?+C+?B@Nb#3MKO7i8H867bl^6auvz2%kJO z*opea%2bX~`~+;eAa~1FFKY z?~^I&vcQX-8l0@OIrHfjRhxLc?=-IIukC%GcXvuRqO6{29eCOXw2r$5O1+%OqB3@K zWIRDl6tBfBCF>Fkd$QEm=SVaf3hzLN^#~H1LQ-w5k5&mWe`6om3y8GmYB=f({ zdBqgjE=<0A*M|L)QP|R#ySnJ4iRVd4L+i7PKRA%UQF30Z1;m_lQPOxEwrM%aXPvQB zvzJp@A2GV)JUvui`$0AOy%jNwjmyw9!@5>roFHuml@17QkfI(2>NZ*4o3mGd`# zLlwdfswDZ*{C$Y`b)$Zzy^rrFew5B*hhhgiVOOlu8$T8hi`5!kE=Bt0)rQ&ErM!+I zY;lD)?Mm-?{1LTE*E?Z%l@?8zjC>dvrw2Cz&%h>SfdldRD(MTta}IMPAAId z*Vxwex09f-S9q*6GMQ~nOYI~bd#CJOckb67Jtqd)j0?u}q~^{_yPwr=dTV6rO1%9v zbs4Rqd;dzAEAyG!OGXB`6<$$wM6GS&fpQI(t_-W(Jsb*CcWbi{4Z#N0+m~iZYlekI z`W1Ck^QR1|A$u)$Tl3^2ZiJs0zfzI~d!@o%j3 zgAAvCy6X~!mYeKGrBY1mgk@m>;OF7xi1c>4ch8mJ;w|rw zcegO1qXz)6hySx3eV)h;VQKy(1_0nZM#o3~OLz7l-22`Bmb=rhd;~bZT%`a;k|tou z1OS4^1a_my{Lw<>=o}~*0WwRF&X#PNCG)RAe=?Sgj1?lgWkH2Oouwab2#83vSdNliEKf-0J2Or{}JKn4A3SPp{@LQ;2UJeYy=h*jW=GayGHYAq{R$7CR&vU z0FE9G7G55n-bi~-&tGE$*-XThnKBv+MpNKA##SfKW{V!JLg>Pkh9TNJOPUYgF&`eX zXpR)PY?B;8dPFi=FBt)Tiz8M?_@b*B?O$l*6adh!qd^m(4Q_Hx&Y9m*(!uAy0W(A( A-T(jq diff --git a/renderer/carbone-templates/registry.json b/renderer/carbone-templates/registry.json index 8220a8d..39a6d72 100644 --- a/renderer/carbone-templates/registry.json +++ b/renderer/carbone-templates/registry.json @@ -6,6 +6,6 @@ "originalName": "master_cv_template.docx", "path": "/root/workspace/cv-app/renderer/carbone-templates/433a0593-d3cf-414e-8763-ab5f87cbc75c.docx", "uploadedAt": "2026-07-16T09:03:29.601Z", - "updatedAt": "2026-07-16T12:06:39.375Z" + "updatedAt": "2026-07-16T12:09:36.709Z" } ] \ No newline at end of file diff --git a/renderer/onlyoffice-service.js b/renderer/onlyoffice-service.js index 5804d30..7906b19 100644 --- a/renderer/onlyoffice-service.js +++ b/renderer/onlyoffice-service.js @@ -147,11 +147,11 @@ router.get('/:templateId/config', (req, res) => { const docKey = generateDocKey(templateId, Date.now()); const fileName = template.originalName || template.name + '.docx'; - // Add file mtime as cache-buster to the document URL so ONLYOFFICE - // always fetches the latest version from our backend. - // The mtime changes every time the file is saved, so the URL is - // different after each save, forcing ONLYOFFICE to re-download. - const documentUrl = `${BACKEND_PUBLIC_URL}/api/onlyoffice/${templateId}/download?mtime=${fileMtime}&cb=${Date.now()}`; + // Add the doc key to the download URL path so ONLYOFFICE treats + // every edit session as a completely fresh document URL. + // Query params alone aren't enough — ONLYOFFICE may ignore them for caching. + const keyHash = docKey.split('_').pop(); + const documentUrl = `${BACKEND_PUBLIC_URL}/api/onlyoffice/${templateId}/download/${keyHash}?mtime=${fileMtime}&cb=${Date.now()}`; const callbackUrl = `${BACKEND_PUBLIC_URL}/api/onlyoffice/${templateId}/callback`; const config = { @@ -223,9 +223,35 @@ router.get('/:templateId/config', (req, res) => { // ============================================================ // ENDPOINT: GET /api/onlyoffice/:templateId/download -// ONLYOFFICE fetches the .docx file from this URL +// ONLYOFFICE fetches the .docx file from this URL. +// The optional :keyHash path param provides per-session cache-busting. // ============================================================ +router.get('/:templateId/download/:keyHash', (req, res) => { + const templateId = req.params.templateId; + const registry = loadRegistry(); + const template = registry.find(t => t.id === templateId); + + if (!template) { + return res.status(404).json({ error: 'Template not found' }); + } + + if (!fs.existsSync(template.path)) { + return res.status(404).json({ error: 'Template file missing' }); + } + + const fileName = template.originalName || template.name + '.docx'; + res.setHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'); + res.setHeader('Content-Disposition', `attachment; filename="${fileName}"`); + res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); + res.setHeader('Pragma', 'no-cache'); + res.setHeader('Expires', '0'); + + const fileStream = fs.createReadStream(template.path); + fileStream.pipe(res); +}); + +// Fallback route without keyHash (backward compatibility) router.get('/:templateId/download', (req, res) => { const templateId = req.params.templateId; const registry = loadRegistry(); diff --git a/static/carbone.js b/static/carbone.js index 0e66a1d..18b33a4 100644 --- a/static/carbone.js +++ b/static/carbone.js @@ -283,9 +283,11 @@ function closeOnlyofficeEditor() { // Reload the page to clear ONLYOFFICE's in-memory state. // Save the active page so the user returns to Templates automatically sessionStorage.setItem('returnPage', 'templates'); + // Wait 2 seconds for the save callback (status=2) to complete + // on our backend before reloading the page setTimeout(() => { location.reload(); - }, 300); + }, 2000); } // Open ONLYOFFICE editor in a modal diff --git a/static/index.html b/static/index.html index 79e4bce..23968c1 100644 --- a/static/index.html +++ b/static/index.html @@ -139,7 +139,7 @@ - - + + \ No newline at end of file