From 55945166971eca89dfebcdeff22fbc68dc3ba571 Mon Sep 17 00:00:00 2001 From: Dany LE Date: Wed, 28 May 2025 22:44:47 +0200 Subject: [PATCH] fix: Libreoffice v0.1.6-a --- LibreOffice/README.md | 3 ++ LibreOffice/api/api.lua | 61 +++++++++++++++++++--- LibreOffice/build.json | 4 +- LibreOffice/build/debug/README.md | 3 ++ LibreOffice/build/debug/api/api.lua | 61 +++++++++++++++++++--- LibreOffice/build/debug/main.js | 2 +- LibreOffice/build/debug/new.png | Bin 0 -> 1922 bytes LibreOffice/build/debug/open.png | Bin 0 -> 1195 bytes LibreOffice/build/debug/package.json | 2 +- LibreOffice/build/release/LibreOffice.zip | Bin 44291 -> 47448 bytes LibreOffice/{ => icons}/icon.png | Bin LibreOffice/icons/new.png | Bin 0 -> 1922 bytes LibreOffice/icons/open.png | Bin 0 -> 1195 bytes LibreOffice/main.ts | 60 ++++++++++++++------- LibreOffice/package.json | 2 +- build.json | 2 +- release/AntunnelTestClient.md | 15 ------ release/AntunnelTestClient.zip | Bin 1731 -> 0 bytes release/LibreOffice.md | 3 ++ release/LibreOffice.zip | Bin 44291 -> 47448 bytes release/packages.json | 2 +- 21 files changed, 164 insertions(+), 56 deletions(-) create mode 100644 LibreOffice/build/debug/new.png create mode 100644 LibreOffice/build/debug/open.png rename LibreOffice/{ => icons}/icon.png (100%) create mode 100644 LibreOffice/icons/new.png create mode 100644 LibreOffice/icons/open.png delete mode 100644 release/AntunnelTestClient.md delete mode 100644 release/AntunnelTestClient.zip diff --git a/LibreOffice/README.md b/LibreOffice/README.md index 5700ea9..9697347 100644 --- a/LibreOffice/README.md +++ b/LibreOffice/README.md @@ -9,6 +9,9 @@ It support a wide range of documents. ![https://github.com/lxsang/antosdk-apps/blob/master/LibreOffice/libreoffice.png?raw=true](https://github.com/lxsang/antosdk-apps/blob/master/LibreOffice/libreoffice.png?raw=true) ## Change log +- v 0.1.6-a: + * fix document exporting does not work + * fix missing toolbar icons - v 0.1.5-a: * allow user to configure document server URI - v 0.1.4-a: diff --git a/LibreOffice/api/api.lua b/LibreOffice/api/api.lua index ec4ebf8..03ee32a 100644 --- a/LibreOffice/api/api.lua +++ b/LibreOffice/api/api.lua @@ -13,9 +13,20 @@ local result = function(data) end local error = function(msg) + LOG_ERROR("Error: "..msg) return {error = msg, result = false} end +local decode_path = function(str) + local encoded = str:gsub("%.(.*)$", ""):gsub('_', '/'):gsub('-', '+') + if #encoded % 4 == 2 then + encoded = encoded.."==" + elseif #encoded %4 == 3 then + encoded = encoded.."=" + end + return tostring(enc.b64decode(encoded)) +end + local fetch = function(url) local https = require('ssl.https') local body, code, headers = https.request(url) @@ -63,15 +74,19 @@ end handle.file = function(data) local rq = REQUEST.r + LOG_INFO("Request Data:"..JSON.encode(data)) if not rq then return error("Unknown request") end + local ret, stat = vfs.fileinfo(data.file) if not ret then return error("Unable to query file info") end local path = vfs.ospath(data.file) + LOG_INFO("Check for request GET/POST/or data") if rq:match("/wopi/files/[^/]*/contents$") then + LOG_INFO("/wopi/files/[^/]*/contents$") if REQUEST.method == "GET" then std.sendFile(path) return nil @@ -84,14 +99,44 @@ handle.file = function(data) return error("Unknown request method") end elseif rq:match("/wopi/files/[^/]*$") then - return { - BaseFileName = stat.name, - Size = math.floor(stat.size), - UserCanWrite = vfs.checkperm(data.file,"write"), - mime = stat.mime, - PostMessageOrigin = "*", - UserCanNotWriteRelative = false - } + LOG_INFO("Matching /wopi/files/[^/]*$") + if REQUEST.method == "GET" then + return { + BaseFileName = stat.name, + Size = math.floor(stat.size), + UserCanWrite = vfs.checkperm(data.file,"write"), + mime = stat.mime, + PostMessageOrigin = "*", + UserCanNotWriteRelative = false + } + elseif REQUEST.method == "POST" then + LOG_INFO("Checking for header X_WOPI_SUGGESTEDTARGET") + local out_file = HEADER['X_WOPI_SUGGESTEDTARGET'] + if not out_file then + return error("Unknown request") + end + LOG_INFO("Encoded path:"..out_file) + local dpath = decode_path(out_file) + LOG_INFO("Decoded path:"..dpath) + out_file = vfs.ospath(dpath) + LOG_INFO("Save file to:"..out_file) + local barr = REQUEST["application/octet-stream"] + barr:fileout(out_file) + local ret, stat = vfs.fileinfo(out_file) + if not ret then + return error("Unable to save file") + end + return { + BaseFileName = stat.name, + Size = math.floor(stat.size), + UserCanWrite = vfs.checkperm(data.file,"write"), + mime = stat.mime, + PostMessageOrigin = "*", + UserCanNotWriteRelative = false + } + else + return error("Unknown request method") + end else return error("Unknown request") end diff --git a/LibreOffice/build.json b/LibreOffice/build.json index d1a93ca..1dd917e 100644 --- a/LibreOffice/build.json +++ b/LibreOffice/build.json @@ -52,7 +52,9 @@ "api", "main.css", "templates", - "icon.png" + "icons/icon.png", + "icons/new.png", + "icons/open.png" ], "dest":"build/debug" } diff --git a/LibreOffice/build/debug/README.md b/LibreOffice/build/debug/README.md index 5700ea9..9697347 100644 --- a/LibreOffice/build/debug/README.md +++ b/LibreOffice/build/debug/README.md @@ -9,6 +9,9 @@ It support a wide range of documents. ![https://github.com/lxsang/antosdk-apps/blob/master/LibreOffice/libreoffice.png?raw=true](https://github.com/lxsang/antosdk-apps/blob/master/LibreOffice/libreoffice.png?raw=true) ## Change log +- v 0.1.6-a: + * fix document exporting does not work + * fix missing toolbar icons - v 0.1.5-a: * allow user to configure document server URI - v 0.1.4-a: diff --git a/LibreOffice/build/debug/api/api.lua b/LibreOffice/build/debug/api/api.lua index ec4ebf8..03ee32a 100644 --- a/LibreOffice/build/debug/api/api.lua +++ b/LibreOffice/build/debug/api/api.lua @@ -13,9 +13,20 @@ local result = function(data) end local error = function(msg) + LOG_ERROR("Error: "..msg) return {error = msg, result = false} end +local decode_path = function(str) + local encoded = str:gsub("%.(.*)$", ""):gsub('_', '/'):gsub('-', '+') + if #encoded % 4 == 2 then + encoded = encoded.."==" + elseif #encoded %4 == 3 then + encoded = encoded.."=" + end + return tostring(enc.b64decode(encoded)) +end + local fetch = function(url) local https = require('ssl.https') local body, code, headers = https.request(url) @@ -63,15 +74,19 @@ end handle.file = function(data) local rq = REQUEST.r + LOG_INFO("Request Data:"..JSON.encode(data)) if not rq then return error("Unknown request") end + local ret, stat = vfs.fileinfo(data.file) if not ret then return error("Unable to query file info") end local path = vfs.ospath(data.file) + LOG_INFO("Check for request GET/POST/or data") if rq:match("/wopi/files/[^/]*/contents$") then + LOG_INFO("/wopi/files/[^/]*/contents$") if REQUEST.method == "GET" then std.sendFile(path) return nil @@ -84,14 +99,44 @@ handle.file = function(data) return error("Unknown request method") end elseif rq:match("/wopi/files/[^/]*$") then - return { - BaseFileName = stat.name, - Size = math.floor(stat.size), - UserCanWrite = vfs.checkperm(data.file,"write"), - mime = stat.mime, - PostMessageOrigin = "*", - UserCanNotWriteRelative = false - } + LOG_INFO("Matching /wopi/files/[^/]*$") + if REQUEST.method == "GET" then + return { + BaseFileName = stat.name, + Size = math.floor(stat.size), + UserCanWrite = vfs.checkperm(data.file,"write"), + mime = stat.mime, + PostMessageOrigin = "*", + UserCanNotWriteRelative = false + } + elseif REQUEST.method == "POST" then + LOG_INFO("Checking for header X_WOPI_SUGGESTEDTARGET") + local out_file = HEADER['X_WOPI_SUGGESTEDTARGET'] + if not out_file then + return error("Unknown request") + end + LOG_INFO("Encoded path:"..out_file) + local dpath = decode_path(out_file) + LOG_INFO("Decoded path:"..dpath) + out_file = vfs.ospath(dpath) + LOG_INFO("Save file to:"..out_file) + local barr = REQUEST["application/octet-stream"] + barr:fileout(out_file) + local ret, stat = vfs.fileinfo(out_file) + if not ret then + return error("Unable to save file") + end + return { + BaseFileName = stat.name, + Size = math.floor(stat.size), + UserCanWrite = vfs.checkperm(data.file,"write"), + mime = stat.mime, + PostMessageOrigin = "*", + UserCanNotWriteRelative = false + } + else + return error("Unknown request method") + end else return error("Unknown request") end diff --git a/LibreOffice/build/debug/main.js b/LibreOffice/build/debug/main.js index 2aaed45..cc06756 100644 --- a/LibreOffice/build/debug/main.js +++ b/LibreOffice/build/debug/main.js @@ -1 +1 @@ -var OS;!function(e){let t;!function(e){class t extends e.BaseApplication{constructor(e){super("LibreOffice",e),this.access_token=void 0,this.curr_file=void 0,this.eid="id"+Math.random().toString(36).replace(".",""),this.iframe=void 0,this.mimes=this.meta().mimes.map(e=>e),this.current_mode=void 0,this.post_msg_handle=e=>{this.process_iframe_msg(e)}}main(){this.args&&this.args.length>0&&(this.curr_file=this.args[0].path.asFileHandle()),this.placeholder=this.find("editor-area"),this.placeholder.id=this.eid,this.find("btn-open-file").onbtclick=e=>{this.openFile()},this.find("btn-new-doc").onbtclick=e=>{this.create("word")},this.find("btn-new-cell").onbtclick=e=>{this.create("sheet")},this.find("btn-new-slide").onbtclick=e=>{this.create("slide")},$(window).on("message",this.post_msg_handle),this.setting.loo_url||(this.setting.loo_url="https://loo.iohub.dev/hosting/discovery"),this.discover().then(e=>{this.editor_meta=e,this.curr_file&&this.open()}).catch(e=>{this.error(__("Unable to discover LibreOffice service: {0}",e.toString()),e)})}menu(){const e=[{text:"__(New)",dataid:"new"},{text:"__(Open)",dataid:"open"}];return"edit"==this.current_mode&&(e.push({text:"__(Save)",dataid:"save"}),e.push({text:"__(Save As)",dataid:"saveas"})),[{text:"__(File)",nodes:e,onchildselect:e=>{switch(e.data.item.data.dataid){case"new":this.check_dirty().then(e=>this.new_document());break;case"open":this.check_dirty().then(e=>this.openFile());break;case"save":this.post_message("Action_Save",{DontTerminateEdit:!0,DontSaveIfUnmodified:!0,Notify:!0});break;case"saveas":this.check_dirty().then(e=>this.save_as())}}},{text:"__(Document server URI)",onmenuselect:async e=>{try{const e=await this.openDialog("PromptDialog",{title:__("Document server URI"),label:__("Please enter LOO discovery URI"),value:this.setting.loo_url});this.setting.loo_url=e;const t=await this.discover();this.editor_meta=t,this.curr_file&&this.open()}catch(e){this.error(__("Unable to set new document server URI: {0}",e.toString()),e)}}}]}update_title(){let e=this.curr_file.path;this.curr_file.dirty&&(e+=" "+__("(modified)")),this.scheme.apptitle=e}post_message(e,t){let i={MessageId:e,SendTime:Date.now()};t&&(i.Values=t),this.iframe.contentWindow.postMessage(JSON.stringify(i),"*")}process_iframe_msg(e){if(e.originalEvent.source!=this.iframe.contentWindow)return;let t=e.originalEvent,i=JSON.parse(t.data);switch(i.MessageId){case"Action_Load_Resp":i.Values.success||this.error(i.Values.errorMsg);break;case"App_LoadingStatus":"Document_Loaded"==i.Values.Status&&(this.post_message("Host_PostmessageReady"),this.trigger("document_file_loaded"),"edit"==this.current_mode&&(this.post_message("Insert_Button",{id:"lool_new_file",imgurl:"data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAABmklEQVRIie2Vv0tbURTHP+fmJTGpIYM/KEoUHItOEtIu6uTk2r9BcNMWuro62X9D6OTWIhp00baLCI2giKKYVoMtJtTE93JPhyLSpyavLxE69Due+73nwzn3nnvhkSX+wNut2pugm9XapdkXicO/A3ysaZDk3UnD9yt77KETs9mOg4d8Jkiy+9TTCc8HIpmoSH7xU3Wo7QCA3k5DLtMY0hIgCKRlwB8QI6v+NSds0sKZpXBm/eFBf6AtFTTSf0BThT5kvxRw620G1FUREQxwUraUa3c9LbXoa0XZLbkUSpYBd4Pp+Bz6eTQJoPo7d0sVVD14FZ8mbc5JU8IRF6/CnpsfSXlr5iVsvw9VQa0Ox5eWRP0b/ZF9uqSII+7Nch+QwthJVSTUc31aUXqvN5npeE2Uexp/q5VQFfQkhCN9hquxZtb1f3PQzq+UQflCVK6bWcdCAboSQtHJMf/zHVV98pBt0Rnfmbx7TYWFZoC4A5m0oVh+mr2gP5viIpbUH7GIeAKcAilUPogQ6H9vqJuB8taGp9z88LJ/0H4BR3aNW1eB/4cAAAAASUVORK5CYII=",label:__("New file").__(),hint:__("Create new document").__(),insertBefore:"save"}),this.post_message("Insert_Button",{id:"lool_open_file",imgurl:"data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAD8UlEQVR42q1Va2gcVRQ+587s7mRItNskfaY1trRi2sZHNYoQHzGmQkAMlNZK1R+l0R+K/REhRAmzIEElaqX2R/tDhZamov4QbV0a6V9Nm9DiI8QEEtpI8zDbPPfh7sw93juzOzv7Ugge2L3nztz7fed859w7CHmGiKocYHVGwswcvLwFWnNzc3tLS8sjaTIvcX4kBZvD4fBAf3//aeEmShGUd3Z2nu7q6noBHZPABOjA2/9ijs4+wiwrydehUKivp6fnqPCjOQSHPhrTmKI2XP/uA33/k9s6Ot58rSkNnvPzZlKQkTDDMM4XJXjp08m3aiqV9xUex3sqZqCtqZ6QMSeDdKQeEoISGQiCvo9PfnY0tjBVQNC9d7vf0Fkcq2AK9jXeR8wrEQB6Ii8gkJWV/skz4ZlLI8posKbOQmQfnnl9y/f2gsMnbnbvuctnaCwOm9QZaH3ifmAlpCklj7RvLw/Bn8lqSPAy+PVGKnT2ja0hN4MdmxTDDzGs1Wbh+aYHXVm8kebNM5m4En3TfxXGY1WUBB3HblmGyCBLsLUaDZViuLN8DvY/s9cL+p8SZQi+DF+BkaW1ZKKON/+iLIGUaEMQDMZjsHtNBA7ue6hAnlISCfldv++HK/DL7SBwpsP0PGQlOnh8onttBRpgruDD6xbgcGtDTgb5EkmXc27XVozus7MXr8Lg7BoCtRznlyF0/litgfUdAxcCqnovAK/l3IRKnWBz9Z155ZMZQEHUcnRcZz41twyROAJj8rZhN5KmOYxtvcMLLz5egxanCimrIiT2qUpBAT1sztzGppw1psXBIlkj0aQIsYHRSAqffnd4fOeWDRoRXy8iYgGBXab5PKDu1SAxwQXOji5BPGlCirNMB94em5xdxGffGx3as23zRotbLoGu+XMzQEgDOagZAqE/SplknUzLwtjfFqDiJ9kTDNn8bxO3JvC53vEfG+o21okF68VWTBN4znnaIUpzkJ2JBBZ1BlVVIJlMwUrCBKb43E2MscXBkekhPHBi8qvHdlc3Eqd1Ygtqoj56ma94Dci5FmT3ZEZRO4jGUwTMZzebXCIlFXkt/Tw8dwlfPjV9qrE+2MYYVckMHAK/q3uGwBN9uj3JliUaN4UsPoK8QyeT+un3hXPY/nmk59FdFa8GfBSUb/2MQ1lALXrXULYOIMDB0bz4BzCaoMTgSPQ4Hju31LHrbu0dXaM7ZDmJmxmof29T+wCq6QNCdmtmw0BcXOHJPyaTb2PvxciRYGX5J5wsvQRocYLSa5yTbiGPLifasfXAkada2g59kTKpuC6rNJ+C1uULX78iPlxKgHPrAfGssqiYqzOZRURRlGv/F2BJ+wdsRP1yLA0KOQAAAABJRU5ErkJggg==",label:__("Open file").__(),hint:__("Open document").__(),insertBefore:"lool_new_file"}))),"Frame_Ready"==i.Values.Status&&$(this.iframe).css("visibility","visible");break;case"Doc_ModifiedStatus":this.curr_file.dirty=i.Values.Modified,this.update_title();break;case"Clicked_Button":switch(i.Values.Id){case"lool_open_file":this.check_dirty().then(e=>this.openFile());break;case"lool_new_file":this.check_dirty().then(e=>this.new_document())}break;case"UI_SaveAs":this.check_dirty().then(e=>this.save_as());break;default:console.log(i)}}save_as(){this.openDialog("FileDialog",{title:__("Save file as"),type:"dir",file:this.curr_file.asFileHandle()}).then(async e=>{const t=`${e.file.path}/${e.name}`.asFileHandle();try{const e=await this.exec({action:"duplicate",args:{src:this.curr_file.path,dest:t.path}});if(e.error)throw e.error;this.curr_file=t,this.open()}catch(e){this.error(__("Unable to save file as {0}: {1}",t.path,e.toString()),e)}})}new_document(){this.openDialog("SelectionDialog",{title:__("Create new"),data:[{text:__("Document"),iconclass:"fa fa-file-word-o",type:"word"},{text:__("Spreadsheet"),iconclass:"fa fa-file-excel-o",type:"sheet"},{text:__("Presentation"),iconclass:"fa fa-file-powerpoint-o",type:"slide"}]}).then(e=>{this.create(e.type)})}discover(){return new Promise(async(e,t)=>{try{let t=await this.setting.loo_url.asFileHandle().read(),i=(new DOMParser).parseFromString(t,"text/xml").getElementsByTagName("app"),s={};if(i)for(let e of i){let t=e.getAttribute("name");t.match(/^[^\/]*\/[^\/]*$/g)&&(this.mimes.includes(t)||this.mimes.push(t));let i=e.getElementsByTagName("action");if(i)for(let e of i){let t=e.getAttribute("ext"),i=e.getAttribute("name"),a=e.getAttribute("urlsrc");t&&""!=t&&a&&(s[t]={url:a,mode:i})}}e(s)}catch(e){t(__e(e))}})}openFile(){this.openDialog("FileDialog",{title:__("Open file"),type:"file",mimes:this.mimes}).then(e=>{this.curr_file=e.file.path.asFileHandle(),this.open()})}create(e){let t=void 0;switch(e){case"word":t="docx";break;case"sheet":t="xlsx";break;case"slide":t="pptx";break;default:this.error(__("Unknown doc type {0}",e))}this.openDialog("FileDialog",{title:__("Save file as"),type:"dir",file:("home://Untitled."+t).asFileHandle()}).then(async e=>{try{let i=`${e.file.path}/${e.name}`.asFileHandle(),s=`${this.path()}/templates/model.${t}`.asFileHandle(),a=await s.read("binary"),r=new Blob([a],{type:s.info.mime});i.cache=r,await i.write(s.info.mime),i.cache=void 0,this.curr_file=i,this.open()}catch(e){this.error(__("Unable to create document {0}",e.toString()),e)}})}open(){this.scheme.apptitle=__("Libre Office Online"),this.curr_file&&this.exec({action:"token",args:{file:this.curr_file.path}}).then(e=>{if(e.error)return void this.error(e.error);this.access_token=e.result.sid;let t=this.editor_meta[this.curr_file.ext];if(!t||!t.url)return this.error(__("Unknown editor for extension {0}",this.curr_file.ext));this.current_mode=t.mode,$(this.placeholder).empty();let i=$("