From 882b57dd876822cd622ea3d345e076cc77d2aa97 Mon Sep 17 00:00:00 2001 From: mrsang Date: Fri, 19 Mar 2021 22:04:27 +0100 Subject: [PATCH] support versionning in OnlyOffice --- OnlyOffice/README.md | 1 + OnlyOffice/api/api.lua | 110 +++++++++++++++++++++++- OnlyOffice/build/release/OnlyOffice.zip | Bin 61645 -> 67239 bytes OnlyOffice/coffees/main.coffee | 73 +++++++++++++++- OnlyOffice/package.json | 4 +- packages.json | 66 +++++++------- 6 files changed, 216 insertions(+), 38 deletions(-) diff --git a/OnlyOffice/README.md b/OnlyOffice/README.md index 4f155e5..5baf38a 100644 --- a/OnlyOffice/README.md +++ b/OnlyOffice/README.md @@ -10,6 +10,7 @@ way to work with multiple documents at the same time. ![https://github.com/lxsang/antosdk-apps/blob/master/OnlyOffice/screenshot.png?raw=true](https://github.com/lxsang/antosdk-apps/blob/master/OnlyOffice/screenshot.png?raw=true) ## Change log +- v 0.1.5a: Add document versionning support - v 0.1.4a: If the iframe has the same origin with the parent, enable the focus event - v 0.1.3a: Let backend generates document key, compatible with doc.iohub.dev/office - v 0.1.2a: generate document key based on username, file path and modified time diff --git a/OnlyOffice/api/api.lua b/OnlyOffice/api/api.lua index 307b703..f92f947 100644 --- a/OnlyOffice/api/api.lua +++ b/OnlyOffice/api/api.lua @@ -32,6 +32,67 @@ handle.token = function(data) return result(ret) end +handle.history = function(data) + local file = vfs.ospath(data.file) + local history_file = vfs.ospath("home://.office/"..std.sha1(file).."/history.json") + if(ulib.exists(history_file)) then + local obj = JSON.decodeFile(history_file) + obj.hash = std.sha1(file) + return result(obj) + else + return error("No history found") + end +end +handle.clean_up_version = function(basepath, h,v) + if not h then + return nil + end + if h.version == v then + return h + else + --delete this version + local cmd = 'rm '..basepath.."/"..h.key.."*" + print(cmd) + os.execute(cmd) + if h.previous then + return handle.clean_up_version(basepath, h.previous,v) + else + return nil + end + end +end +handle.restore = function(data) + local version = data.version + local file = vfs.ospath(data.file) + local basepath = vfs.ospath("home://.office/"..std.sha1(file)) + if ulib.exists(basepath.."/history.json") then + local history = JSON.decodeFile(basepath.."/history.json") + local obj = handle.clean_up_version(basepath, history,version) + if obj then + -- restore the file + local cmd = 'cp '..basepath.."/"..obj.key..' "'..file..'"' + os.execute(cmd) + local cmd = 'rm '..basepath.."/"..obj.key + os.execute(cmd) + + local f = io.open(basepath.."/history.json", "w") + if f then + f:write(JSON.encode(obj)) + f:close() + return result("File restored") + else + return error("Cannot save history") + end + else + local cmd = "rm "..basepath.."/history.json" + os.execute(cmd) + return result("File restored") + end + else + return error("Unable to restore: no history meta-data found") + end + +end handle.duplicate = function(data) local file = vfs.ospath(data.as) local tmpfile = "/tmp/"..std.sha1(file) @@ -67,8 +128,55 @@ handle.save = function() os.execute(cmd) -- move file to correct position if ulib.exists(tmpfile) then - cmd = "mv "..tmpfile.." "..file + -- back up the file version + local history_dir = "home://.office" + vfs.mkdir(history_dir) + history_dir = history_dir.."/"..std.sha1(file) + vfs.mkdir(history_dir) + history_dir = vfs.ospath(history_dir) + -- backup old version + cmd = 'cp "'..file..'" "'..history_dir.."/"..data.key..'"' os.execute(cmd) + -- create new version + local old_stat = ulib.file_stat(file) + cmd = 'mv "'..tmpfile..'" "'..file..'"' + os.execute(cmd) + -- get the new key + local stat = ulib.file_stat(file) + local new_key = std.sha1(file..":"..stat.mtime) + -- save changes + if(data.changesurl) then + cmd = "curl -o "..history_dir.."/"..new_key..'.zip "'..data.changesurl..'"' + os.execute(cmd) + end + -- now save version object + local history_file = history_dir.."/history.json" + local history = {} + if ulib.exists(history_file) then + history.previous = JSON.decodeFile(history_file) + history.version = history.previous.version + 1 + else + history.version = 1 + history.previous = { + key = data.key, + version = 0, + create = old_stat.mtime + } + end + history.key = new_key + history.changes = data.history.changes + history.serverVersion = data.history.serverVersion + history.create = stat.mtime + history.user = { id = ulib.uid(SESSION.user).id, name = SESSION.user } + -- save the history to file + local f = io.open(history_file, "w") + if f then + f:write(JSON.encode(history)) + f:close() + + else + return error("Cannot save history") + end print("File "..file.." sync with remote") else return error("Unable to download") diff --git a/OnlyOffice/build/release/OnlyOffice.zip b/OnlyOffice/build/release/OnlyOffice.zip index cebcad66d2f813500b8fe33662727f59d64087ae..52dcbfdfd69deb2573332e7bd26d05900b6e776e 100644 GIT binary patch delta 5635 zcmbVQU2NP~74{^drOl>g`g`z@f$QSL^>=T-F{mhS zbbk8RGXqn{t+Kk{II0ua%{ujCb(MyZ8~DEKuc%S8(Fnr0^Ph(crD198rMIGYMve}T zz;*H2)3blP3&!qt&JOP`jUS)0G;^m4AI-L6x)OvpwX$}hT6JyOiJ$rAz#u54KbZO? zUOWH%!a&4+{QJk2Id}<1em^xaxeIAXu?o(*a05{lw&jfdyu0 zMxWyvdR)=nicZZKf=neK6~O5PAWj-#LRa0O8J%#!?MBFNK)AdbxQ=?%(AgFQp0Hm; z+c0k3V#CyN!9NmFNhRh-i$PRgUe>kqfr<)hHE8;dW)K)NfUseuW!Ef!g+`ac(_Zujz@JP-8rGo znJ`;sGG;U6mb+S;X(XnMe=Nain{kH3^t2vkHU|8|C(+b z(N2i{rIQmQM}R1Daf}S0O?nv2{D2)*(vQaH5<#pj;IAR%<*;2~h;9@pB+OTMlsN@? zVu%??jJ^y2f>?2_ZKUehjzn@z@Jtn%aUxHQkX9i-YNvTN>Vgmf{dv70WHCDPx`4$z&TglXrK!gRGa_d-L1RpNC#@eza4&f4SQk zp4>l>{`rHsL;$&rF;^?$48>Y5Bq7SD+vXPh?GE3eU+yat34jKQ=)$|)1+N^{CtstuMnnPH$-<0!j+kr07SiB@&>67(|^urJKCvvN> z`TvEQS$OhHl(zbLTf~4P&e)QKH(}*oW^QdL3jnvliTxBn@;WJNPd8`@gbIxmvIbF| zn}aa1(-Y3An2*`oIA36m-PnXRm`IE_GpYuhLJNeB)_8qhM=O1`1p0XEuza zpwCsSfT0@@c6!+oJ5$wehzf!mzz=M`+P`(2sh0V1mqmv9STiuw4P)mtPUk<>GCNV} zT~Kj0ef`0~DS;rIPYO=cd~)7dKaiZXd`$DmTBWjx^r{H5qv?V=4&?FE06$3CEm0^q z!c*2x&u;8bzy4s~c9}arhx>&GQxoF83`I!#rPgU|&0#8~e_7u@gte{nleH^D2@vM0 zWnWX9jf^mTrKanwEZUA6LhO1vLAT7H0;XmC8VF_u8-5o71#1Z&XP3FToN-aXwy5M! zZ$4)|S0-``B}I<}8URM%Ih*1j3NEBhK0DY=&aCjCl`fu4JqaX2*i6rD>@#6ie)Ld% zdSla7IaR=?<#c#WoksxhBb=$Pvi0M7LuPBixf#sAF<1mnn=Ht<3V4-qDlM(e?%@_C zD?wyAZLG~Eav0PZ&&8=J)5Uq{>};oE4o;;#{ahO1{%UZJ^VGQj3Ez(yuFN6BGyNpn zNsskzJxV{jp(nDV$W_2qKe)l&m2Cuy0JYc;^W2D_X8>0+Tai29xFwomgqzZagWGQY`8ju^zT+d9(o~a&DkL6uU`YX}q1`ApY zT)Aj=Mu2VSO*0|<2LXf~N&54bA96CIRM+*RMF}Y>lA?mixE#e+OzJVb;OJYih z58)L~t)}bfOQ)8W&cOK?rw!sdrs`XDByxU2EdZ3@A%W#Go)Cn6H4e5qEabbikY-N> z|8HZye4dETEUZCymJyfN&6_jM7DNjz6*}_l(|6>w^x(P9>c)I&q%^Qk>An#B`=hY| zMM-x(K9CgN3&QKX9qg^4{I?E27Edj_@TF6v?p!?AwSsQ||L|_fScERK~7Nqa)UF|m>C$RZT`Z~&nRu8o2aD2 zr2qs<$%!SY>G?&KN>)n#B^jwjo8<*NnV5lkHaot|WCk%N@;>1MnIW4o@q~#W1A~d+ z=Jbo%ER4mIFJCnUlAPBHfn@bHdB)<+v#+HyO%}UpAfS<)pI4lpld6}KpRSRrsk7Pb zW;WyIq}z#%lMmfd-+b^)B zpC{Ai5@riVUPdMn26(_s?`L6@t_OuuCeWRF1$pTK-UtOK0R}XM2c!@VjJX*Y3KEmE z6Vp@mvWoNb&~-j}^svSms0)OFN|C^4J_d&3Ye#Aj_UcZ return unless @currfile @iframe = undefined + @history = undefined @exec("token", {file: @currfile.path}) .then (d) => - console.log(d) return @error d.error if d.error @access_token = d.result.sid @currfile.onready() @@ -105,7 +105,11 @@ class OnlyOffice extends this.OS.application.BaseApplication events: { onAppReady: (e) => @editorReady(e), onRequestCreateNew: () => @newDocument(), - onRequestSaveAs: (e) => @saveAs(e) + onRequestSaveAs: (e) => @saveAs(e), + onRequestHistory: () => @loadHistory(), + onRequestHistoryData: (e) => @loadHistoryData(e), + onRequestHistoryClose: (e) => @closeHistory(e), + onRequestRestore: (e) => @restoreVersion(e) }, document: { fileType: @currfile.ext, @@ -130,6 +134,71 @@ class OnlyOffice extends this.OS.application.BaseApplication .catch (e) => @error e.toString(), e + restoreVersion: (e) -> + return if e.data.version is @history.version + @exec("restore", { version: e.data.version, file: @currfile.path }) + .then (d) => + @error d.error if d.error + @notify d.result if d.result + @loadHistory() + .catch (e) => + @error e.toString(),e + @loadHistory() + + closeHistory: (e) -> + @open() + + loadHistoryData: (e) -> + fn = (h,v) => + return h if h.version is v + return fn h.previous, v if h.previous + return undefined + data = fn @history, e.data + @editor.setHistoryData({ error:__("No data found").__()}) unless data + path = "home://.office/#{@history.hash}" + hdata = { + changesUrl: "#{path}/#{data.key}.zip".asFileHandle().getlink()+ "?" + @access_token, + key: data.key, + url: "#{path}/#{data.key}".asFileHandle().getlink()+ "?" + @access_token, + version: data.version + } + if data.previous + hdata.previous = { + key: data.previous.key, + url: "#{path}/#{data.previous.key}".asFileHandle().getlink()+ "?" + @access_token + } + hdata.url = @currfile.getlink()+ "?" + @access_token if data.version is @history.version + # console.log(hdata) + @editor.setHistoryData {hdata} + + loadHistory: () -> + @history = undefined + @exec("history", { file: @currfile.path }) + .then (d) => + return @editor.refreshHistory({error: d.error}) if d.error + @history = d.result + history = {} + history.currentVersion = d.result.version + history.history = [] + fn = (list, obj) => + list.push { + changes: obj.changes, + created: obj.create, + key: obj.key, + user: obj.user, + version: obj.version + } + return unless obj.previous + fn list, obj.previous + + fn history.history, d.result + console.log history + @editor.refreshHistory(history) + + .catch (e) => + @editor.refreshHistory({ error: e.toString()}) + @error e.toString(), e + getDocType: (ext) -> return "word" if "doc,docx,epub,odt".split(",").includes(ext) return "cell" if "csv,ods,xls,xlsx".split(",").includes(ext) diff --git a/OnlyOffice/package.json b/OnlyOffice/package.json index 58cc570..b5329c2 100644 --- a/OnlyOffice/package.json +++ b/OnlyOffice/package.json @@ -7,8 +7,8 @@ "author": "Xuan Sang LE", "email": "mrsang@iohub.dev" }, - "version":"0.1.4-a", - "category":"Other", + "version":"0.1.5-a", + "category":"Office", "icon":"icon.png", "mimes":[ "application/vnd.oasis.opendocument.text", diff --git a/packages.json b/packages.json index f381568..bb64510 100644 --- a/packages.json +++ b/packages.json @@ -139,6 +139,36 @@ "dependencies": [], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/Katex/build/release/Katex.zip" }, + { + "pkgname": "libjpeg", + "name": "libjpeg", + "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libjpeg/README.md", + "category": "Library", + "author": "", + "version": "0.1.1-a", + "dependencies": [], + "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libjpeg/build/release/libjpeg.zip" + }, + { + "pkgname": "libpdfjs", + "name": "PDF JS library", + "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libpdfjs/README.md", + "category": "Library", + "author": "Xuan Sang LE", + "version": "2.6.347-r", + "dependencies": [], + "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libpdfjs/build/release/libpdfjs.zip" + }, + { + "pkgname": "libwvnc", + "name": "libwvnc", + "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libwvnc/README.md", + "category": "Library", + "author": "", + "version": "0.1.2-a", + "dependencies": ["libjpeg@0.1.1-a"], + "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libwvnc/build/release/libwvnc.zip" + }, { "pkgname": "LuaPlayground", "name": "LuaPlayground", @@ -163,9 +193,9 @@ "pkgname": "OnlyOffice", "name": "Office Suite", "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/OnlyOffice/README.md", - "category": "Other", + "category": "Office", "author": "Xuan Sang LE", - "version": "0.1.4-a", + "version": "0.1.5-a", "dependencies": [], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/OnlyOffice/build/release/OnlyOffice.zip" }, @@ -215,7 +245,7 @@ "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/ShowCase/README.md", "category": "Other", "author": "Xuan Sang LE", - "version": "0.0.4-a", + "version": "0.0.5-a", "dependencies": [], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/ShowCase/build/release/ShowCase.zip" }, @@ -259,36 +289,6 @@ "dependencies": [], "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/VizApp/build/release/VizApp.zip" }, - { - "pkgname": "libjpeg", - "name": "libjpeg", - "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libjpeg/README.md", - "category": "Library", - "author": "", - "version": "0.1.1-a", - "dependencies": [], - "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libjpeg/build/release/libjpeg.zip" - }, - { - "pkgname": "libpdfjs", - "name": "PDF JS library", - "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libpdfjs/README.md", - "category": "Library", - "author": "Xuan Sang LE", - "version": "2.6.347-r", - "dependencies": [], - "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libpdfjs/build/release/libpdfjs.zip" - }, - { - "pkgname": "libwvnc", - "name": "libwvnc", - "description": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libwvnc/README.md", - "category": "Library", - "author": "", - "version": "0.1.2-a", - "dependencies": ["libjpeg@0.1.1-a"], - "download": "https://raw.githubusercontent.com/lxsang/antosdk-apps/master/libwvnc/build/release/libwvnc.zip" - }, { "pkgname": "vTerm", "name": "Virtual Terminal",