From 6354c48680aa195b255872336c3eee2dd68d64c5 Mon Sep 17 00:00:00 2001 From: DanyLE Date: Fri, 24 Feb 2023 18:41:36 +0100 Subject: [PATCH] Blogger: use luasocket for mail sending --- Blogger/api/sendmail.lua | 56 ++++++++++++++++++------------ Blogger/build/debug/main.js | 2 +- Blogger/build/debug/package.json | 3 ++ Blogger/build/debug/sendmail.lua | 56 ++++++++++++++++++------------ Blogger/build/release/Blogger.zip | Bin 10239 -> 10426 bytes Blogger/dialogs.ts | 46 +++++++++++++----------- Blogger/package.json | 3 ++ 7 files changed, 100 insertions(+), 66 deletions(-) diff --git a/Blogger/api/sendmail.lua b/Blogger/api/sendmail.lua index 6e8aab4..8d98a3a 100644 --- a/Blogger/api/sendmail.lua +++ b/Blogger/api/sendmail.lua @@ -1,30 +1,42 @@ local data = ... --- print(data.content) +-- load the smtp support +local smtp = require("socket.smtp") + +local from = string.format("<%s@iohub.dev>", data.user); + +local mesgt = { + headers = { + from = string.format("Dany <%s@iohub.dev>", data.user), + to = "", + subject = data.title + }, + body = data.content +} + local error_msg = {} local iserror = false -local tmp_name = "/tmp/"..os.time(os.date("!*t")) -local file = io.open (tmp_name , "w") -if file then - file:write("From: mrsang@lxsang.me\n") - file:write("Subject: " .. data.title .. "\n") - file:write( data.content.."\n") - file:close() - for k,v in pairs(data.to) do - print("sent to:"..v) - local to = v - local cmd = 'cat ' ..tmp_name .. '| sendmail ' .. to - --print(cmd) - local r = os.execute(cmd) - if not r then - iserror = true - table.insert(error_msg, v) - print("Unable to send mail to: "..v) - end + +for k,v in pairs(data.to) do + LOG_DEBUG("Send email to:"..v.email) + local rcpt = string.format("<%s>",v.email) + mesgt.headers.to = string.format("%s <%s>",v.text, v.email) + local r, e = smtp.send{ + from = from, + rcpt = rcpt, + server = "iohub.dev", + domain = "iohub.dev", + user = data.user, + password = data.password, + source = smtp.message(mesgt) + } + + local r = os.execute(cmd) + if not r then + iserror = true + table.insert(error_msg, v.email) + LOG_ERROR(string.format("Unable to send mail to %s: %s",v.email, e)) end -else - iserror = true - table.insert(error_msg, "Cannot create mail file") end local result = {} result.error = iserror diff --git a/Blogger/build/debug/main.js b/Blogger/build/debug/main.js index 59d4cd8..b7ca0e6 100644 --- a/Blogger/build/debug/main.js +++ b/Blogger/build/debug/main.js @@ -1 +1 @@ -var OS;!function(t){let e;!function(t){class e extends t.BaseApplication{constructor(t){super("Blogger",t),this.previewOn=!1}async init_db(){try{const e=await this.openDialog("FileDialog",{title:__("Open/create new database"),file:"Untitled.db"});var t=e.file.path.asFileHandle();"file"===e.file.type&&(t=t.parent());const i=`${t.path}/${e.name}`.asFileHandle();this.dbhandle=("sqlite://"+i.genealogy.join("/")).asFileHandle();const a=await this.dbhandle.read();if(!a.user){this.dbhandle.cache={address:"TEXT",Phone:"TEXT",shortbiblio:"TEXT",fullname:"TEXT",email:"TEXT",url:"TEXT",photo:"TEXT"};const t=await this.dbhandle.write("user");if(t.error)throw new Error(t.error)}if(!a.cv_cat){this.dbhandle.cache={publish:"NUMERIC",name:"TEXT",pid:"NUMERIC"};const t=await this.dbhandle.write("cv_cat");if(t.error)throw new Error(t.error)}if(!a.cv_sections){this.dbhandle.cache={title:"TEXT",start:"NUMERIC",location:"TEXT",end:"NUMERIC",content:"TEXT",subtitle:"TEXT",publish:"NUMERIC",cid:"NUMERIC"};const t=await this.dbhandle.write("cv_sections");if(t.error)throw new Error(t.error)}if(!a.blogs){this.dbhandle.cache={tags:"TEXT",content:"TEXT",utime:"NUMERIC",rendered:"TEXT",title:"TEXT",utimestr:"TEXT",ctime:"NUMERIC",ctimestr:"TEXT",publish:"INTEGER DEFAULT 0"};const t=await this.dbhandle.write("blogs");if(t.error)throw new Error(t.error)}if(!a.st_similarity){this.dbhandle.cache={pid:"NUMERIC",sid:"NUMERIC",score:"NUMERIC"};const t=await this.dbhandle.write("st_similarity");if(t.error)throw new Error(t.error)}if(!a.subscribers){this.dbhandle.cache={name:"TEXT",email:"TEXT"};const t=await this.dbhandle.write("subscribers");if(t.error)throw new Error(t.error)}this.userdb=(this.dbhandle.path+"@user").asFileHandle(),this.cvcatdb=(this.dbhandle.path+"@cv_cat").asFileHandle(),this.cvsecdb=(this.dbhandle.path+"@cv_sections").asFileHandle(),this.blogdb=(this.dbhandle.path+"@blogs").asFileHandle(),this.subdb=(this.dbhandle.path+"@subscribers").asFileHandle(),this.last_ctime=0,this.bloglist.data=[],this.loadBlogs()}catch(t){this.error(__("Unable to init database file: {0}",t.toString()),t),this.dbhandle=void 0}}menu(){return[{text:"__(Open/Create database)",onmenuselect:t=>{this.init_db()}}]}main(){this.user={},this.cvlist=this.find("cv-list"),this.cvlist.ontreeselect=t=>{if(!t)return;const{data:e}=t.data.item;return this.CVSectionByCID(Number(e.id))},this.inputtags=this.find("input-tags"),this.bloglist=this.find("blog-list"),this.seclist=this.find("cv-sec-list");let e=this.find("photo");return $(e).on("click",async t=>{try{const t=await this.openDialog("FileDialog",{title:__("Select image file"),mimes:["image/.*"]});return e.value=t.file.path}catch(t){return this.error(__("Unable to get file"),t)}}),this.tabcontainer=this.find("tabcontainer"),this.tabcontainer.ontabselect=t=>this.fetchData(t.data.container.aid),this.find("bt-user-save").onbtclick=t=>this.saveUser(),this.find("blog-load-more").onbtclick=t=>{this.loadBlogs()},this.find("cv-cat-add").onbtclick=async e=>{try{const e=await this.fetchCVCat(),i=await this.openDialog(new t.blogger.BloggerCategoryDialog,{title:__("Add category"),tree:e});this.cvcatdb.cache={name:i.value,pid:i.p.id,publish:1};const a=await this.cvcatdb.write(void 0);if(a.error)throw new Error(a.error);await this.refreshCVCat()}catch(e){this.error(__("cv-cat-add: {0}",e.toString()),e)}},this.find("cv-cat-edit").onbtclick=async e=>{try{const e=this.cvlist.selectedItem;if(!e)return;const i=e.data;if(!i)return;const a=await this.fetchCVCat(),s=await this.openDialog(new t.blogger.BloggerCategoryDialog,{title:__("Edit category"),tree:a,cat:i}),n=i.$vfs;n.cache={id:i.id,publish:i.publish,pid:s.p.id,name:s.value};const r=await n.write(void 0);if(r.error)throw new Error(r.error);await this.refreshCVCat()}catch(e){this.error(__("cv-cat-edit: {0}",e.toString()),e)}},this.find("cv-cat-del").onbtclick=async t=>{try{const t=this.cvlist.selectedItem;if(!t)return;const e=t.data;if(!e)return;if(!await this.openDialog("YesNoDialog",{title:__("Delete category"),iconclass:"fa fa-question-circle",text:__("Do you really want to delete: {0}?",e.name)}))return;await this.deleteCVCat(e)}catch(t){this.error(__("cv-cat-del: {0}",t.toString()),t)}},this.find("cv-sec-add").onbtclick=async e=>{try{const e=this.cvlist.selectedItem;if(!e)return;const i=e.data;if(!i||"0"===i.id)return this.toast(__("Please select a category"));const a=await this.openDialog(new t.blogger.BloggerCVSectionDiaglog,{title:__("New section entry for {0}",i.name)});a.cid=Number(i.id),a.start=Number(a.start),a.end=Number(a.end),this.cvsecdb.cache=a;const s=await this.cvsecdb.write(void 0);if(s.error)throw new Error(s.error);await this.CVSectionByCID(Number(i.id))}catch(e){this.error(__("cv-sec-add: {0}",e.toString()),e)}},this.find("cv-sec-move").onbtclick=async e=>{try{const e=this.seclist.selectedItem;if(!e)return this.toast(__("Please select a section to move"));const i=e.data,a=i.$vfs;console.log(a);const s=await this.fetchCVCat(),n=await this.openDialog(new t.blogger.BloggerCategoryDialog,{title:__("Move to"),tree:s,selonly:!0});a.cache={id:i.id,cid:n.p.id};const r=await a.write(void 0);if(r.error)throw new Error(r.error);await this.CVSectionByCID(i.cid),this.seclist.unselect()}catch(e){this.error(__("cv-sec-move: {0}",e.toString()),e)}},this.find("cv-sec-edit").onbtclick=async e=>{try{const e=this.seclist.selectedItem;if(!e)return this.toast(__("Please select a section to edit"));const i=e.data,a=await this.openDialog(new t.blogger.BloggerCVSectionDiaglog,{title:__("Modify section entry"),section:i});a.cid=Number(i.cid),a.start=Number(a.start),a.end=Number(a.end);const s=i.$vfs;s.cache=a;const n=await s.write(void 0);if(n.error)throw new Error(n.error);await this.CVSectionByCID(Number(i.cid))}catch(e){this.error(__("cv-sec-edit: {0}",e.toString()),e)}},this.seclist.onitemclose=t=>{if(!t)return;const e=t.data.item.data;return this.openDialog("YesNoDialog",{iconclass:"fa fa-question-circle",text:__("Do you really want to delete: {0}?",e.title)}).then(async i=>{if(i)try{const i=await this.cvsecdb.remove({where:{id:e.id}});if(i.error)throw new Error(i.error);return this.seclist.delete(t.data.item)}catch(t){return this.error(__("Cannot delete the section: {0}",t.toString()),t)}}),!1},this.editor=new EasyMDE({element:this.find("markarea"),autoDownloadFontAwesome:!1,autofocus:!0,tabSize:4,indentWithTabs:!0,toolbar:[{name:__("New"),className:"fa fa-file",action:t=>(this.bloglist.unselect(),this.clearEditor())},{name:__("Save"),className:"fa fa-save",action:t=>this.saveBlog()},"|","bold","italic","heading","|","quote","code","unordered-list","ordered-list","|","link","image","table","horizontal-rule",{name:"image",className:"fa fa-file-image-o",action:t=>this.openDialog("FileDialog",{title:__("Select image file"),mimes:["image/.*"]}).then(t=>t.file.path.asFileHandle().publish().then(t=>this.editor.codemirror.getDoc().replaceSelection(`![](${this._api.handle.shared}/${t.result})`)).catch(t=>this.error(__("Cannot export file for embedding to text"),t)))},{name:"Youtube",className:"fa fa-youtube",action:t=>this.editor.codemirror.getDoc().replaceSelection("[[youtube:]]")},"|",{name:__("Preview"),className:"fa fa-eye no-disable",action:t=>{this.previewOn=!this.previewOn,EasyMDE.togglePreview(t),renderMathInElement(this.find("editor-container"))}},"|",{name:__("Send mail"),className:"fa fa-paper-plane",action:async e=>{try{const e=await this.subdb.read(),i=this.bloglist.selectedItem;if(!i)return this.error(__("No post selected"));const a=i.data;await this.openDialog(new t.blogger.BloggerSendmailDiaglog,{title:__("Send mail"),content:this.editor.value(),mails:e,id:a.id}),this.toast(__("Emails sent"))}catch(e){this.error(__("Error sending mails: {0}",e.toString()),e)}}}]}),this.bloglist.onlistselect=async t=>{const e=this.bloglist.selectedItem;if(!e)return;const i=e.data;if(i)try{const t=await this.blogdb.read({where:{id:Number(i.id)}});if(!t||0==t.length)throw new Error(__("No record found for ID {}",i.id).__());const e=t[0];return this.editor.value(e.content),this.inputtags.value=e.tags,this.find("blog-publish").swon=!!Number(e.publish)}catch(t){return this.error(__("Cannot fetch the entry content"),t)}},this.bloglist.onitemclose=t=>{if(!t)return;const e=t.data.item,i=e.data;return this.openDialog("YesNoDialog",{title:__("Delete a post"),iconclass:"fa fa-question-circle",text:__("Do you really want to delete this post ?")}).then(async t=>{if(!t)return;const a=await this.blogdb.remove({where:{id:Number(i.id)}});if(a.error)throw new Error(a.error);return this.bloglist.delete(e),this.bloglist.unselect(),this.clearEditor()}),!1},this.bindKey("CTRL-S",()=>{const t=this.tabcontainer.selectedTab;if(t&&"blog-container"===t.container.aid)return this.saveBlog()}),this.on("resize",()=>this.resizeContent()),this.resizeContent(),this.init_db()}fetchData(t){switch(t){case"user-container":return this.userdb.read().then(t=>{if(t&&0!=t.length)return this.user=t[0],this.select("[input-class='user-input']").map((t,e)=>$(e).val(this.user[e.name]))}).catch(t=>this.error(__("Cannot fetch user data"),t));case"cv-container":return this.refreshCVCat();default:return this.last_ctime=0,this.bloglist.data=[],this.loadBlogs()}}async saveUser(){try{const t=this.select("[input-class='user-input']");for(let e of t)this.user[e.name]=$(e).val();if(!this.user.fullname||""===this.user.fullname)return this.toast(__("Full name must be entered"));let e=this.userdb;this.user&&this.user.id&&(e=`${this.userdb.path}@${this.user.id}`.asFileHandle()),e.cache=this.user;const i=await e.write(void 0);if(i.error)throw new Error(i.error);this.user.id||(this.user.id=i.result),this.toast(__("User data updated"))}catch(t){this.error(__("Cannot save user data: {0}",t.toString()),t)}}refreshCVCat(){return this.fetchCVCat().then(t=>(this.cvlist.data=t,this.cvlist.expandAll())).catch(t=>this.error(__("Unable to load categories"),t))}fetchCVCat(){return new Promise(async(t,e)=>{try{const e={text:"Porfolio",id:0,nodes:[]},i={order:["name$asc"]},a=await this.cvcatdb.read(i);this.catListToTree(a,e,0),t(e)}catch(t){e(__e(t))}})}catListToTree(t,e,i){const a=t.filter(t=>t.pid==i);if(0===a.length)return e.nodes=null;for(let i of a)i.nodes=[],i.text=i.name,this.catListToTree(t,i,i.id),e.nodes.push(i)}deleteCVCat(t){return new Promise(async(e,i)=>{try{const e=[];var a=function(t){e.push(t.id),t.nodes&&t.nodes.map(t=>a(t))};a(t);let i=await this.cvsecdb.remove({where:{$or:{cid:e}}});if(i.error)throw new Error(i.error);if(i=await this.cvcatdb.remove({where:{$or:{id:e}}}),i.error)throw new Error(i.error);await this.refreshCVCat(),this.seclist.data=[]}catch(t){i(__e(t))}})}CVSectionByCID(t){return new Promise(async(e,i)=>{try{const e=await this.cvsecdb.read({where:{cid:t},order:["start$desc"]}),i=[];this.find("cv-sec-status").text=__("Found {0} sections",e.length);for(let t of e)t.closable=!0,t.tag="afx-blogger-cvsection-item",t.start=Number(t.start),t.end=Number(t.end),t.start<1e3&&(t.start=void 0),t.end<1e3&&(t.end=void 0),i.push(t);this.seclist.data=i}catch(t){i(__e(t))}})}async saveBlog(){try{let t=void 0;const e=this.bloglist.selectedItem;e&&(t=e.data);const i=this.inputtags.value,a=this.editor.value(),s=new RegExp("^#+(.*)\n","g").exec(a);if(!s||2!==s.length)return this.toast(__("Please insert a title in the text: beginning with heading"));if(""===i)return this.toast(__("Please enter tags"));const n=new Date,r={content:a,title:s[1].trim(),tags:i,ctime:t?t.ctime:n.timestamp(),ctimestr:t?t.ctimestr:n.toString(),utime:n.timestamp(),utimestr:n.toString(),rendered:this.process(this.editor.options.previewRender(a)),publish:this.find("blog-publish").swon?1:0};let o=this.blogdb;t&&(r.id=t.id,o=t.$vfs),o.cache=r;const l=await o.write(void 0);if(l.error)throw new Error(l.error);t?e.data=r:(this.last_ctime=0,this.bloglist.data=[],await this.loadBlogs())}catch(t){this.error(__("Cannot save blog: {0}",t.toString()),t)}}process(t){let e;const i=/\[\[youtube:([^\]]*)\]\]/g,a=[];for(;null!==(e=i.exec(t));)a.push(e);if(!(a.length>0))return t;let s="",n=0;for(let e of a)s+=t.substring(n,e.index),s+=``,n=e.index+e[0].length;return s+=t.substring(n,t.length),s}clearEditor(){return this.editor.value(""),this.inputtags.value="",this.find("blog-publish").swon=!1}loadBlogs(){return new Promise(async(t,e)=>{try{const t={order:["ctime$desc"],fields:["id","title","ctimestr","ctime","utime","utimestr"],limit:10};this.last_ctime&&(t.where={ctime$lt:this.last_ctime});const e=await this.blogdb.read(t);if(0==e.length)return void this.toast(__("No more record to load"));this.last_ctime=e[e.length-1].ctime;for(let t of e)t.tag="afx-blogger-post-item",this.bloglist.push(t);return this.clearEditor(),this.bloglist.selected=-1}catch(t){e(__e(t))}})}resizeContent(){const t=this.find("editor-container"),e=$(".EasyMDEContainer",t).children(),i=$(this.scheme).find(".afx-window-top")[0],a=e[0],s=e[3],n=$(this.scheme).height()-$(i).height()-$(a).height()-$(s).height()-90;return $(e[1]).css("height",n+"px")}}t.Blogger=e,e.singleton=!0,e.dependencies=["pkg://SimpleMDE/main.js","pkg://SimpleMDE/main.css","pkg://Katex/main.js","pkg://Katex/main.css","pkg://SQLiteDB/libsqlite.js"]}(e=t.application||(t.application={}))}(OS||(OS={})),function(t){let e;!function(e){let i;!function(e){class i extends t.GUI.BasicDialog{constructor(){super("BloggerCategoryDialog",i.scheme)}main(){if(super.main(),this.tree=this.find("tree"),this.txtinput=this.find("txtinput"),this.find("bt-ok").onbtclick=t=>{const e=this.tree.selectedItem;if(!e)return this.notify(__("Please select a parent category"));const i=e.data,a=this.txtinput.value;return""!==a||this.data.selonly?this.data.cat&&this.data.cat.id===i.id?this.notify(__("Parent can not be the category itself")):(this.handle&&this.handle({p:i,value:a}),this.quit()):this.notify(__("Please enter category name"))},this.find("bt-cancel").onbtclick=t=>this.quit(),this.data&&this.data.tree){if(this.data&&this.data.cat){let t;this.txtinput.value=this.data.cat.name,t="0"===this.data.cat.pid?this.data.tree:this.findDataByID(this.data.cat.pid,this.data.tree.nodes),t&&(t.selected=!0)}return this.tree.data=this.data.tree,this.tree.expandAll()}}findDataByID(t,e){for(let i of e){if(i.id===t)return i;i.nodes&&this.findDataByID(t,i.nodes)}}}e.BloggerCategoryDialog=i,i.scheme='\n \n \n \n \n \n \n
\n \n \n
\n
\n
\n
s\n ';class a extends t.GUI.BasicDialog{constructor(){super("BloggerCVSectionDiaglog")}main(){super.main(),this.editor=new EasyMDE({autoDownloadFontAwesome:!1,element:this.find("contentarea"),status:!1,toolbar:!1}),$(this.select('[class = "CodeMirror-scroll"]')[0]).css("min-height","50px"),$(this.select('[class="CodeMirror cm-s-paper CodeMirror-wrap"]')[0]).css("min-height","50px");const t=this.select("[input-class='user-input']");if(this.data&&this.data.section)for(let e of t)$(e).val(this.data.section[e.name]);return this.data&&this.data.section&&this.editor.value(this.data.section.content),this.find("section-publish").swon=!!(this.data&&this.data.section&&Number(this.data.section.publish)),this.find("bt-cv-sec-save").onbtclick=e=>{const i={};for(let e of t)i[e.name]=$(e).val();if(i.content=this.editor.value(),""===i.title&&""===i.content)return this.notify(__("Title or content must not be blank"));this.data&&this.data.section&&(i.id=this.data.section.id);const a=this.find("section-publish").swon;return i.publish=!0===a?1:0,this.handle&&this.handle(i),this.quit()},this.on("resize",()=>this.resizeContent()),this.resizeContent()}resizeContent(){const t=this.find("editor-container"),e=$(".EasyMDEContainer",t).children(),i=$(t).height()-30;return $(e[0]).css("height",i+"px")}}e.BloggerCVSectionDiaglog=a,a.scheme='\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n
\n \n \n
\n
\n
';class s extends t.GUI.BasicDialog{constructor(){super("BloggerSendmailDiaglog")}main(){super.main(),this.maillinglist=this.find("email-list");const t=new RegExp("^#+(.*)\n","g").exec(this.data.content);this.find("mail-title").value=t[1];const e=this.data.content.substring(0,500)+"...";this.find("contentarea").value=s.template.format(this.data.id,e);const i=this.data.mails.map(t=>({text:t.name,email:t.email,switch:!0,checked:!0}));return this.maillinglist.data=i,this.find("bt-sendmail").onbtclick=t=>{const e=this.maillinglist.data,i=[];for(let t of e)!0===t.checked&&(console.log(t.email),i.push(t.email));if(0===i.length)return this.notify(__("No email selected"));const a={path:this.meta().path+"/sendmail.lua",parameters:{to:i,title:this.find("mail-title").value,content:this.find("contentarea").value}};return this._api.apigateway(a,!1).then(t=>t.error?this.notify(__("Unable to send mail to: {0}",t.result.join(","))):this.quit()).catch(t=>(console.log(t),this.error(__("Error sending mail: {0}",t.toString()),t)))}}}e.BloggerSendmailDiaglog=s,s.scheme='\n \n \n \n
\n \n
\n \n \n \n \n
\n \n
\n \n
\n
\n
\n
\n
',s.template="Hello,\n\nXuan Sang LE has just published a new post on his blog: https://blog.iohub.dev/post/id/{0}\n\n==========\n{1}\n==========\n\n\nRead the full article via:\nhttps://blog.iohub.dev/post/id/{0}\n\nYou receive this email because you have been subscribed to his blog.\n\nHave a nice day,\n\nSent from Blogger, an AntOS application"}(i=e.blogger||(e.blogger={}))}(e=t.application||(t.application={}))}(OS||(OS={})),function(t){let e;!function(e){let i;!function(e){class i extends t.GUI.tag.ListViewItemTag{constructor(){super()}ondatachange(){if(!this.data)return;const t=this.data,e=["content","start","end"];return this.closable=t.closable,(()=>{const i=[];for(let a in this.refs){const s=this.refs[a];t[a]&&""!==t[a]?e.includes(a)?i.push($(s).text(t[a])):i.push(s.text=t[a]):i.push(void 0)}return i})()}reload(){}init(){}itemlayout(){return{el:"div",children:[{el:"afx-label",ref:"title",class:"afx-cv-sec-title"},{el:"afx-label",ref:"subtitle",class:"afx-cv-sec-subtitle"},{el:"p",ref:"content",class:"afx-cv-sec-content"},{el:"p",class:"afx-cv-sec-period",children:[{el:"i",ref:"start"},{el:"i",ref:"end",class:"period-end"}]},{el:"afx-label",ref:"location",class:"afx-cv-sec-loc"}]}}}t.GUI.tag.define("afx-blogger-cvsection-item",i);class a extends t.GUI.tag.ListViewItemTag{constructor(){super()}ondatachange(){if(!this.data)return;const t=this.data;t.closable=!0,this.closable=t.closable,this.refs.title.text=t.title,this.refs.ctimestr.text=__("Created: {0}",t.ctimestr),this.refs.utimestr.text=__("Updated: {0}",t.utimestr)}reload(){}init(){}itemlayout(){return{el:"div",children:[{el:"afx-label",ref:"title",class:"afx-blogpost-title"},{el:"afx-label",ref:"ctimestr",class:"blog-dates"},{el:"afx-label",ref:"utimestr",class:"blog-dates"}]}}}t.GUI.tag.define("afx-blogger-post-item",a)}(i=e.blogger||(e.blogger={}))}(e=t.application||(t.application={}))}(OS||(OS={})); \ No newline at end of file +var OS;!function(t){let e;!function(t){class e extends t.BaseApplication{constructor(t){super("Blogger",t),this.previewOn=!1}async init_db(){try{const e=await this.openDialog("FileDialog",{title:__("Open/create new database"),file:"Untitled.db"});var t=e.file.path.asFileHandle();"file"===e.file.type&&(t=t.parent());const i=`${t.path}/${e.name}`.asFileHandle();this.dbhandle=("sqlite://"+i.genealogy.join("/")).asFileHandle();const a=await this.dbhandle.read();if(!a.user){this.dbhandle.cache={address:"TEXT",Phone:"TEXT",shortbiblio:"TEXT",fullname:"TEXT",email:"TEXT",url:"TEXT",photo:"TEXT"};const t=await this.dbhandle.write("user");if(t.error)throw new Error(t.error)}if(!a.cv_cat){this.dbhandle.cache={publish:"NUMERIC",name:"TEXT",pid:"NUMERIC"};const t=await this.dbhandle.write("cv_cat");if(t.error)throw new Error(t.error)}if(!a.cv_sections){this.dbhandle.cache={title:"TEXT",start:"NUMERIC",location:"TEXT",end:"NUMERIC",content:"TEXT",subtitle:"TEXT",publish:"NUMERIC",cid:"NUMERIC"};const t=await this.dbhandle.write("cv_sections");if(t.error)throw new Error(t.error)}if(!a.blogs){this.dbhandle.cache={tags:"TEXT",content:"TEXT",utime:"NUMERIC",rendered:"TEXT",title:"TEXT",utimestr:"TEXT",ctime:"NUMERIC",ctimestr:"TEXT",publish:"INTEGER DEFAULT 0"};const t=await this.dbhandle.write("blogs");if(t.error)throw new Error(t.error)}if(!a.st_similarity){this.dbhandle.cache={pid:"NUMERIC",sid:"NUMERIC",score:"NUMERIC"};const t=await this.dbhandle.write("st_similarity");if(t.error)throw new Error(t.error)}if(!a.subscribers){this.dbhandle.cache={name:"TEXT",email:"TEXT"};const t=await this.dbhandle.write("subscribers");if(t.error)throw new Error(t.error)}this.userdb=(this.dbhandle.path+"@user").asFileHandle(),this.cvcatdb=(this.dbhandle.path+"@cv_cat").asFileHandle(),this.cvsecdb=(this.dbhandle.path+"@cv_sections").asFileHandle(),this.blogdb=(this.dbhandle.path+"@blogs").asFileHandle(),this.subdb=(this.dbhandle.path+"@subscribers").asFileHandle(),this.last_ctime=0,this.bloglist.data=[],this.loadBlogs()}catch(t){this.error(__("Unable to init database file: {0}",t.toString()),t),this.dbhandle=void 0}}menu(){return[{text:"__(Open/Create database)",onmenuselect:t=>{this.init_db()}}]}main(){this.user={},this.cvlist=this.find("cv-list"),this.cvlist.ontreeselect=t=>{if(!t)return;const{data:e}=t.data.item;return this.CVSectionByCID(Number(e.id))},this.inputtags=this.find("input-tags"),this.bloglist=this.find("blog-list"),this.seclist=this.find("cv-sec-list");let e=this.find("photo");return $(e).on("click",async t=>{try{const t=await this.openDialog("FileDialog",{title:__("Select image file"),mimes:["image/.*"]});return e.value=t.file.path}catch(t){return this.error(__("Unable to get file"),t)}}),this.tabcontainer=this.find("tabcontainer"),this.tabcontainer.ontabselect=t=>this.fetchData(t.data.container.aid),this.find("bt-user-save").onbtclick=t=>this.saveUser(),this.find("blog-load-more").onbtclick=t=>{this.loadBlogs()},this.find("cv-cat-add").onbtclick=async e=>{try{const e=await this.fetchCVCat(),i=await this.openDialog(new t.blogger.BloggerCategoryDialog,{title:__("Add category"),tree:e});this.cvcatdb.cache={name:i.value,pid:i.p.id,publish:1};const a=await this.cvcatdb.write(void 0);if(a.error)throw new Error(a.error);await this.refreshCVCat()}catch(e){this.error(__("cv-cat-add: {0}",e.toString()),e)}},this.find("cv-cat-edit").onbtclick=async e=>{try{const e=this.cvlist.selectedItem;if(!e)return;const i=e.data;if(!i)return;const a=await this.fetchCVCat(),s=await this.openDialog(new t.blogger.BloggerCategoryDialog,{title:__("Edit category"),tree:a,cat:i}),n=i.$vfs;n.cache={id:i.id,publish:i.publish,pid:s.p.id,name:s.value};const r=await n.write(void 0);if(r.error)throw new Error(r.error);await this.refreshCVCat()}catch(e){this.error(__("cv-cat-edit: {0}",e.toString()),e)}},this.find("cv-cat-del").onbtclick=async t=>{try{const t=this.cvlist.selectedItem;if(!t)return;const e=t.data;if(!e)return;if(!await this.openDialog("YesNoDialog",{title:__("Delete category"),iconclass:"fa fa-question-circle",text:__("Do you really want to delete: {0}?",e.name)}))return;await this.deleteCVCat(e)}catch(t){this.error(__("cv-cat-del: {0}",t.toString()),t)}},this.find("cv-sec-add").onbtclick=async e=>{try{const e=this.cvlist.selectedItem;if(!e)return;const i=e.data;if(!i||"0"===i.id)return this.toast(__("Please select a category"));const a=await this.openDialog(new t.blogger.BloggerCVSectionDiaglog,{title:__("New section entry for {0}",i.name)});a.cid=Number(i.id),a.start=Number(a.start),a.end=Number(a.end),this.cvsecdb.cache=a;const s=await this.cvsecdb.write(void 0);if(s.error)throw new Error(s.error);await this.CVSectionByCID(Number(i.id))}catch(e){this.error(__("cv-sec-add: {0}",e.toString()),e)}},this.find("cv-sec-move").onbtclick=async e=>{try{const e=this.seclist.selectedItem;if(!e)return this.toast(__("Please select a section to move"));const i=e.data,a=i.$vfs;console.log(a);const s=await this.fetchCVCat(),n=await this.openDialog(new t.blogger.BloggerCategoryDialog,{title:__("Move to"),tree:s,selonly:!0});a.cache={id:i.id,cid:n.p.id};const r=await a.write(void 0);if(r.error)throw new Error(r.error);await this.CVSectionByCID(i.cid),this.seclist.unselect()}catch(e){this.error(__("cv-sec-move: {0}",e.toString()),e)}},this.find("cv-sec-edit").onbtclick=async e=>{try{const e=this.seclist.selectedItem;if(!e)return this.toast(__("Please select a section to edit"));const i=e.data,a=await this.openDialog(new t.blogger.BloggerCVSectionDiaglog,{title:__("Modify section entry"),section:i});a.cid=Number(i.cid),a.start=Number(a.start),a.end=Number(a.end);const s=i.$vfs;s.cache=a;const n=await s.write(void 0);if(n.error)throw new Error(n.error);await this.CVSectionByCID(Number(i.cid))}catch(e){this.error(__("cv-sec-edit: {0}",e.toString()),e)}},this.seclist.onitemclose=t=>{if(!t)return;const e=t.data.item.data;return this.openDialog("YesNoDialog",{iconclass:"fa fa-question-circle",text:__("Do you really want to delete: {0}?",e.title)}).then(async i=>{if(i)try{const i=await this.cvsecdb.remove({where:{id:e.id}});if(i.error)throw new Error(i.error);return this.seclist.delete(t.data.item)}catch(t){return this.error(__("Cannot delete the section: {0}",t.toString()),t)}}),!1},this.editor=new EasyMDE({element:this.find("markarea"),autoDownloadFontAwesome:!1,autofocus:!0,tabSize:4,indentWithTabs:!0,toolbar:[{name:__("New"),className:"fa fa-file",action:t=>(this.bloglist.unselect(),this.clearEditor())},{name:__("Save"),className:"fa fa-save",action:t=>this.saveBlog()},"|","bold","italic","heading","|","quote","code","unordered-list","ordered-list","|","link","image","table","horizontal-rule",{name:"image",className:"fa fa-file-image-o",action:t=>this.openDialog("FileDialog",{title:__("Select image file"),mimes:["image/.*"]}).then(t=>t.file.path.asFileHandle().publish().then(t=>this.editor.codemirror.getDoc().replaceSelection(`![](${this._api.handle.shared}/${t.result})`)).catch(t=>this.error(__("Cannot export file for embedding to text"),t)))},{name:"Youtube",className:"fa fa-youtube",action:t=>this.editor.codemirror.getDoc().replaceSelection("[[youtube:]]")},"|",{name:__("Preview"),className:"fa fa-eye no-disable",action:t=>{this.previewOn=!this.previewOn,EasyMDE.togglePreview(t),renderMathInElement(this.find("editor-container"))}},"|",{name:__("Send mail"),className:"fa fa-paper-plane",action:async e=>{try{const e=await this.subdb.read(),i=this.bloglist.selectedItem;if(!i)return this.error(__("No post selected"));const a=i.data;await this.openDialog(new t.blogger.BloggerSendmailDiaglog,{title:__("Send mail"),content:this.editor.value(),mails:e,id:a.id}),this.toast(__("Emails sent"))}catch(e){this.error(__("Error sending mails: {0}",e.toString()),e)}}}]}),this.bloglist.onlistselect=async t=>{const e=this.bloglist.selectedItem;if(!e)return;const i=e.data;if(i)try{const t=await this.blogdb.read({where:{id:Number(i.id)}});if(!t||0==t.length)throw new Error(__("No record found for ID {}",i.id).__());const e=t[0];return this.editor.value(e.content),this.inputtags.value=e.tags,this.find("blog-publish").swon=!!Number(e.publish)}catch(t){return this.error(__("Cannot fetch the entry content"),t)}},this.bloglist.onitemclose=t=>{if(!t)return;const e=t.data.item,i=e.data;return this.openDialog("YesNoDialog",{title:__("Delete a post"),iconclass:"fa fa-question-circle",text:__("Do you really want to delete this post ?")}).then(async t=>{if(!t)return;const a=await this.blogdb.remove({where:{id:Number(i.id)}});if(a.error)throw new Error(a.error);return this.bloglist.delete(e),this.bloglist.unselect(),this.clearEditor()}),!1},this.bindKey("CTRL-S",()=>{const t=this.tabcontainer.selectedTab;if(t&&"blog-container"===t.container.aid)return this.saveBlog()}),this.on("resize",()=>this.resizeContent()),this.resizeContent(),this.init_db()}fetchData(t){switch(t){case"user-container":return this.userdb.read().then(t=>{if(t&&0!=t.length)return this.user=t[0],this.select("[input-class='user-input']").map((t,e)=>$(e).val(this.user[e.name]))}).catch(t=>this.error(__("Cannot fetch user data"),t));case"cv-container":return this.refreshCVCat();default:return this.last_ctime=0,this.bloglist.data=[],this.loadBlogs()}}async saveUser(){try{const t=this.select("[input-class='user-input']");for(let e of t)this.user[e.name]=$(e).val();if(!this.user.fullname||""===this.user.fullname)return this.toast(__("Full name must be entered"));let e=this.userdb;this.user&&this.user.id&&(e=`${this.userdb.path}@${this.user.id}`.asFileHandle()),e.cache=this.user;const i=await e.write(void 0);if(i.error)throw new Error(i.error);this.user.id||(this.user.id=i.result),this.toast(__("User data updated"))}catch(t){this.error(__("Cannot save user data: {0}",t.toString()),t)}}refreshCVCat(){return this.fetchCVCat().then(t=>(this.cvlist.data=t,this.cvlist.expandAll())).catch(t=>this.error(__("Unable to load categories"),t))}fetchCVCat(){return new Promise(async(t,e)=>{try{const e={text:"Porfolio",id:0,nodes:[]},i={order:["name$asc"]},a=await this.cvcatdb.read(i);this.catListToTree(a,e,0),t(e)}catch(t){e(__e(t))}})}catListToTree(t,e,i){const a=t.filter(t=>t.pid==i);if(0===a.length)return e.nodes=null;for(let i of a)i.nodes=[],i.text=i.name,this.catListToTree(t,i,i.id),e.nodes.push(i)}deleteCVCat(t){return new Promise(async(e,i)=>{try{const e=[];var a=function(t){e.push(t.id),t.nodes&&t.nodes.map(t=>a(t))};a(t);let i=await this.cvsecdb.remove({where:{$or:{cid:e}}});if(i.error)throw new Error(i.error);if(i=await this.cvcatdb.remove({where:{$or:{id:e}}}),i.error)throw new Error(i.error);await this.refreshCVCat(),this.seclist.data=[]}catch(t){i(__e(t))}})}CVSectionByCID(t){return new Promise(async(e,i)=>{try{const e=await this.cvsecdb.read({where:{cid:t},order:["start$desc"]}),i=[];this.find("cv-sec-status").text=__("Found {0} sections",e.length);for(let t of e)t.closable=!0,t.tag="afx-blogger-cvsection-item",t.start=Number(t.start),t.end=Number(t.end),t.start<1e3&&(t.start=void 0),t.end<1e3&&(t.end=void 0),i.push(t);this.seclist.data=i}catch(t){i(__e(t))}})}async saveBlog(){try{let t=void 0;const e=this.bloglist.selectedItem;e&&(t=e.data);const i=this.inputtags.value,a=this.editor.value(),s=new RegExp("^#+(.*)\n","g").exec(a);if(!s||2!==s.length)return this.toast(__("Please insert a title in the text: beginning with heading"));if(""===i)return this.toast(__("Please enter tags"));const n=new Date,r={content:a,title:s[1].trim(),tags:i,ctime:t?t.ctime:n.timestamp(),ctimestr:t?t.ctimestr:n.toString(),utime:n.timestamp(),utimestr:n.toString(),rendered:this.process(this.editor.options.previewRender(a)),publish:this.find("blog-publish").swon?1:0};let o=this.blogdb;t&&(r.id=t.id,o=t.$vfs),o.cache=r;const l=await o.write(void 0);if(l.error)throw new Error(l.error);t?e.data=r:(this.last_ctime=0,this.bloglist.data=[],await this.loadBlogs())}catch(t){this.error(__("Cannot save blog: {0}",t.toString()),t)}}process(t){let e;const i=/\[\[youtube:([^\]]*)\]\]/g,a=[];for(;null!==(e=i.exec(t));)a.push(e);if(!(a.length>0))return t;let s="",n=0;for(let e of a)s+=t.substring(n,e.index),s+=``,n=e.index+e[0].length;return s+=t.substring(n,t.length),s}clearEditor(){return this.editor.value(""),this.inputtags.value="",this.find("blog-publish").swon=!1}loadBlogs(){return new Promise(async(t,e)=>{try{const t={order:["ctime$desc"],fields:["id","title","ctimestr","ctime","utime","utimestr"],limit:10};this.last_ctime&&(t.where={ctime$lt:this.last_ctime});const e=await this.blogdb.read(t);if(0==e.length)return void this.toast(__("No more record to load"));this.last_ctime=e[e.length-1].ctime;for(let t of e)t.tag="afx-blogger-post-item",this.bloglist.push(t);return this.clearEditor(),this.bloglist.selected=-1}catch(t){e(__e(t))}})}resizeContent(){const t=this.find("editor-container"),e=$(".EasyMDEContainer",t).children(),i=$(this.scheme).find(".afx-window-top")[0],a=e[0],s=e[3],n=$(this.scheme).height()-$(i).height()-$(a).height()-$(s).height()-90;return $(e[1]).css("height",n+"px")}}t.Blogger=e,e.singleton=!0,e.dependencies=["pkg://SimpleMDE/main.js","pkg://SimpleMDE/main.css","pkg://Katex/main.js","pkg://Katex/main.css","pkg://SQLiteDB/libsqlite.js"]}(e=t.application||(t.application={}))}(OS||(OS={})),function(t){let e;!function(e){let i;!function(e){class i extends t.GUI.BasicDialog{constructor(){super("BloggerCategoryDialog",i.scheme)}main(){if(super.main(),this.tree=this.find("tree"),this.txtinput=this.find("txtinput"),this.find("bt-ok").onbtclick=t=>{const e=this.tree.selectedItem;if(!e)return this.notify(__("Please select a parent category"));const i=e.data,a=this.txtinput.value;return""!==a||this.data.selonly?this.data.cat&&this.data.cat.id===i.id?this.notify(__("Parent can not be the category itself")):(this.handle&&this.handle({p:i,value:a}),this.quit()):this.notify(__("Please enter category name"))},this.find("bt-cancel").onbtclick=t=>this.quit(),this.data&&this.data.tree){if(this.data&&this.data.cat){let t;this.txtinput.value=this.data.cat.name,t="0"===this.data.cat.pid?this.data.tree:this.findDataByID(this.data.cat.pid,this.data.tree.nodes),t&&(t.selected=!0)}return this.tree.data=this.data.tree,this.tree.expandAll()}}findDataByID(t,e){for(let i of e){if(i.id===t)return i;i.nodes&&this.findDataByID(t,i.nodes)}}}e.BloggerCategoryDialog=i,i.scheme='\n \n \n \n \n \n \n
\n \n \n
\n
\n
\n
s\n ';class a extends t.GUI.BasicDialog{constructor(){super("BloggerCVSectionDiaglog")}main(){super.main(),this.editor=new EasyMDE({autoDownloadFontAwesome:!1,element:this.find("contentarea"),status:!1,toolbar:!1}),$(this.select('[class = "CodeMirror-scroll"]')[0]).css("min-height","50px"),$(this.select('[class="CodeMirror cm-s-paper CodeMirror-wrap"]')[0]).css("min-height","50px");const t=this.select("[input-class='user-input']");if(this.data&&this.data.section)for(let e of t)$(e).val(this.data.section[e.name]);return this.data&&this.data.section&&this.editor.value(this.data.section.content),this.find("section-publish").swon=!!(this.data&&this.data.section&&Number(this.data.section.publish)),this.find("bt-cv-sec-save").onbtclick=e=>{const i={};for(let e of t)i[e.name]=$(e).val();if(i.content=this.editor.value(),""===i.title&&""===i.content)return this.notify(__("Title or content must not be blank"));this.data&&this.data.section&&(i.id=this.data.section.id);const a=this.find("section-publish").swon;return i.publish=!0===a?1:0,this.handle&&this.handle(i),this.quit()},this.on("resize",()=>this.resizeContent()),this.resizeContent()}resizeContent(){const t=this.find("editor-container"),e=$(".EasyMDEContainer",t).children(),i=$(t).height()-30;return $(e[0]).css("height",i+"px")}}e.BloggerCVSectionDiaglog=a,a.scheme='\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n
\n \n \n
\n
\n
';class s extends t.GUI.BasicDialog{constructor(){super("BloggerSendmailDiaglog")}main(){super.main(),this.maillinglist=this.find("email-list");const t=new RegExp("^#+(.*)\n","g").exec(this.data.content);this.find("mail-title").value=t[1];const e=this.data.content.substring(0,500)+"...";this.find("contentarea").value=s.template.format(this.data.id,e);const i=this.data.mails.map(t=>({text:t.name,email:t.email,switch:!0,checked:!0}));return console.log(i),this.maillinglist.items=i,this.find("bt-sendmail").onbtclick=t=>{const e=this.maillinglist.items,i=[];for(let t of e)!0===t.checked&&i.push(t);if(0===i.length)return this.notify(__("No email selected"));const a={path:this.meta().path+"/sendmail.lua",parameters:{to:i,title:this.find("mail-title").value,content:this.find("contentarea").value,user:this.find("mail-user").value,password:this.find("mail-password").value}};return this._api.apigateway(a,!1).then(t=>{if(t.error){const e=t.result.join(",");return this.notify(__("Unable to send mail to: {0}",e))}return this.quit()}).catch(t=>this.error(__("Error sending mail: {0}",t.toString()),t))}}}e.BloggerSendmailDiaglog=s,s.scheme='\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n
\n
\n
\n
',s.template="Hello,\n\nDany LE has just published a new post on his blog: https://blog.iohub.dev/post/id/{0}\n\n==========\n{1}\n==========\n\n\nRead the full article via:\nhttps://blog.iohub.dev/post/id/{0}\n\nYou receive this email because you have been subscribed to his blog.\n\nHave a nice day,\n\nSent from Blogger, an AntOS application"}(i=e.blogger||(e.blogger={}))}(e=t.application||(t.application={}))}(OS||(OS={})),function(t){let e;!function(e){let i;!function(e){class i extends t.GUI.tag.ListViewItemTag{constructor(){super()}ondatachange(){if(!this.data)return;const t=this.data,e=["content","start","end"];return this.closable=t.closable,(()=>{const i=[];for(let a in this.refs){const s=this.refs[a];t[a]&&""!==t[a]?e.includes(a)?i.push($(s).text(t[a])):i.push(s.text=t[a]):i.push(void 0)}return i})()}reload(){}init(){}itemlayout(){return{el:"div",children:[{el:"afx-label",ref:"title",class:"afx-cv-sec-title"},{el:"afx-label",ref:"subtitle",class:"afx-cv-sec-subtitle"},{el:"p",ref:"content",class:"afx-cv-sec-content"},{el:"p",class:"afx-cv-sec-period",children:[{el:"i",ref:"start"},{el:"i",ref:"end",class:"period-end"}]},{el:"afx-label",ref:"location",class:"afx-cv-sec-loc"}]}}}t.GUI.tag.define("afx-blogger-cvsection-item",i);class a extends t.GUI.tag.ListViewItemTag{constructor(){super()}ondatachange(){if(!this.data)return;const t=this.data;t.closable=!0,this.closable=t.closable,this.refs.title.text=t.title,this.refs.ctimestr.text=__("Created: {0}",t.ctimestr),this.refs.utimestr.text=__("Updated: {0}",t.utimestr)}reload(){}init(){}itemlayout(){return{el:"div",children:[{el:"afx-label",ref:"title",class:"afx-blogpost-title"},{el:"afx-label",ref:"ctimestr",class:"blog-dates"},{el:"afx-label",ref:"utimestr",class:"blog-dates"}]}}}t.GUI.tag.define("afx-blogger-post-item",a)}(i=e.blogger||(e.blogger={}))}(e=t.application||(t.application={}))}(OS||(OS={})); \ No newline at end of file diff --git a/Blogger/build/debug/package.json b/Blogger/build/debug/package.json index 67e3f7b..8baf217 100644 --- a/Blogger/build/debug/package.json +++ b/Blogger/build/debug/package.json @@ -28,6 +28,8 @@ "Location": "Location", "From": "From", "Save": "Save", + "Content": "Content", + "IO Hub mail username/password": "IO Hub mail username/password", "Send": "Send", "Please select a parent category": "Please select a parent category", "Please enter category name": "Please enter category name", @@ -36,6 +38,7 @@ "No email selected": "No email selected", "Unable to send mail to: {0}": "Unable to send mail to: {0}", "Error sending mail: {0}": "Error sending mail: {0}", + "Open/Create database": "Open/Create database", "Open/create new database": "Open/create new database", "Unable to init database file: {0}": "Unable to init database file: {0}", "Select image file": "Select image file", diff --git a/Blogger/build/debug/sendmail.lua b/Blogger/build/debug/sendmail.lua index 6e8aab4..8d98a3a 100644 --- a/Blogger/build/debug/sendmail.lua +++ b/Blogger/build/debug/sendmail.lua @@ -1,30 +1,42 @@ local data = ... --- print(data.content) +-- load the smtp support +local smtp = require("socket.smtp") + +local from = string.format("<%s@iohub.dev>", data.user); + +local mesgt = { + headers = { + from = string.format("Dany <%s@iohub.dev>", data.user), + to = "", + subject = data.title + }, + body = data.content +} + local error_msg = {} local iserror = false -local tmp_name = "/tmp/"..os.time(os.date("!*t")) -local file = io.open (tmp_name , "w") -if file then - file:write("From: mrsang@lxsang.me\n") - file:write("Subject: " .. data.title .. "\n") - file:write( data.content.."\n") - file:close() - for k,v in pairs(data.to) do - print("sent to:"..v) - local to = v - local cmd = 'cat ' ..tmp_name .. '| sendmail ' .. to - --print(cmd) - local r = os.execute(cmd) - if not r then - iserror = true - table.insert(error_msg, v) - print("Unable to send mail to: "..v) - end + +for k,v in pairs(data.to) do + LOG_DEBUG("Send email to:"..v.email) + local rcpt = string.format("<%s>",v.email) + mesgt.headers.to = string.format("%s <%s>",v.text, v.email) + local r, e = smtp.send{ + from = from, + rcpt = rcpt, + server = "iohub.dev", + domain = "iohub.dev", + user = data.user, + password = data.password, + source = smtp.message(mesgt) + } + + local r = os.execute(cmd) + if not r then + iserror = true + table.insert(error_msg, v.email) + LOG_ERROR(string.format("Unable to send mail to %s: %s",v.email, e)) end -else - iserror = true - table.insert(error_msg, "Cannot create mail file") end local result = {} result.error = iserror diff --git a/Blogger/build/release/Blogger.zip b/Blogger/build/release/Blogger.zip index ea7d5ea4fe51192f27776fec6e027ae4c17664d1..eb345506d399a23743ddc703537f90df090f5342 100644 GIT binary patch delta 8394 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 Gz5fA`=i%M} delta 8181 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 diff --git a/Blogger/dialogs.ts b/Blogger/dialogs.ts index 8453425..f0167dc 100644 --- a/Blogger/dialogs.ts +++ b/Blogger/dialogs.ts @@ -175,7 +175,7 @@ namespace OS { // this dialog is for send mail export class BloggerSendmailDiaglog extends OS.GUI.BasicDialog { static template: string; - private maillinglist: OS.GUI.tag.ListViewTag; + private maillinglist: OS.GUI.tag.StackMenuTag; // TODO: convert to SQLite handle private subdb: API.VFS.BaseFileHandle; constructor() { @@ -184,7 +184,7 @@ namespace OS { main() { super.main(); - this.maillinglist = this.find("email-list") as OS.GUI.tag.ListViewTag; + this.maillinglist = this.find("email-list") as OS.GUI.tag.StackMenuTag; const title = (new RegExp("^#+(.*)\n", "g")).exec(this.data.content); (this.find("mail-title") as HTMLInputElement).value = title[1]; const content = (this.data.content.substring(0, 500)) + "..."; @@ -196,16 +196,16 @@ namespace OS { switch: true, checked: true } - }) - this.maillinglist.data = mlist; + }); + console.log(mlist); + this.maillinglist.items = mlist; return (this.find("bt-sendmail") as OS.GUI.tag.ButtonTag).onbtclick = (e: any) => { - const items = this.maillinglist.data; + const items = this.maillinglist.items; const emails = []; for (let v of items) { if (v.checked === true) { - console.log(v.email); - emails.push(v.email); + emails.push(v); } } @@ -216,15 +216,18 @@ namespace OS { parameters: { to: emails, title: (this.find("mail-title") as HTMLInputElement).value, - content: (this.find("contentarea") as HTMLTextAreaElement).value + content: (this.find("contentarea") as HTMLTextAreaElement).value, + user: (this.find("mail-user") as HTMLInputElement).value, + password: (this.find("mail-password") as HTMLInputElement).value, } }; return this._api.apigateway(data, false) .then((d: { error: any; result: { join: (arg0: string) => any; }; }) => { - if (d.error) { return this.notify(__("Unable to send mail to: {0}", d.result.join(","))); } + if (d.error) { + const str = d.result.join(','); + return this.notify(__("Unable to send mail to: {0}", str)); } return this.quit(); }).catch((e) => { - console.log(e); return this.error(__("Error sending mail: {0}", e.toString()), e); }); }; @@ -232,24 +235,25 @@ namespace OS { } BloggerSendmailDiaglog.scheme = `\ - - - + + + -
-
- - + + -
+ + + + +
- +
-
`; @@ -257,7 +261,7 @@ namespace OS { BloggerSendmailDiaglog.template = `\ Hello, -Xuan Sang LE has just published a new post on his blog: https://blog.iohub.dev/post/id/{0} +Dany LE has just published a new post on his blog: https://blog.iohub.dev/post/id/{0} ========== {1} diff --git a/Blogger/package.json b/Blogger/package.json index 67e3f7b..8baf217 100644 --- a/Blogger/package.json +++ b/Blogger/package.json @@ -28,6 +28,8 @@ "Location": "Location", "From": "From", "Save": "Save", + "Content": "Content", + "IO Hub mail username/password": "IO Hub mail username/password", "Send": "Send", "Please select a parent category": "Please select a parent category", "Please enter category name": "Please enter category name", @@ -36,6 +38,7 @@ "No email selected": "No email selected", "Unable to send mail to: {0}": "Unable to send mail to: {0}", "Error sending mail: {0}": "Error sending mail: {0}", + "Open/Create database": "Open/Create database", "Open/create new database": "Open/create new database", "Unable to init database file: {0}": "Unable to init database file: {0}", "Select image file": "Select image file",