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 ea7d5ea..eb34550 100644 Binary files a/Blogger/build/release/Blogger.zip and b/Blogger/build/release/Blogger.zip differ 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",