From 84fd9baf5add4ec835b64576d4d47a0fd55a9b5f Mon Sep 17 00:00:00 2001 From: Yannick Reekmans Date: Mon, 20 Apr 2020 15:52:29 +0000 Subject: [PATCH] Add v3.13.4 --- ...r.min-dd367fd71acbc2c70621e55ba07b7193.js} | 96 +++++----- core/frontend/meta/schema.js | 5 +- .../services/routing/config/canary.js | 2 +- core/frontend/services/routing/config/v2.js | 2 +- core/frontend/services/routing/config/v3.js | 2 +- core/server/api/canary/email-preview.js | 12 +- .../utils/validators/input/schemas/pages.json | 1 + .../utils/validators/input/schemas/posts.json | 1 + .../utils/validators/utils/json-schema.js | 12 +- .../utils/validators/input/schemas/pages.json | 1 + .../utils/validators/input/schemas/posts.json | 1 + .../v2/utils/validators/utils/json-schema.js | 12 +- core/server/services/mega/mega.js | 70 ++++++-- .../services/mega/post-email-serializer.js | 70 +++++++- core/server/web/admin/views/default-prod.html | 2 +- core/server/web/admin/views/default.html | 2 +- .../shared/middlewares/api/spam-prevention.js | 8 +- package.json | 34 ++-- yarn.lock | 169 +++++++++++------- 19 files changed, 335 insertions(+), 167 deletions(-) rename core/built/assets/{vendor.min-d101f3d8eb38856c4ed168cee6232f37.js => vendor.min-dd367fd71acbc2c70621e55ba07b7193.js} (99%) diff --git a/core/built/assets/vendor.min-d101f3d8eb38856c4ed168cee6232f37.js b/core/built/assets/vendor.min-dd367fd71acbc2c70621e55ba07b7193.js similarity index 99% rename from core/built/assets/vendor.min-d101f3d8eb38856c4ed168cee6232f37.js rename to core/built/assets/vendor.min-dd367fd71acbc2c70621e55ba07b7193.js index c3577ec0f0..b868f980db 100644 --- a/core/built/assets/vendor.min-d101f3d8eb38856c4ed168cee6232f37.js +++ b/core/built/assets/vendor.min-dd367fd71acbc2c70621e55ba07b7193.js @@ -10952,21 +10952,20 @@ break case"ArrowUp":case"ArrowLeft":r&&0===t&&(e.preventDefault(),e.target.blur(),this.moveCursorToPrevSection()) break case"ArrowRight":case"ArrowDown":r&&n===i.length&&(e.preventDefault(),e.target.blur(),this.moveCursorToNextSection())}}))}) -e.default=i})),define("koenig-editor/components/koenig-basic-html-input",["exports","mobiledoc-kit/editor/editor","@tryghost/kg-clean-basic-html","koenig-editor/templates/components/koenig-basic-html-input","koenig-editor/options/basic-html-parser-plugins","koenig-editor/options/key-commands","validator","koenig-editor/lib/dnd/constants","koenig-editor/components/koenig-editor","mobiledoc-kit/utils/parse-utils","koenig-editor/utils/markup-utils","koenig-editor/options/text-expansions"],(function(e,t,n,i,r,a,o,s,l,u,c,d){"use strict" +e.default=i})),define("koenig-editor/components/koenig-basic-html-input",["exports","mobiledoc-kit/editor/editor","@tryghost/kg-clean-basic-html","koenig-editor/templates/components/koenig-basic-html-input","koenig-editor/options/basic-html-parser-plugins","koenig-editor/options/key-commands","validator","koenig-editor/components/koenig-editor","koenig-editor/lib/dnd/constants","mobiledoc-kit/utils/parse-utils","koenig-editor/utils/markup-utils","koenig-editor/options/text-expansions"],(function(e,t,n,i,r,a,o,s,l,u,c,d){"use strict" Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0 -const h={version:"0.3.1",markups:[],atoms:[],cards:[],sections:[[1,"p",[[0,[],0,""]]]]} -var p=Ember.Component.extend({layout:i.default,autofocus:!1,html:null,placeholder:"",spellcheck:!0,activeMarkupTagNames:null,editor:null,linkRange:null,mobiledoc:null,selectedRange:null,_hasFocus:!1,_lastMobiledoc:null,_startedRunLoop:!1,willCreateEditor(){},didCreateEditor(){},onChange(){},onNewline(){},onFocus(){},onBlur(){},cleanHTML:Ember.computed("html",(function(){return(0,n.default)(this.html)})),editorOptions:Ember.computed("cleanHTML",(function(){let e=this.options||{},t=this.atoms||[],n=this.cards||[] -return Ember.assign({html:"

".concat(this.cleanHTML||"","

"),placeholder:this.placeholder,spellcheck:this.spellcheck,autofocus:this.autofocus,cards:n,atoms:t,unknownCardHandler(){},unknownAtomHandler(){}},e)})),didReceiveAttrs(){this._super(...arguments),this.cleanHTML!==this._getHTML()&&this.set("mobiledoc",null)},willRender(){let e=this.mobiledoc -e||this.cleanHTML||(e=h) +var h=Ember.Component.extend({layout:i.default,autofocus:!1,html:null,placeholder:"",spellcheck:!0,activeMarkupTagNames:null,editor:null,linkRange:null,mobiledoc:null,selectedRange:null,_hasFocus:!1,_lastMobiledoc:null,_startedRunLoop:!1,willCreateEditor(){},didCreateEditor(){},onChange(){},onNewline(){},onFocus(){},onBlur(){},cleanHTML:Ember.computed("html",(function(){return(0,n.default)(this.html)})),editorOptions:Ember.computed("cleanHTML",(function(){let e=this.options||{},t=this.atoms||[],n=this.cards||[] +return Ember.assign({html:"

".concat(this.cleanHTML||"","

"),placeholder:this.placeholder,spellcheck:this.spellcheck,autofocus:this.autofocus,cards:n,atoms:t,unknownCardHandler(){},unknownAtomHandler(){}},e)})),init(){this._super(...arguments),this.SPECIAL_MARKUPS=[]},didReceiveAttrs(){this._super(...arguments),this.cleanHTML!==this._getHTML()&&this.set("mobiledoc",null)},willRender(){let e=this.mobiledoc +e||this.cleanHTML||(e=s.BLANK_DOC) let n=this._lastMobiledoc&&this._lastMobiledoc===e,i=this._lastIsEditingDisabled===this.isEditingDisabled if(n&&i)return this._lastIsEditingDisabled=this.isEditingDisabled,this.willCreateEditor() let o=this.editor o&&o.destroy() -let s=this.editorOptions -s.mobiledoc=e,s.showLinkTooltips=!1,s.undoDepth=50,s.parserPlugins=r.default,o=new t.default(s),(0,a.default)(o,this,a.BASIC_KEY_COMMANDS),(0,d.registerBasicTextExpansions)(o),o.willRender(()=>{Ember.run.currentRunLoop||(this._startedRunLoop=!0,Ember.run.begin())}),o.didRender(()=>{this._startedRunLoop&&(this._startedRunLoop=!1,Ember.run.end())}),o.willHandleNewline(e=>{Ember.run.join(()=>{this.willHandleNewline(e)})}),o.didUpdatePost(e=>{Ember.run.join(()=>{this.didUpdatePost(e)})}),o.postDidChange(()=>{Ember.run.join(()=>{this.postDidChange(o)})}),o.cursorDidChange(()=>{Ember.run.join(()=>{this.cursorDidChange(o)})}),o.inputModeDidChange(()=>{this.isDestroyed||Ember.run.join(()=>{this.inputModeDidChange(o)})}),this.isEditingDisabled&&o.disableEditing(),this.mobiledoc=o.serialize(),this._lastMobiledoc=this.mobiledoc,this.set("editor",o),this.didCreateEditor(o)},didInsertElement(){this._super(...arguments) +let l=this.editorOptions +l.mobiledoc=e,l.showLinkTooltips=!1,l.undoDepth=50,l.parserPlugins=r.default,o=new t.default(l),(0,a.default)(o,this,a.BASIC_KEY_COMMANDS),(0,d.registerBasicTextExpansions)(o),o.willRender(()=>{Ember.run.currentRunLoop||(this._startedRunLoop=!0,Ember.run.begin())}),o.didRender(()=>{this._startedRunLoop&&(this._startedRunLoop=!1,Ember.run.end())}),o.willHandleNewline(e=>{Ember.run.join(()=>{this.willHandleNewline(e)})}),o.didUpdatePost(e=>{Ember.run.join(()=>{this.didUpdatePost(e)})}),o.postDidChange(()=>{Ember.run.join(()=>{this.postDidChange(o)})}),o.cursorDidChange(()=>{Ember.run.join(()=>{this.cursorDidChange(o)})}),o.inputModeDidChange(()=>{this.isDestroyed||Ember.run.join(()=>{this.inputModeDidChange(o)})}),this.isEditingDisabled&&o.disableEditing(),this.mobiledoc=o.serialize(s.MOBILEDOC_VERSION),this._lastMobiledoc=this.mobiledoc,this.set("editor",o),this.didCreateEditor(o)},didInsertElement(){this._super(...arguments) let e=this.element.querySelector('[data-kg="editor"]') -this._pasteHandler=Ember.run.bind(this,this.handlePaste),e.addEventListener("paste",this._pasteHandler),this.element.dataset[s.DRAG_DISABLED_DATA_ATTR]="true"},didRender(){this._super(...arguments) +this._pasteHandler=Ember.run.bind(this,this.handlePaste),e.addEventListener("paste",this._pasteHandler),this.element.dataset[l.DRAG_DISABLED_DATA_ATTR]="true"},didRender(){this._super(...arguments) let{editor:e}=this if(!e.hasRendered){let t=this.element.querySelector('[data-kg="editor"]') this._isRenderingEditor=!0,e.render(t),this._isRenderingEditor=!1}},willDestroyElement(){this._super(...arguments),this.element.querySelector('[data-kg="editor"]').removeEventListener("paste",this._pasteHandler),this.editor.destroy()},actions:{toggleMarkup(e,t){(t||this.editor).toggleMarkup(e)},editLink(e){let t=(0,c.getLinkMarkupFromRange)(e) @@ -10976,11 +10975,11 @@ return t.run(e=>{e.addMarkupToRange(n,r)}),t.selectRange(n.tail),e.preventDefaul if(i.sections.forEach(t=>{if(!t.isMarkerable&&!t.isListSection){let r=t===n.activeSection e.removeSection(t),r&&e.setRange(i.sections.head.tailPosition())}}),i.sections.length>1){for(;i.sections.length>1;)e.removeSection(i.sections.tail) e.setRange(i.sections.head.tailPosition())}if(i.sections.head.isListSection){let n=i.sections.head,r=n.items.head.markers.map(e=>e.clone()),a=t.createMarkupSection("p",r) -e.replaceSection(n,a),e.setRange(i.sections.head.tailPosition())}},postDidChange(){this.onChange(this._getHTML())},cursorDidChange(e){(0,l.toggleSpecialFormatEditState)(e),this.set("selectedRange",e.range)},inputModeDidChange(e){let t=(0,l.arrayToMap)(e.activeMarkups.map(e=>e.tagName));(0,l.toggleSpecialFormatEditState)(e),this._isRenderingEditor?Ember.run.schedule("afterRender",()=>{this.set("activeMarkupTagNames",t)}):this.set("activeMarkupTagNames",t)},_getHTML(){if(this.editor&&this.editor.element){let e=this.editor.element.querySelector("p") +e.replaceSection(n,a),e.setRange(i.sections.head.tailPosition())}},postDidChange(){this.onChange(this._getHTML())},cursorDidChange(e){(0,s.toggleSpecialFormatEditState)(e),this.set("selectedRange",e.range)},inputModeDidChange(e){let t=(0,s.arrayToMap)(e.activeMarkups.map(e=>e.tagName));(0,s.toggleSpecialFormatEditState)(e),this._isRenderingEditor?Ember.run.schedule("afterRender",()=>{this.set("activeMarkupTagNames",t)}):this.set("activeMarkupTagNames",t)},_getHTML(){if(this.editor&&this.editor.element){let e=this.editor.element.querySelector("p") if(!e)return"" let t=e.innerHTML return(0,n.default)(t)}}}) -e.default=p})),define("koenig-editor/components/koenig-caption-input",["exports","mobiledoc-kit/utils/key","koenig-editor/templates/components/koenig-caption-input","koenig-editor/helpers/kg-style"],(function(e,t,n,i){"use strict" +e.default=h})),define("koenig-editor/components/koenig-caption-input",["exports","mobiledoc-kit/utils/key","koenig-editor/templates/components/koenig-caption-input","koenig-editor/helpers/kg-style"],(function(e,t,n,i){"use strict" Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0 var r=Ember.Component.extend({koenigUi:Ember.inject.service(),tagName:"figcaption",classNameBindings:["figCaptionClass"],layout:n.default,caption:"",captureInput:!1,placeholder:"",_keypressHandler:null,_keydownHandler:null,update(){},addParagraphAfterCard(){},moveCursorToNextSection(){},moveCursorToPrevSection(){},figCaptionClass:Ember.computed((function(){return"".concat((0,i.kgStyle)(["figcaption"])," w-100 relative")})),didReceiveAttrs(){this._super(...arguments),this.captureInput&&!this._keypressHandler&&this._attachHandlers(),!this.captureInput&&this._keypressHandler&&this._detachHandlers()},willDestroyElement(){this._super(...arguments),this.koenigUi.captionLostFocus(this),this._detachHandlers()},actions:{registerEditor(e){let t={ENTER:Ember.run.bind(this,this._enter),ESC:Ember.run.bind(this,this._escape),UP:Ember.run.bind(this,this._upOrLeft),LEFT:Ember.run.bind(this,this._upOrLeft),DOWN:Ember.run.bind(this,this._rightOrDown),RIGHT:Ember.run.bind(this,this._rightOrDown)} Object.keys(t).forEach(n=>{e.registerKeyCommand({str:n,run:()=>t[n](e,n)})}),this.editor=e},handleEnter(){this.addParagraphAfterCard()}},focusIn(){this.koenigUi.captionGainedFocus(this)},focusOut(){this.koenigUi.captionLostFocus(this)},_attachHandlers(){this._keypressHandler||(this._keypressHandler=Ember.run.bind(this,this._handleKeypress),window.addEventListener("keypress",this._keypressHandler))},_detachHandlers(){window.removeEventListener("keypress",this._keypressHandler),this._keypressHandler=null,this._keydownHandler=null},_handleKeypress(e){let n=new t.default(e),{editor:i}=this @@ -11013,12 +11012,12 @@ return this.showLanguageInput||e.push("opacity: 0"),Ember.String.htmlSafe(e.join let e=this.payload||{} e.code||Ember.set(e,"code",""),this.set("payload",e),this.registerComponent(this)},actions:{updateCode(e){this._hideLanguageInput(),this._updatePayloadAttr("code",e)},updateCaption(e){this._updatePayloadAttr("caption",e)},enterEditMode(){this._addMousemoveHandler()},leaveEditMode(){this._removeMousemoveHandler(),Ember.isBlank(this.payload.code)&&Ember.run.scheduleOnce("afterRender",this,this.deleteCard)}},_updatePayloadAttr(e,t){let n=this.payload,i=this.saveCard Ember.set(n,e,t),i(n,!1)},_hideLanguageInput(){this.set("showLanguageInput",!1)},_showLanguageInput(){this.set("showLanguageInput",!0)},_addMousemoveHandler(){this._mousemoveHandler=Ember.run.bind(this,this._showLanguageInput),window.addEventListener("mousemove",this._mousemoveHandler)},_removeMousemoveHandler(){window.removeEventListener("mousemove",this._mousemoveHandler)}}) -e.default=o})),define("koenig-editor/components/koenig-card-email",["exports","mobiledoc-kit/utils/browser","koenig-editor/templates/components/koenig-card-email"],(function(e,t,n){"use strict" +e.default=o})),define("koenig-editor/components/koenig-card-email",["exports","mobiledoc-kit/utils/browser","koenig-editor/templates/components/koenig-card-email","koenig-editor/components/koenig-text-replacement-html-input"],(function(e,t,n,i){"use strict" Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0 -var i=Ember.Component.extend({layout:n.default,payload:null,isSelected:!1,isEditing:!1,selectCard(){},deselectCard(){},editCard(){},saveCard(){},deleteCard(){},moveCursorToNextSection(){},moveCursorToPrevSection(){},addParagraphAfterCard(){},registerComponent(){},init(){this._super(...arguments),this.registerComponent(this)},actions:{updateHtml(e){this._updatePayloadAttr("html",e)},registerEditor(e){let t={"META+ENTER":Ember.run.bind(this,this._enter,"meta"),"CTRL+ENTER":Ember.run.bind(this,this._enter,"ctrl")} +var r=Ember.Component.extend({layout:n.default,payload:null,isSelected:!1,isEditing:!1,selectCard(){},deselectCard(){},editCard(){},saveCard(){},deleteCard(){},moveCursorToNextSection(){},moveCursorToPrevSection(){},addParagraphAfterCard(){},registerComponent(){},formattedHtml:Ember.computed("payload.html",(function(){return(0,i.formatTextReplacementHtml)(this.payload.html)})),init(){this._super(...arguments),this.registerComponent(this)},actions:{updateHtml(e){this._updatePayloadAttr("html",e)},registerEditor(e){let t={"META+ENTER":Ember.run.bind(this,this._enter,"meta"),"CTRL+ENTER":Ember.run.bind(this,this._enter,"ctrl")} Object.keys(t).forEach(n=>{e.registerKeyCommand({str:n,run:()=>t[n](e,n)})}),this._textReplacementEditor=e},leaveEditMode(){Ember.isBlank(this.payload.html)&&Ember.run.scheduleOnce("afterRender",this,this.deleteCard)}},_updatePayloadAttr(e,t){let n=this.payload,i=this.saveCard Ember.set(n,e,t),i(n,!1)},_enter(e){this.isEditing&&("meta"===e||"crtl"===e&&t.default.isWin())&&this.editCard()}}) -e.default=i})),define("koenig-editor/components/koenig-card-embed",["exports","koenig-editor/templates/components/koenig-card-embed","koenig-editor/components/koenig-editor","@tryghost/helpers","ember-concurrency"],(function(e,t,n,i,r){"use strict" +e.default=r})),define("koenig-editor/components/koenig-card-embed",["exports","koenig-editor/templates/components/koenig-card-embed","koenig-editor/components/koenig-editor","@tryghost/helpers","ember-concurrency"],(function(e,t,n,i,r){"use strict" Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0 const{countWords:a}=i.utils var o=Ember.Component.extend({ajax:Ember.inject.service(),ghostPaths:Ember.inject.service(),layout:t.default,payload:null,isSelected:!1,isEditing:!1,hasError:!1,selectCard(){},deselectCard(){},editCard(){},saveCard(){},deleteCard(){},moveCursorToNextSection(){},moveCursorToPrevSection(){},addParagraphAfterCard(){},registerComponent(){},counts:Ember.computed("payload.{html,caption}",(function(){return{imageCount:this.payload.html?1:0,wordCount:a(this.payload.caption)}})),init(){this._super(...arguments),this.payload.url&&!this.payload.html&&this.convertUrl.perform(this.payload.url),this.registerComponent(this)},didInsertElement(){this._super(...arguments),this._populateIframe(),this._focusInput()},willDestroyElement(){this._super(...arguments),Ember.run.cancel(this._resizeDebounce),this._iframeMutationObserver&&this._iframeMutationObserver.disconnect(),window.removeEventListener("resize",this._windowResizeHandler)},actions:{onDeselect(){!this.payload.url||this.payload.html||this.hasError?this._deleteIfEmpty():this.convertUrl.perform(this.payload.url)},updateUrl(e){let t=e.target.value @@ -11133,11 +11132,12 @@ this.element.contains(t)||n.find(i("#".concat(this.element.id)))||n.find(i('[dat return t.observe(e,{childList:!0,subtree:!0}),t}(e) return{disconnect(){"disconnect"in s&&(s.disconnect(),o.forEach(r))}}},_inputFocus(){this._hasDisabledContenteditable=!0,this.editor.element.contentEditable=!1},_inputBlur(){this._hasDisabledContenteditable=!1,this.editor.element.contentEditable=!0}}) e.default=i})),define("koenig-editor/components/koenig-editor",["exports","mobiledoc-kit/utils/browser","mobiledoc-kit/editor/editor","mobiledoc-kit/utils/key","mobiledoc-kit/utils/cursor/range","koenig-editor/utils/reading-time","koenig-editor/options/atoms","koenig-editor/options/cards","ghost-admin/utils/format-markdown","koenig-editor/templates/components/koenig-editor","koenig-editor/options/key-commands","koenig-editor/options/text-expansions","validator","@tryghost/kg-parser-plugins","mobiledoc-kit/utils/parse-utils","koenig-editor/utils/markup-utils","koenig-editor/lib/dnd/utils","@tryghost/helpers","ghost-admin/helpers/svg-jar"],(function(e,t,n,i,r,a,o,s,l,u,c,d,h,p,f,m,g,b,y){"use strict" -Object.defineProperty(e,"__esModule",{value:!0}),e.arrayToMap=w,e.toggleSpecialFormatEditState=k,e.default=e.SPECIAL_MARKUPS=e.NO_CURSOR_MOVEMENT=e.CURSOR_AFTER=e.CURSOR_BEFORE=e.BLANK_DOC=e.TESTING_EXPANDO_PROPERTY=e.REMOVE_CARD_HOOK=e.ADD_CARD_HOOK=void 0 +Object.defineProperty(e,"__esModule",{value:!0}),e.arrayToMap=w,e.toggleSpecialFormatEditState=k,e.default=e.SPECIAL_MARKUPS=e.NO_CURSOR_MOVEMENT=e.CURSOR_AFTER=e.CURSOR_BEFORE=e.BLANK_DOC=e.MOBILEDOC_VERSION=e.TESTING_EXPANDO_PROPERTY=e.REMOVE_CARD_HOOK=e.ADD_CARD_HOOK=void 0 const{countWords:v}=b.utils e.ADD_CARD_HOOK="addComponent" e.REMOVE_CARD_HOOK="removeComponent" e.TESTING_EXPANDO_PROPERTY="__mobiledoc_kit_editor" +e.MOBILEDOC_VERSION="0.3.1" const M={version:"0.3.1",markups:[],atoms:[],cards:[],sections:[[1,"p",[[0,[],0,""]]]]} e.BLANK_DOC=M e.CURSOR_BEFORE=-1 @@ -11153,7 +11153,7 @@ t.insertSectionAtEnd(e),t.setRange(e.toRange()),o=t._range.head.section}if(o.isB e.next?t.insertSectionBefore(a,n,e.next):t.insertSectionAtEnd(n),t.setRange(n.toRange()),o=t._range.head.section}e.forEach(e=>{let r={files:[e]} n=i.createCardSection("image",r),t.insertSectionBefore(a,n,o)}),o.isBlank&&t.removeSection(o),t.setRange(n.tailPosition())}e.SPECIAL_MARKUPS=_ var E=Ember.Component.extend({koenigDragDropHandler:Ember.inject.service(),layout:u.default,tagName:"article",classNames:["koenig-editor","w-100","flex-grow","relative","center","mb0","mt0"],mobiledoc:null,placeholder:"Write here...",autofocus:!1,spellcheck:!0,options:null,headerOffset:0,dropTargetSelector:null,scrollContainerSelector:null,scrollOffsetTopSelector:null,scrollOffsetBottomSelector:null,editor:null,activeMarkupTagNames:null,activeSectionTagNames:null,selectedRange:null,componentCards:null,linkRange:null,selectedCard:null,_localMobiledoc:null,_upstreamMobiledoc:null,_startedRunLoop:!1,_lastIsEditingDisabled:!1,_isRenderingEditor:!1,_skipCursorChange:!1,_modifierKeys:null,willCreateEditor(){},didCreateEditor(){},onChange(){},cursorDidExitAtTop(){},wordCountDidChange(){},editorOptions:Ember.computed((function(){let e=this.options||{},t=this.atoms||[],n=this.cards||[] -return t=o.default.concat(t),n=s.default.concat(n),Ember.assign({placeholder:this.placeholder,spellcheck:this.spellcheck,autofocus:this.autofocus,atoms:t,cards:n},e)})),init(){this._super(...arguments) +return t=o.default.concat(t),n=s.default.concat(n),Ember.assign({placeholder:this.placeholder,spellcheck:this.spellcheck,autofocus:this.autofocus,atoms:t,cards:n},e)})),init(){this._super(...arguments),this.SPECIAL_MARKUPS=_ let e=this.mobiledoc e||(e=M,this.set("mobiledoc",e)),this.set("componentCards",Ember.A([])),this.set("activeMarkupTagNames",{}),this.set("activeSectionTagNames",{}),this._modifierKeys={shift:!1,alt:!1,ctrl:!1},this._onMousedownHandler=Ember.run.bind(this,this.handleMousedown),window.addEventListener("mousedown",this._onMousedownHandler),this._onMouseupHandler=Ember.run.bind(this,this.handleMouseup),window.addEventListener("mouseup",this._onMouseupHandler),this._startedRunLoop=!1},willRender(){let e=this.mobiledoc||M,t=this._localMobiledoc&&this._localMobiledoc===e||this._upstreamMobiledoc&&this._upstreamMobiledoc===e,i=this._lastIsEditingDisabled===this.isEditingDisabled if(t&&i)return @@ -11185,8 +11185,8 @@ t.next?(this.deselectCard(e),this.moveCaretToHeadOfSection(t.next,!1)):this.send this.deselectCard(e),t.run(e=>{let{builder:t}=e,n=t.createMarkupSection("p") r?e.insertSectionBefore(i,n,r):e.insertSectionAtEnd(n),e.setRange(n.tailPosition())})}},skipNewline(){this._skipNextNewline=!0},cleanup(){this._cleanupScheduled=!0},_cleanup(){this.componentCards.forEach(e=>{let t=e.koenigOptions.deleteIfEmpty if(t){if("string"==typeof t){let e=t -t=t=>Ember.isBlank(Ember.get(t,e))}t(e)&&this.deleteCard(e,0)}}),this._cleanupScheduled=!1},postDidChange(e){let t=this.serializeVersion,n=e.serialize(t) -this._localMobiledoc=n,this.onChange(n),this._calculateWordCount(),this._cardDragDropContainer.refresh()},cursorDidChange(e){let{head:t,tail:n,direction:i,isCollapsed:a,head:{section:o}}=e.range +t=t=>Ember.isBlank(Ember.get(t,e))}t(e)&&this.deleteCard(e,0)}}),this._cleanupScheduled=!1},postDidChange(e){let t=e.serialize("0.3.1") +this._localMobiledoc=t,this.onChange(t),this._calculateWordCount(),this._cardDragDropContainer.refresh()},cursorDidChange(e){let{head:t,tail:n,direction:i,isCollapsed:a,head:{section:o}}=e.range if(this._skipCursorChange)return this._skipCursorChange=!1,this.set("selectedRange",e.range),void this._scrollCursorIntoView() if(!this.selectedCard||this.selectedCard.postModel!==o)if(!o||!a||"card-section"!==o.type||0!==t.offset&&1!==t.offset){if(this.selectedCard&&!e.range.isBlank&&this.deselectCard(this.selectedCard),k(e),1===i&&!a&&0===n.offset&&n.section.prev){let i=n.section.prev,a=new r.default(t,i.tailPosition()) return e.selectRange(a)}this.set("selectedRange",e.range),this._scrollCursorIntoView()}else Ember.run.schedule("afterRender",this,()=>{let t=this.getCardFromSection(o) @@ -11352,32 +11352,34 @@ if(e)return e}},_moveSelection(e){let t=this.itemMap if(Ember.isEmpty(t))return let n=this._getSelectedItem(),i=t.find(e=>e.includes(n)),r=t.indexOf(i),a=i.indexOf(n),o=t.length-1,s=i.length-1 Ember.set(n,"selected",!1),"right"===e?(a+=1,a>s&&(r0?r-=1:r=t.length-1,a=t[r].length-1)):"up"===e?(r-=1,r<0&&(r=o)):"down"===e&&(r+=1,r>o&&(r=0)),a>t[r].length-1&&(a=t[r].length-1),Ember.set(t[r][a],"selected",!0)},_unregisterKeyboardNavHandlers(){this.editor.unregisterKeyCommands("slash-menu")}}) -e.default=i})),define("koenig-editor/components/koenig-text-replacement-html-input",["exports","mobiledoc-kit/editor/editor","koenig-editor/lib/clean-text-replacement-html","koenig-editor/options/atoms","koenig-editor/templates/components/koenig-text-replacement-html-input","koenig-editor/options/key-commands","validator","koenig-editor/lib/dnd/constants","koenig-editor/components/koenig-editor","mobiledoc-kit/utils/parse-utils","koenig-editor/utils/markup-utils","koenig-editor/options/text-expansions"],(function(e,t,n,i,r,a,o,s,l,u,c,d){"use strict" -Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.SPECIAL_MARKUPS=void 0 -const h={version:"0.3.1",markups:[],atoms:[],cards:[],sections:[[1,"p",[[0,[],0,""]]]]} -e.SPECIAL_MARKUPS={S:"~~",CODE:"{",SUP:"^",SUB:"~"} -var p=Ember.Component.extend({layout:r.default,autofocus:!1,html:null,placeholder:"",spellcheck:!0,activeMarkupTagNames:null,editor:null,linkRange:null,mobiledoc:null,selectedRange:null,_hasFocus:!1,_lastMobiledoc:null,_startedRunLoop:!1,willCreateEditor(){},didCreateEditor(){},onChange(){},onFocus(){},onBlur(){},cleanHTML:Ember.computed("html",(function(){return(0,n.default)(this.html)})),editorOptions:Ember.computed("cleanHTML",(function(){let e=this.options||{},t=this.atoms||[],n=this.cards||[] -return t=i.default.concat(t),Ember.assign({html:"

".concat(this.cleanHTML||"","

"),placeholder:this.placeholder,spellcheck:this.spellcheck,autofocus:this.autofocus,cards:n,atoms:t,unknownCardHandler(){},unknownAtomHandler(){}},e)})),didReceiveAttrs(){this._super(...arguments),this.cleanHTML!==this._getHTML()&&this.set("mobiledoc",null)},willRender(){let e=this.mobiledoc -e||this.cleanHTML||(e=h) +e.default=i})),define("koenig-editor/components/koenig-text-replacement-html-input",["exports","mobiledoc-kit/editor/editor","koenig-editor/lib/clean-text-replacement-html","koenig-editor/options/atoms","koenig-editor/templates/components/koenig-text-replacement-html-input","koenig-editor/options/key-commands","validator","koenig-editor/components/koenig-editor","koenig-editor/lib/dnd/constants","mobiledoc-kit/utils/parse-utils","koenig-editor/utils/markup-utils","koenig-editor/options/text-expansions"],(function(e,t,n,i,r,a,o,s,l,u,c,d){"use strict" +function h(e){return(e||"").replace(/\{(.*?)\}/g,"$&")}Object.defineProperty(e,"__esModule",{value:!0}),e.formatTextReplacementHtml=h,e.default=void 0 +const p={S:"~~",CODE:{char:"{",replace:!1},SUP:"^",SUB:"~"} +function f(e){let{head:t,isCollapsed:n}=e.range +n&&Object.keys(p).forEach(n=>{if(n=n.toLowerCase(),t.marker&&t.marker.hasMarkup(n)&&e._editState.activeMarkups.findBy("tagName",n)){let i=t.markerIn(1) +i&&i.hasMarkup(n)||e._editState.activeMarkups.filterBy("tagName",n).forEach(t=>{e._editState.toggleMarkupState(t)})}})}var m=Ember.Component.extend({layout:r.default,autofocus:!1,html:null,placeholder:"",spellcheck:!0,activeMarkupTagNames:null,editor:null,linkRange:null,mobiledoc:null,selectedRange:null,_hasFocus:!1,_lastMobiledoc:null,_startedRunLoop:!1,willCreateEditor(){},didCreateEditor(){},onChange(){},onFocus(){},onBlur(){},formattedHtml:Ember.computed("html",(function(){return h(this.html)})),editorOptions:Ember.computed("formattedHtml",(function(){let e=this.options||{},t=this.atoms||[],n=this.cards||[] +return t=i.default.concat(t),Ember.assign({html:this.formattedHtml||"",placeholder:this.placeholder,spellcheck:this.spellcheck,autofocus:this.autofocus,cards:n,atoms:t,unknownCardHandler(){},unknownAtomHandler(){}},e)})),init(){this._super(...arguments),this.SPECIAL_MARKUPS=p},didReceiveAttrs(){this._super(...arguments),this.html!==this.getCleanHTML()&&this.set("mobiledoc",null)},willRender(){let e=this.mobiledoc +e||this.formattedHtml||(e=s.BLANK_DOC) let n=this._lastMobiledoc&&this._lastMobiledoc===e,i=this._lastIsEditingDisabled===this.isEditingDisabled if(n&&i)return this._lastIsEditingDisabled=this.isEditingDisabled,this.willCreateEditor() let r=this.editor r&&r.destroy() let o=this.editorOptions -o.mobiledoc=e,o.showLinkTooltips=!1,o.undoDepth=50,o.parserPlugins=[],r=new t.default(o),(0,a.default)(r,this,a.TEXT_REPLACEMENT_KEY_COMMANDS),(0,d.registerTextReplacementTextExpansions)(r,this),r.willRender(()=>{Ember.run.currentRunLoop||(this._startedRunLoop=!0,Ember.run.begin())}),r.didRender(()=>{this._startedRunLoop&&(this._startedRunLoop=!1,Ember.run.end())}),r.didUpdatePost(e=>{Ember.run.join(()=>{this.didUpdatePost(e)})}),r.postDidChange(()=>{Ember.run.join(()=>{this.postDidChange(r)})}),r.cursorDidChange(()=>{Ember.run.join(()=>{this.cursorDidChange(r)})}),r.inputModeDidChange(()=>{this.isDestroyed||Ember.run.join(()=>{this.inputModeDidChange(r)})}),this.isEditingDisabled&&r.disableEditing(),this.mobiledoc=r.serialize(),this._lastMobiledoc=this.mobiledoc,this.set("editor",r),this.didCreateEditor(r)},didInsertElement(){this._super(...arguments) +o.mobiledoc=e,o.showLinkTooltips=!1,o.undoDepth=50,o.parserPlugins=[],r=new t.default(o),(0,a.default)(r,this,a.TEXT_REPLACEMENT_KEY_COMMANDS),(0,d.registerTextReplacementTextExpansions)(r,this),r.willRender(()=>{Ember.run.currentRunLoop||(this._startedRunLoop=!0,Ember.run.begin())}),r.didRender(()=>{this._startedRunLoop&&(this._startedRunLoop=!1,Ember.run.end())}),r.didUpdatePost(e=>{Ember.run.join(()=>{this.didUpdatePost(e)})}),r.postDidChange(()=>{Ember.run.join(()=>{this.postDidChange(r)})}),r.cursorDidChange(()=>{Ember.run.join(()=>{this.cursorDidChange(r)})}),r.inputModeDidChange(()=>{this.isDestroyed||Ember.run.join(()=>{this.inputModeDidChange(r)})}),this.isEditingDisabled&&r.disableEditing(),this.mobiledoc=r.serialize(s.MOBILEDOC_VERSION),this._lastMobiledoc=this.mobiledoc,this.set("editor",r),this.didCreateEditor(r)},didInsertElement(){this._super(...arguments) let e=this.element.querySelector('[data-kg="editor"]') -this._pasteHandler=Ember.run.bind(this,this.handlePaste),e.addEventListener("paste",this._pasteHandler),this.element.dataset[s.DRAG_DISABLED_DATA_ATTR]="true"},didRender(){this._super(...arguments) +this._pasteHandler=Ember.run.bind(this,this.handlePaste),e.addEventListener("paste",this._pasteHandler),this.element.dataset[l.DRAG_DISABLED_DATA_ATTR]="true"},didRender(){this._super(...arguments) let{editor:e}=this if(!e.hasRendered){let t=this.element.querySelector('[data-kg="editor"]') this._isRenderingEditor=!0,e.render(t),this._isRenderingEditor=!1}},willDestroyElement(){this._super(...arguments),this.element.querySelector('[data-kg="editor"]').removeEventListener("paste",this._pasteHandler),this.editor.destroy()},actions:{toggleMarkup(e,t){(t||this.editor).toggleMarkup(e)},editLink(e){let t=(0,c.getLinkMarkupFromRange)(e) e.isCollapsed&&!t||!e.headSection.isMarkerable||this.set("linkRange",e)},cancelEditLink(){this.set("linkRange",null)}},focusIn(e){this._hasFocus||(this._hasFocus=!0,Ember.run.scheduleOnce("actions",this,this.onFocus,e))},focusOut(e){e.relatedTarget&&this.element.contains(e.relatedTarget)||(this._hasFocus=!1,Ember.run.scheduleOnce("actions",this,this.onBlur,e))},handlePaste(e){let{editor:t,editor:{range:n}}=this,{text:i}=(0,u.getContentFromPasteEvent)(e) if(t.cursor.isAddressable(e.target)&&i&&o.default.isURL(i)&&n&&!n.isCollapsed&&n.headSection===n.tailSection&&n.headSection.isMarkerable){let r=t.builder.createMarkup("a",{href:i}) -return t.run(e=>{e.addMarkupToRange(n,r)}),t.selectRange(n.tail),e.preventDefault(),void e.stopImmediatePropagation()}},didUpdatePost(e){let{builder:t,editor:n,editor:{post:i}}=e -if(i.sections.forEach(t=>{if(!t.isMarkerable&&!t.isListSection){let r=t===n.activeSection -e.removeSection(t),r&&e.setRange(i.sections.head.tailPosition())}}),i.sections.head.isListSection){let n=i.sections.head,r=n.items.head.markers.map(e=>e.clone()),a=t.createMarkupSection("p",r) -e.replaceSection(n,a),e.setRange(i.sections.head.tailPosition())}},postDidChange(){this.onChange(this._getHTML())},cursorDidChange(e){(0,l.toggleSpecialFormatEditState)(e),this.set("selectedRange",e.range)},inputModeDidChange(e){let t=(0,l.arrayToMap)(e.activeMarkups.map(e=>e.tagName));(0,l.toggleSpecialFormatEditState)(e),this._isRenderingEditor?Ember.run.schedule("afterRender",()=>{this.set("activeMarkupTagNames",t)}):this.set("activeMarkupTagNames",t)},_getHTML(){if(this.editor&&this.editor.element)return(0,n.default)(this.editor.element.innerHTML)}}) -e.default=p})),define("koenig-editor/components/koenig-toolbar",["exports","koenig-editor/templates/components/koenig-toolbar","ember-concurrency"],(function(e,t,n){"use strict" +return t.run(e=>{e.addMarkupToRange(n,r)}),t.selectRange(n.tail),e.preventDefault(),void e.stopImmediatePropagation()}},didUpdatePost(e){let{editor:t,editor:{post:n}}=e,i=[] +try{i=n.markersContainedByRange(n.toRange())}catch(r){}i.forEach(e=>{let{markups:t}=e +t.length>1&&e.hasMarkup("code")&&t.rejectBy("tagName","code").forEach(t=>{e.removeMarkup(t)})}),n.sections.forEach(i=>{if(!i.isMarkerable&&!i.isListSection){let r=i===t.activeSection +e.removeSection(i),r&&e.setRange(n.sections.head.tailPosition())}})},postDidChange(){this.onChange(this.getCleanHTML())},cursorDidChange(e){f(e),this.set("selectedRange",e.range)},inputModeDidChange(e){let t=(0,s.arrayToMap)(e.activeMarkups.map(e=>e.tagName)) +f(e),this._isRenderingEditor?Ember.run.schedule("afterRender",()=>{this.set("activeMarkupTagNames",t)}):this.set("activeMarkupTagNames",t)},getCleanHTML(){if(this.editor&&this.editor.element)return(0,n.default)(this.editor.element.innerHTML)}}) +e.default=m})),define("koenig-editor/components/koenig-toolbar",["exports","koenig-editor/templates/components/koenig-toolbar","ember-concurrency"],(function(e,t,n){"use strict" Object.defineProperty(e,"__esModule",{value:!0}),e.default=e.TOOLBAR_MARGIN=void 0 e.TOOLBAR_MARGIN=15 var i=Ember.Component.extend({layout:t.default,attributeBindings:["style"],classNames:["absolute","z-999"],basicOnly:!1,editor:null,editorRange:null,activeMarkupTagNames:null,activeSectionTagNames:null,showToolbar:!1,top:null,left:-1e3,right:null,_isMouseDown:!1,_hasSelectedRange:!1,_onMousedownHandler:null,_onMousemoveHandler:null,_onMouseupHandler:null,_onResizeHandler:null,toggleMarkup(){},toggleSection(){},toggleHeaderSection(){},editLink(){},style:Ember.computed("showToolbar","top","left","right",(function(){let e=this.getProperties("top","left","right"),t=Object.keys(e).map(t=>{if(null!==e[t])return"".concat(t,": ").concat(e[t],"px")}) @@ -11426,7 +11428,7 @@ e.default=i})),define("koenig-editor/lib/clean-text-replacement-html",["exports" Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(e="",t={}){const n=Object.assign({},{},t) if(!n.createDocument){const e="undefined"!=typeof DOMParser&&DOMParser||"undefined"!=typeof window&&window.DOMParser if(!e)throw new Error("cleanTextReplacementHtml() must be passed a `createDocument` function as an option when used in a non-browser environment") -n.createDocument=function(t){return(new e).parseFromString(t,"text/html")}}let i=e.replace(/(\s| ){2,}/g," ").trim().replace(/^ | $/g,"").trim() +n.createDocument=function(t){return(new e).parseFromString(t,"text/html")}}let i=e.replace(/({.*?})<\/code>/gi,"$1").trim().replace(/^ | $/g,"").trim() if(i){let e=n.createDocument(i) e.body.querySelectorAll("*").forEach(t=>{if(!t.textContent.trim())if(t.textContent.length>0){let n=e.createTextNode(" ") t.replaceWith(n)}else t.remove()}),i=e.body.innerHTML.trim()}return i}})),define("koenig-editor/lib/dnd/constants",["exports"],(function(e){"use strict" @@ -11507,13 +11509,17 @@ if(s===c.head&&r&&0===o&&(s.isBlank||""===s.text))e.run(e=>{if(e.removeSection(s let{builder:t}=e,n=t.createMarkupSection("p") e.insertSectionAtEnd(n),e.setRange(n.tailPosition())}) else if(r&&0===o&&u&&"card-section"===u.type&&!s.isBlank){let e=t.getCardFromSection(u) -t.deleteCard(e)}else{if(!(r&&0===o&&s.tagName.match(/^h\d$/)&&u&&"p"===u.tagName&&u.isBlank)){if(r&&a&&0!==o){let t=Object.keys(n.SPECIAL_MARKUPS),r=!1 -if(t.forEach(t=>{let o=a.markups.find(e=>e.tagName.toUpperCase()===t) +t.deleteCard(e)}else{if(!(r&&0===o&&s.tagName.match(/^h\d$/)&&u&&"p"===u.tagName&&u.isBlank)){if(r&&a&&0!==o){let n=Object.keys(t.SPECIAL_MARKUPS),r=!1 +if(n.forEach(n=>{let o=a.markups.find(e=>e.tagName.toUpperCase()===n) if(o){let a=i.markerIn(1) -a&&a.hasMarkup(t)||(e.run(i=>{let r=n.SPECIAL_MARKUPS[t],a=e.range.expandByMarker(e=>!!e.markups.includes(o)) -i.insertText(a.head,r),a=a.extend(r.length) -let s=i.insertText(a.tail,r) -a=a.extend(r.length),i.toggleMarkup(t,a),s=i.deleteAtPosition(s,-1),i.setRange(s)}),r=!0)}}),r)return}return!1}e.run(e=>{e.removeSection(u)})}}},{str:"DEL",run(e,t){let{isCollapsed:i,head:{offset:r,section:a}}=e.range +a&&a.hasMarkup(n)||(e.run(i=>{let r=t.SPECIAL_MARKUPS[n],a=!0 +"object"==typeof r&&(a=r.replace,r=r.char) +let s=e.range.expandByMarker(e=>!!e.markups.includes(o)) +if(a){i.insertText(s.head,r),s=s.extend(r.length) +let e=i.insertText(s.tail,r) +s=s.extend(r.length),i.toggleMarkup(n,s),e=i.deleteAtPosition(e,-1),i.setRange(e)}else{i.toggleMarkup(n,s) +let e=i.deleteAtPosition(s.tail) +i.setRange(e)}}),r=!0)}}),r)return}return!1}e.run(e=>{e.removeSection(u)})}}},{str:"DEL",run(e,t){let{isCollapsed:i,head:{offset:r,section:a}}=e.range if(t.selectedCard){let e="card-section"===a.next.type,n=t.getCardFromSection(a.next) return t.deleteCard(t.selectedCard),void(e&&t.selectCard(n))}if(!i||r!==a.length||!a.next||"card-section"!==a.next.type||a.isBlank)return!1 {let e=t.getCardFromSection(a.next) @@ -11586,10 +11592,10 @@ a.textUntil(r)===t[0]&&"blockquote"!==a.tagName&&e.run(e=>{i=i.extend(-t[0].leng let r=e.deleteRange(i) e.setRange(r),n.send("toggleSection","blockquote",e)})}}),e.onTextInput({name:"md_hr",match:/^---$/,run(e){let{range:{head:t,head:{section:i}}}=e t.isTail()&&(i.isListItem||n.send("replaceWithCardSection","hr",i.toRange()))}}),e.onTextInput({name:"md_code",match:/^```([a-zA-Z0-9]*)(\s)$/,run(e,t){let{range:{head:i,head:{section:r}}}=e,a={} -i.isTail()&&(r.isListItem||(t[1]&&(a.language=t[1]),"\n"===t[2]&&n.skipNewline(),n.send("replaceWithCardSection","code",r.toRange(),a)))}}),d(e),h(e)},e.registerBasicTextExpansions=function(e){e.unregisterTextInputHandler("heading"),e.unregisterTextInputHandler("ul"),e.unregisterTextInputHandler("ol"),d(e),h(e)},e.registerTextReplacementTextExpansions=function(e,d){e.unregisterTextInputHandler("heading"),e.unregisterTextInputHandler("ul"),e.onTextInput({name:"md_ul",match:/^\* |^- /,run(e,n){t(e,n,"ul")}}),e.unregisterTextInputHandler("ol"),e.onTextInput({name:"md_ol",match:/^1\.? /,run(e,n){t(e,n,"ol")}}),e.onTextInput({name:"md_blockquote",match:/^> /,run(e,t){let{range:n}=e,{head:i,head:{section:r}}=n -r.textUntil(i)===t[0]&&"blockquote"!==r.tagName&&e.run(e=>{n=n.extend(-t[0].length) -let i=e.deleteRange(n) -e.setRange(i),d.send("toggleSection","blockquote",e)})}}),e.onTextInput({name:"inline_markdown",match:/[*_)~^]$/,run(e,t){let n=e.range.head.section.textUntil(e.range.head) +i.isTail()&&(r.isListItem||(t[1]&&(a.language=t[1]),"\n"===t[2]&&n.skipNewline(),n.send("replaceWithCardSection","code",r.toRange(),a)))}}),d(e),h(e)},e.registerBasicTextExpansions=function(e){e.unregisterTextInputHandler("heading"),e.unregisterTextInputHandler("ul"),e.unregisterTextInputHandler("ol"),d(e),h(e)},e.registerTextReplacementTextExpansions=function(e,n){e.unregisterTextInputHandler("heading"),e.unregisterTextInputHandler("ul"),e.onTextInput({name:"md_ul",match:/^\* |^- /,run(e,n){t(e,n,"ul")}}),e.unregisterTextInputHandler("ol"),e.onTextInput({name:"md_ol",match:/^1\.? /,run(e,n){t(e,n,"ol")}}),e.onTextInput({name:"md_blockquote",match:/^> /,run(e,t){let{range:i}=e,{head:r,head:{section:a}}=i +a.textUntil(r)===t[0]&&"blockquote"!==a.tagName&&e.run(e=>{i=i.extend(-t[0].length) +let r=e.deleteRange(i) +e.setRange(r),n.send("toggleSection","blockquote",e)})}}),e.onTextInput({name:"inline_markdown",match:/[*_)~^]$/,run(e,t){let n=e.range.head.section.textUntil(e.range.head) switch(t[0]){case"*":i(e,n),a(e,n) break case"_":r(e,n),o(e,n) @@ -11599,7 +11605,9 @@ break case"~":s(e,n),l(e,n) break case"^":u(e,n)}}}),e.onTextInput({name:"text_replacement",match:/\}$/,run(e){let t=e.range.head.section.textUntil(e.range.head).match(/(?:^|\s)\{([^\s{}]+|[^\s{}][^{}]*[^\s{}])\}$/) -t&&n(this,e,t,"code")}})}})),define("koenig-editor/services/koenig-drag-drop-handler",["exports","koenig-editor/lib/dnd/constants","koenig-editor/lib/dnd/utils","koenig-editor/lib/dnd/container","koenig-editor/lib/dnd/scroll-handler","ember-concurrency"],(function(e,t,n,i,r,a){"use strict" +t&&function(e,t,n,i){let{range:r}=t,a=n[0].trim() +r=r.extend(-a.length),t.run(e=>{let n=t.builder.createMarkup(i) +e.addMarkupToRange(r,n),e.setRange(r.tail.toRange())}),Ember.run.later(e,(function(){t.toggleMarkup(i)}),10)}(this,e,t,"code")}})}})),define("koenig-editor/services/koenig-drag-drop-handler",["exports","koenig-editor/lib/dnd/constants","koenig-editor/lib/dnd/utils","koenig-editor/lib/dnd/container","koenig-editor/lib/dnd/scroll-handler","ember-concurrency"],(function(e,t,n,i,r,a){"use strict" Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0 var o=Ember.Service.extend({koenigUi:Ember.inject.service(),containers:null,ghostInfo:null,grabbedElement:null,sourceContainer:null,isDragging:Ember.computed.alias("koenigUi.isDragging"),_eventHandlers:null,init(){this._super(...arguments),this.containers=Ember.A([]),this.scrollHandler=new r.default,this._eventHandlers={},this._transformedDroppables=Ember.A([]),this._rafUpdateGhostElementPosition=Ember.run.bind(this,this._updateGhostElementPosition),this._addGrabListeners(),this._appendGhostContainerElement()},willDestroy(){this._super(...arguments),this.cleanup(),this._removeGrabListeners(),this._removeDropIndicator(),this._removeGhostContainerElement()},registerContainer(e,t){let n=new i.default(e,t) return this.containers.pushObject(n),{enableDrag:()=>{n.enableDrag()},disableDrag:()=>{n.disableDrag()},refresh:()=>{n.refresh()},destroy:()=>{this.containers.removeObject(n)}}},cleanup(){this.containers=Ember.A([]),this._resetDrag()},_onMouseDown(e){if(!this.isDragging&&(void 0===e.button||0===e.button)&&(this.grabbedElement=n.getParent(e.target,t.DRAGGABLE_SELECTOR),this.grabbedElement)){let i=n.getParent(e.target,t.DRAG_DISABLED_SELECTOR) @@ -11670,7 +11678,7 @@ Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0 var t=Ember.HTMLBars.template({id:"hpf1dErB",block:'{"symbols":["card"],"statements":[[5,"koenig-card",[],[["@class","@style","@headerOffset","@toolbar","@payload","@isSelected","@isEditing","@selectCard","@deselectCard","@editCard","@saveCard","@onEnterEdit","@onLeaveEdit","@addParagraphAfterCard","@moveCursorToPrevSection","@moveCursorToNextSection","@editor"],[[28,"concat",["ba b--white relative kg-card-hover miw-100 relative",[28,"if",[[23,0,["isEditing"]]," bw2 pt1 pb1 pl2 nl6 pr6 nr6"],null]],null],[23,0,["cardStyle"]],[23,0,["headerOffset"]],[23,0,["toolbar"]],[23,0,["payload"]],[23,0,["isSelected"]],[23,0,["isEditing"]],[28,"action",[[23,0,[]],[23,0,["selectCard"]]],null],[28,"action",[[23,0,[]],[23,0,["deselectCard"]]],null],[28,"action",[[23,0,[]],[23,0,["editCard"]]],null],[28,"action",[[23,0,[]],[23,0,["saveCard"]]],null],[28,"action",[[23,0,[]],"enterEditMode"],null],[28,"action",[[23,0,[]],"leaveEditMode"],null],[23,0,["addParagraphAfterCard"]],[23,0,["moveCursorToPrevSection"]],[23,0,["moveCursorToNextSection"]],[23,0,["editor"]]]],{"statements":[[0,"\\n"],[4,"if",[[23,0,["isEditing"]]],null,{"statements":[[0," "],[5,"gh-cm-editor",[],[["@value","@class","@textareaClass","@autofocus","@lineWrapping","@update","@mode"],[[23,0,["payload","code"]],"koenig-card-code--editor koenig-card-html--editor","o-0",true,true,[28,"action",[[23,0,[]],"updateCode"],null],[23,0,["cmMode"]]]]],[0,"\\n "],[7,"input",true],[11,"value",[28,"readonly",[[23,0,["payload","language"]]],null]],[11,"onblur",[28,"action",[[23,0,[]],[28,"mut",[[23,0,["payload","language"]]],null]],[["value"],["target.value"]]]],[10,"placeholder","Language..."],[10,"class","absolute w-20 pa1 ba b--lightgrey br2 f8 tracked-2 fw4 z-999 outline-0 anim-normal"],[11,"style",[23,0,["languageInputStyle"]]],[10,"type","text"],[8],[9],[0,"\\n"]],"parameters":[]},{"statements":[[0," "],[7,"div",true],[10,"class","koenig-card-html-rendered"],[8],[0,"\\n "],[7,"pre",true],[8],[7,"code",true],[11,"class",[29,["line-numbers ",[28,"if",[[23,0,["payload","language"]],[28,"concat",["language-",[23,0,["payload","language"]]],null]],null]]]],[8],[1,[23,0,["escapedCode"]],false],[9],[9],[0,"\\n "],[9],[0,"\\n"],[4,"if",[[23,0,["payload","language"]]],null,{"statements":[[0," "],[7,"div",true],[10,"class","absolute top-2 right-2 flex justify-center items-center pa2"],[8],[0,"\\n "],[7,"span",true],[10,"class","db nudge-top--2 fw5 f8 midlightgrey"],[8],[1,[23,0,["payload","language"]],false],[9],[0,"\\n "],[9],[0,"\\n"]],"parameters":[]},null],[0," "],[7,"div",true],[10,"class","koenig-card-click-overlay"],[8],[9],[0,"\\n"]],"parameters":[]}],[0,"\\n"],[4,"if",[[28,"and",[[28,"not",[[23,0,["isEditing"]]],null],[28,"or",[[23,0,["isSelected"]],[28,"clean-basic-html",[[23,0,["payload","caption"]]],null]],null]],null]],null,{"statements":[[0," "],[6,[23,1,["CaptionInput"]],[],[["@class","@caption","@update","@placeholder"],["z-999",[23,0,["payload","caption"]],[28,"action",[[23,0,[]],"updateCaption"],null],"Type caption for code block (optional)"]]],[0,"\\n"]],"parameters":[]},null]],"parameters":[1]}]],"hasEval":false}',meta:{moduleName:"koenig-editor/templates/components/koenig-card-code.hbs"}}) e.default=t})),define("koenig-editor/templates/components/koenig-card-email",["exports"],(function(e){"use strict" Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0 -var t=Ember.HTMLBars.template({id:"UFiAfus0",block:'{"symbols":["card"],"statements":[[0," "],[5,"koenig-card",[],[["@icon","@class","@style","@headerOffset","@toolbar","@payload","@isSelected","@isEditing","@selectCard","@deselectCard","@editCard","@saveCard","@onLeaveEdit","@addParagraphAfterCard","@moveCursorToPrevSection","@moveCursorToNextSection","@editor"],["koenig/card-indicator-email",[28,"concat",[[28,"kg-style",["container-card"],null]," kg-email-card mih10 miw-100 relative"],null],[23,0,["cardStyle"]],[23,0,["headerOffset"]],[23,0,["toolbar"]],[23,0,["payload"]],[23,0,["isSelected"]],[23,0,["isEditing"]],[28,"action",[[23,0,[]],[23,0,["selectCard"]]],null],[28,"action",[[23,0,[]],[23,0,["deselectCard"]]],null],[28,"action",[[23,0,[]],[23,0,["editCard"]]],null],[28,"action",[[23,0,[]],[23,0,["saveCard"]]],null],[28,"action",[[23,0,[]],"leaveEditMode"],null],[23,0,["addParagraphAfterCard"]],[23,0,["moveCursorToPrevSection"]],[23,0,["moveCursorToNextSection"]],[23,0,["editor"]]]],{"statements":[[0,"\\n"],[4,"if",[[23,0,["isEditing"]]],null,{"statements":[[0," "],[5,"koenig-text-replacement-html-input",[],[["@html","@placeholder","@autofocus","@class","@onChange","@onFocus","@onBlur","@didCreateEditor"],[[23,0,["payload","html"]],"Email only content...",true,"miw-100 bn bg-transparent",[28,"action",[[23,0,[]],"updateHtml"],null],[28,"action",[[23,0,[]],[28,"mut",[[23,0,["isFocused"]]],null],true],null],[28,"action",[[23,0,[]],[28,"mut",[[23,0,["isFocused"]]],null],false],null],[28,"action",[[23,0,[]],"registerEditor"],null]]]],[0,"\\n"]],"parameters":[]},{"statements":[[0," "],[7,"p",true],[8],[1,[23,0,["payload","html"]],true],[9],[0,"\\n "],[7,"div",true],[10,"class","koenig-card-click-overlay"],[8],[9],[0,"\\n"]],"parameters":[]}]],"parameters":[1]}],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"koenig-editor/templates/components/koenig-card-email.hbs"}}) +var t=Ember.HTMLBars.template({id:"6dISTFRL",block:'{"symbols":["card"],"statements":[[0," "],[5,"koenig-card",[],[["@icon","@class","@style","@headerOffset","@toolbar","@payload","@isSelected","@isEditing","@selectCard","@deselectCard","@editCard","@saveCard","@onLeaveEdit","@addParagraphAfterCard","@moveCursorToPrevSection","@moveCursorToNextSection","@editor"],["koenig/card-indicator-email",[28,"concat",[[28,"kg-style",["container-card"],null]," kg-email-card mih10 miw-100 relative"],null],[23,0,["cardStyle"]],[23,0,["headerOffset"]],[23,0,["toolbar"]],[23,0,["payload"]],[23,0,["isSelected"]],[23,0,["isEditing"]],[28,"action",[[23,0,[]],[23,0,["selectCard"]]],null],[28,"action",[[23,0,[]],[23,0,["deselectCard"]]],null],[28,"action",[[23,0,[]],[23,0,["editCard"]]],null],[28,"action",[[23,0,[]],[23,0,["saveCard"]]],null],[28,"action",[[23,0,[]],"leaveEditMode"],null],[23,0,["addParagraphAfterCard"]],[23,0,["moveCursorToPrevSection"]],[23,0,["moveCursorToNextSection"]],[23,0,["editor"]]]],{"statements":[[0,"\\n"],[4,"if",[[23,0,["isEditing"]]],null,{"statements":[[0," "],[5,"koenig-text-replacement-html-input",[],[["@html","@placeholder","@autofocus","@class","@onChange","@onFocus","@onBlur","@didCreateEditor"],[[23,0,["payload","html"]],"Email only content...",true,"miw-100 bn bg-transparent",[28,"action",[[23,0,[]],"updateHtml"],null],[28,"action",[[23,0,[]],[28,"mut",[[23,0,["isFocused"]]],null],true],null],[28,"action",[[23,0,[]],[28,"mut",[[23,0,["isFocused"]]],null],false],null],[28,"action",[[23,0,[]],"registerEditor"],null]]]],[0,"\\n"]],"parameters":[]},{"statements":[[0," "],[7,"p",true],[8],[1,[23,0,["formattedHtml"]],true],[9],[0,"\\n "],[7,"div",true],[10,"class","koenig-card-click-overlay"],[8],[9],[0,"\\n"]],"parameters":[]}]],"parameters":[1]}],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"koenig-editor/templates/components/koenig-card-email.hbs"}}) e.default=t})),define("koenig-editor/templates/components/koenig-card-embed",["exports"],(function(e){"use strict" Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0 var t=Ember.HTMLBars.template({id:"mSDD+bPI",block:'{"symbols":["card"],"statements":[[5,"koenig-card",[],[["@class","@isSelected","@isEditing","@selectCard","@deselectCard","@onDeselect","@editCard","@toolbar","@hasEditMode","@showSelectedOutline","@addParagraphAfterCard","@moveCursorToPrevSection","@moveCursorToNextSection","@editor"],["flex flex-column",[23,0,["isSelected"]],[23,0,["isEditing"]],[28,"action",[[23,0,[]],[23,0,["selectCard"]]],null],[28,"action",[[23,0,[]],[23,0,["deselectCard"]]],null],[28,"action",[[23,0,[]],"onDeselect"],null],[28,"action",[[23,0,[]],[23,0,["editCard"]]],null],[23,0,["toolbar"]],false,[23,0,["payload","html"]],[23,0,["addParagraphAfterCard"]],[23,0,["moveCursorToPrevSection"]],[23,0,["moveCursorToNextSection"]],[23,0,["editor"]]]],{"statements":[[0,"\\n"],[4,"if",[[23,0,["payload","html"]]],null,{"statements":[[0," "],[7,"div",true],[10,"class","kg-card-hover"],[8],[0,"\\n "],[7,"div",true],[11,"class",[29,["koenig-embed-",[23,0,["payload","type"]]," flex justify-center relative"]]],[10,"data-kg-embed",""],[8],[0,"\\n "],[7,"iframe",true],[10,"class","bn miw-100"],[10,"scrolling","no"],[8],[9],[0,"\\n "],[7,"div",true],[10,"class","koenig-card-click-overlay ba b--transparent"],[10,"data-kg-overlay",""],[8],[9],[0,"\\n "],[9],[0,"\\n\\n"],[4,"if",[[28,"or",[[23,0,["isSelected"]],[28,"clean-basic-html",[[23,0,["payload","caption"]]],null]],null]],null,{"statements":[[0," "],[6,[23,1,["CaptionInput"]],[],[["@caption","@update","@placeholder"],[[23,0,["payload","caption"]],[28,"action",[[23,0,[]],"updateCaption"],null],"Type caption for embed (optional)"]]],[0,"\\n"]],"parameters":[]},null],[0," "],[9],[0,"\\n"]],"parameters":[]},{"statements":[[4,"if",[[23,0,["convertUrl","isRunning"]]],null,{"statements":[[0," "],[7,"div",true],[10,"class","miw-100 pa2 ba br2 b--lightgrey-d1 flex items-center justify-center bg-whitegrey-l2 f6 lh-title h10"],[8],[0,"\\n  "],[7,"div",true],[10,"class","ghost-spinner spinner-blue"],[8],[9],[0," \\n "],[9],[0,"\\n"]],"parameters":[]},{"statements":[[4,"if",[[23,0,["hasError"]]],null,{"statements":[[0," "],[7,"div",true],[10,"class","miw-100 flex flex-row pa2 pl3 ba br2 b--red-l3 red bg-error-red f7 fw4 lh-title h10 items-center"],[8],[0,"\\n "],[7,"span",true],[10,"class","mr3"],[8],[0,"There was an error when parsing the URL."],[9],[0,"\\n "],[7,"button",false],[12,"class","red-d2 mr3 fw6 hover-red"],[12,"type","button"],[3,"action",[[23,0,[]],"retry"]],[8],[7,"span",true],[10,"class","underline"],[8],[0,"Retry"],[9],[9],[0,"\\n "],[7,"button",false],[12,"class","red-d2 mr-auto fw6 underline hover-red"],[12,"type","button"],[3,"action",[[23,0,[]],"insertAsLink"]],[8],[7,"span",true],[10,"class","underline"],[8],[0,"Paste URL as link"],[9],[9],[0,"\\n "],[7,"button",false],[12,"class","nudge-right--2"],[12,"type","button"],[3,"action",[[23,0,[]],[23,0,["deleteCard"]]]],[8],[0,"\\n "],[1,[28,"svg-jar",["close"],[["class"],["w3 stroke-red-l3"]]],false],[0,"\\n "],[9],[0,"\\n "],[9],[0,"\\n"]],"parameters":[]},{"statements":[[0," "],[7,"input",true],[11,"value",[23,0,["payload","url"]]],[10,"name","url"],[10,"placeholder","Paste URL to add embedded content..."],[10,"class","miw-100 pa2 ba br2 b--lightgrey-d2 f7 form-text lh-title tracked-2 h10 nl2 nr2"],[11,"oninput",[28,"action",[[23,0,[]],"updateUrl"],null]],[11,"onkeydown",[28,"action",[[23,0,[]],"urlKeydown"],null]],[10,"type","text"],[8],[9],[0,"\\n "]],"parameters":[]}]],"parameters":[]}]],"parameters":[]}]],"parameters":[1]}],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"koenig-editor/templates/components/koenig-card-embed.hbs"}}) diff --git a/core/frontend/meta/schema.js b/core/frontend/meta/schema.js index 61c6e58e7b..6c9cbfc555 100644 --- a/core/frontend/meta/schema.js +++ b/core/frontend/meta/schema.js @@ -29,10 +29,7 @@ function schemaPublisherObject(metaDataVal) { '@type': 'Organization', name: escapeExpression(metaDataVal.site.title), url: metaDataVal.site.url || null, - logo: { - '@type': 'ImageObject', - url: schemaImageObject(metaDataVal.site.logo) || null - } + logo: schemaImageObject(metaDataVal.site.logo) || null }; return publisherObject; diff --git a/core/frontend/services/routing/config/canary.js b/core/frontend/services/routing/config/canary.js index 8be78b3309..98c7457991 100644 --- a/core/frontend/services/routing/config/canary.js +++ b/core/frontend/services/routing/config/canary.js @@ -42,7 +42,7 @@ module.exports.QUERY = { module.exports.TAXONOMIES = { tag: { filter: 'tags:\'%s\'+tags.visibility:public', - editRedirect: '#/settings/tags/:slug/', + editRedirect: '#/tags/:slug/', resource: 'tags' }, author: { diff --git a/core/frontend/services/routing/config/v2.js b/core/frontend/services/routing/config/v2.js index 8be78b3309..98c7457991 100644 --- a/core/frontend/services/routing/config/v2.js +++ b/core/frontend/services/routing/config/v2.js @@ -42,7 +42,7 @@ module.exports.QUERY = { module.exports.TAXONOMIES = { tag: { filter: 'tags:\'%s\'+tags.visibility:public', - editRedirect: '#/settings/tags/:slug/', + editRedirect: '#/tags/:slug/', resource: 'tags' }, author: { diff --git a/core/frontend/services/routing/config/v3.js b/core/frontend/services/routing/config/v3.js index 8be78b3309..98c7457991 100644 --- a/core/frontend/services/routing/config/v3.js +++ b/core/frontend/services/routing/config/v3.js @@ -42,7 +42,7 @@ module.exports.QUERY = { module.exports.TAXONOMIES = { tag: { filter: 'tags:\'%s\'+tags.visibility:public', - editRedirect: '#/settings/tags/:slug/', + editRedirect: '#/tags/:slug/', resource: 'tags' }, author: { diff --git a/core/server/api/canary/email-preview.js b/core/server/api/canary/email-preview.js index 7a23c5ee80..b1a57e6f69 100644 --- a/core/server/api/canary/email-preview.js +++ b/core/server/api/canary/email-preview.js @@ -30,7 +30,17 @@ module.exports = { }); } - return mega.postEmailSerializer.serialize(model, {isBrowserPreview: true}); + return mega.postEmailSerializer.serialize(model, {isBrowserPreview: true}).then(({emailTmpl, replacements}) => { + // perform replacements using no member data + replacements.forEach((replacement) => { + emailTmpl[replacement.format] = emailTmpl[replacement.format].replace( + replacement.match, + replacement.fallback || '' + ); + }); + + return emailTmpl; + }); }); } }, diff --git a/core/server/api/canary/utils/validators/input/schemas/pages.json b/core/server/api/canary/utils/validators/input/schemas/pages.json index 7c0ea6323d..46b59a882e 100644 --- a/core/server/api/canary/utils/validators/input/schemas/pages.json +++ b/core/server/api/canary/utils/validators/input/schemas/pages.json @@ -19,6 +19,7 @@ }, "mobiledoc": { "type": ["string", "null"], + "format": "json-string", "maxLength": 1000000000 }, "html": { diff --git a/core/server/api/canary/utils/validators/input/schemas/posts.json b/core/server/api/canary/utils/validators/input/schemas/posts.json index 58145ccfda..a34db4884c 100644 --- a/core/server/api/canary/utils/validators/input/schemas/posts.json +++ b/core/server/api/canary/utils/validators/input/schemas/posts.json @@ -19,6 +19,7 @@ }, "mobiledoc": { "type": ["string", "null"], + "format": "json-string", "maxLength": 1000000000 }, "html": { diff --git a/core/server/api/canary/utils/validators/utils/json-schema.js b/core/server/api/canary/utils/validators/utils/json-schema.js index b355239ddc..a9949298e4 100644 --- a/core/server/api/canary/utils/validators/utils/json-schema.js +++ b/core/server/api/canary/utils/validators/utils/json-schema.js @@ -5,7 +5,17 @@ const common = require('../../../../../lib/common'); const ajv = new Ajv({ allErrors: true, - useDefaults: true + useDefaults: true, + formats: { + 'json-string': (data) => { + try { + JSON.parse(data); + return true; + } catch (e) { + return false; + } + } + } }); stripKeyword(ajv); diff --git a/core/server/api/v2/utils/validators/input/schemas/pages.json b/core/server/api/v2/utils/validators/input/schemas/pages.json index 7c0ea6323d..46b59a882e 100644 --- a/core/server/api/v2/utils/validators/input/schemas/pages.json +++ b/core/server/api/v2/utils/validators/input/schemas/pages.json @@ -19,6 +19,7 @@ }, "mobiledoc": { "type": ["string", "null"], + "format": "json-string", "maxLength": 1000000000 }, "html": { diff --git a/core/server/api/v2/utils/validators/input/schemas/posts.json b/core/server/api/v2/utils/validators/input/schemas/posts.json index 30047da93c..6c27253957 100644 --- a/core/server/api/v2/utils/validators/input/schemas/posts.json +++ b/core/server/api/v2/utils/validators/input/schemas/posts.json @@ -19,6 +19,7 @@ }, "mobiledoc": { "type": ["string", "null"], + "format": "json-string", "maxLength": 1000000000 }, "html": { diff --git a/core/server/api/v2/utils/validators/utils/json-schema.js b/core/server/api/v2/utils/validators/utils/json-schema.js index b355239ddc..a9949298e4 100644 --- a/core/server/api/v2/utils/validators/utils/json-schema.js +++ b/core/server/api/v2/utils/validators/utils/json-schema.js @@ -5,7 +5,17 @@ const common = require('../../../../../lib/common'); const ajv = new Ajv({ allErrors: true, - useDefaults: true + useDefaults: true, + formats: { + 'json-string': (data) => { + try { + JSON.parse(data); + return true; + } catch (e) { + return false; + } + } + } }); stripKeyword(ajv); diff --git a/core/server/services/mega/mega.js b/core/server/services/mega/mega.js index 3edccca492..91557e7dfa 100644 --- a/core/server/services/mega/mega.js +++ b/core/server/services/mega/mega.js @@ -8,19 +8,41 @@ const models = require('../../models'); const postEmailSerializer = require('./post-email-serializer'); const config = require('../../config'); -const getEmailData = async (postModel, recipients = []) => { - const emailTmpl = await postEmailSerializer.serialize(postModel); +const getEmailData = async (postModel, members = []) => { + const {emailTmpl, replacements} = await postEmailSerializer.serialize(postModel); + emailTmpl.from = membersService.config.getEmailFromAddress(); - const emails = recipients.map(recipient => recipient.email); - const emailData = recipients.reduce((emailData, recipient) => { - return Object.assign({ - [recipient.email]: { - unique_id: recipient.uuid, - unsubscribe_url: postEmailSerializer.createUnsubscribeUrl(recipient.uuid) - } - }, emailData); - }, {}); + // update templates to use Mailgun variable syntax for replacements + replacements.forEach((replacement) => { + emailTmpl[replacement.format] = emailTmpl[replacement.format].replace( + replacement.match, + `%recipient.${replacement.id}%` + ); + }); + + const emails = []; + const emailData = {}; + members.forEach((member) => { + emails.push(member.email); + + // first_name is a computed property only used here for now + // TODO: move into model computed property or output serializer? + member.first_name = (member.name || '').split(' ')[0]; + + // add static data to mailgun template variables + const data = { + unique_id: member.uuid, + unsubscribe_url: postEmailSerializer.createUnsubscribeUrl(member.uuid) + }; + + // add replacement data/requested fallback to mailgun template variables + replacements.forEach(({id, memberProp, fallback}) => { + data[id] = member[memberProp] || fallback || ''; + }); + + emailData[member.email] = data; + }); return {emailTmpl, emails, emailData}; }; @@ -36,9 +58,10 @@ const sendEmail = async (postModel, members) => { }; const sendTestEmail = async (postModel, toEmails) => { - const recipients = toEmails.map((email) => { - return {email}; - }); + const recipients = await Promise.all(toEmails.map(async (email) => { + const member = await membersService.api.members.get({email}); + return member || {email}; + })); const {emailTmpl, emails, emailData} = await getEmailData(postModel, recipients); emailTmpl.subject = `[Test] ${emailTmpl.subject}`; return bulkEmailService.send(emailTmpl, emails, emailData); @@ -60,10 +83,9 @@ const addEmail = async (postModel, options) => { const membersToSendTo = members.filter((member) => { return membersService.contentGating.checkPostAccess(postModel.toJSON(), member); }); - const {emailTmpl, emails} = await getEmailData(postModel, membersToSendTo); // NOTE: don't create email object when there's nobody to send the email to - if (!emails.length) { + if (!membersToSendTo.length) { return null; } @@ -71,10 +93,20 @@ const addEmail = async (postModel, options) => { const existing = await models.Email.findOne({post_id: postId}, knexOptions); if (!existing) { + // get email contents and perform replacements using no member data so + // we have a decent snapshot of email content for later display + const {emailTmpl, replacements} = await postEmailSerializer.serialize(postModel, {isBrowserPreview: true}); + replacements.forEach((replacement) => { + emailTmpl[replacement.format] = emailTmpl[replacement.format].replace( + replacement.match, + replacement.fallback || '' + ); + }); + return models.Email.add({ post_id: postId, status: 'pending', - email_count: emails.length, + email_count: membersToSendTo.length, subject: emailTmpl.subject, html: emailTmpl.html, plaintext: emailTmpl.plaintext, @@ -233,7 +265,9 @@ async function pendingEmailHandler(emailModel, options) { } const statusChangedHandler = (emailModel, options) => { - const emailRetried = emailModel.wasChanged() && (emailModel.get('status') === 'pending') && (emailModel.previous('status') === 'failed'); + const emailRetried = emailModel.wasChanged() + && emailModel.get('status') === 'pending' + && emailModel.previous('status') === 'failed'; if (emailRetried) { pendingEmailHandler(emailModel, options); diff --git a/core/server/services/mega/post-email-serializer.js b/core/server/services/mega/post-email-serializer.js index 50c0a965e1..ec48902452 100644 --- a/core/server/services/mega/post-email-serializer.js +++ b/core/server/services/mega/post-email-serializer.js @@ -6,6 +6,8 @@ const moment = require('moment'); const cheerio = require('cheerio'); const api = require('../../api'); const {URL} = require('url'); +const mobiledocLib = require('../../lib/mobiledoc'); +const htmlToText = require('html-to-text'); const getSite = () => { const publicSettings = settingsCache.getPublic(); @@ -39,7 +41,8 @@ const createUnsubscribeUrl = (uuid) => { // NOTE: serialization is needed to make sure we are using current API and do post transformations // such as image URL transformation from relative to absolute const serializePostModel = async (model) => { - const frame = {options: {context: {user: true}, formats: 'html, plaintext'}}; + // fetch mobiledoc rather than html and plaintext so we can render email-specific contents + const frame = {options: {context: {user: true}, formats: 'mobiledoc'}}; const apiVersion = model.get('api_version') || 'v3'; const docName = 'posts'; @@ -51,29 +54,90 @@ const serializePostModel = async (model) => { return frame.response[docName][0]; }; +// parses templates and extracts an array of replacements with desired fallbacks +// removes %% wrappers from unknown replacement strings (modifies emailTmpl in place) +const _parseReplacements = (emailTmpl) => { + const EMAIL_REPLACEMENT_REGEX = /%%(\{.*?\})%%/g; + // the " is necessary here because `juice` will convert "->" for email compatibility + const REPLACEMENT_STRING_REGEX = /\{(?\w*?)(?:,? *(?:"|")(?.*?)(?:"|"))?\}/; + const ALLOWED_REPLACEMENTS = ['first_name']; + + const replacements = []; + ['html', 'plaintext'].forEach((format) => { + emailTmpl[format] = emailTmpl[format].replace(EMAIL_REPLACEMENT_REGEX, (replacementMatch, replacementStr) => { + const match = replacementStr.match(REPLACEMENT_STRING_REGEX); + + if (match) { + const {memberProp, fallback} = match.groups; + + if (ALLOWED_REPLACEMENTS.includes(memberProp)) { + const id = `replacement_${replacements.length + 1}`; + + replacements.push({ + format, + id, + match: replacementMatch, + memberProp, + fallback + }); + + // keeps wrapping %% for later replacement with real data + return replacementMatch; + } + } + + // removes %% so output matches user supplied content + return replacementStr; + }); + }); + + return replacements; +}; + const serialize = async (postModel, options = {isBrowserPreview: false}) => { const post = await serializePostModel(postModel); + post.published_at = post.published_at ? moment(post.published_at).format('DD MMM YYYY') : moment().format('DD MMM YYYY'); post.authors = post.authors && post.authors.map(author => author.name).join(','); - post.html = post.html || ''; if (post.posts_meta) { post.email_subject = post.posts_meta.email_subject; } + post.html = mobiledocLib.mobiledocHtmlRenderer.render(JSON.parse(post.mobiledoc), {target: 'email'}); + // same options as used in Post model for generating plaintext but without `wordwrap: 80` + // to avoid replacement strings being split across lines and for mail clients to handle + // word wrapping based on user preferences + post.plaintext = htmlToText.fromString(post.html, { + wordwrap: false, + ignoreImage: true, + hideLinkHrefIfSameAsText: true, + preserveNewlines: true, + returnDomByDefault: true, + uppercaseHeadings: false + }); + let htmlTemplate = template({post, site: getSite()}); if (options.isBrowserPreview) { const previewUnsubscribeUrl = createUnsubscribeUrl(); htmlTemplate = htmlTemplate.replace('%recipient.unsubscribe_url%', previewUnsubscribeUrl); } + let juicedHtml = juice(htmlTemplate); + // Force all links to open in new tab let _cheerio = cheerio.load(juicedHtml); _cheerio('a').attr('target','_blank'); juicedHtml = _cheerio.html(); - return { + + const emailTmpl = { subject: post.email_subject || post.title, html: juicedHtml, plaintext: post.plaintext }; + + // Extract known replacements and clean up unknown replacement strings + const replacements = _parseReplacements(emailTmpl); + + return {emailTmpl, replacements}; }; module.exports = { diff --git a/core/server/web/admin/views/default-prod.html b/core/server/web/admin/views/default-prod.html index b2ea25923c..3f4fec011e 100644 --- a/core/server/web/admin/views/default-prod.html +++ b/core/server/web/admin/views/default-prod.html @@ -52,7 +52,7 @@
- + diff --git a/core/server/web/admin/views/default.html b/core/server/web/admin/views/default.html index b2ea25923c..3f4fec011e 100644 --- a/core/server/web/admin/views/default.html +++ b/core/server/web/admin/views/default.html @@ -52,7 +52,7 @@
- + diff --git a/core/server/web/shared/middlewares/api/spam-prevention.js b/core/server/web/shared/middlewares/api/spam-prevention.js index 75734a1b27..8061bf3bf9 100644 --- a/core/server/web/shared/middlewares/api/spam-prevention.js +++ b/core/server/web/shared/middlewares/api/spam-prevention.js @@ -6,7 +6,7 @@ const config = require('../../../../config'); const {logging,i18n} = require('../../../../lib/common'); const spam = config.get('spam') || {}; -const spamPrivateBlog = spam.private_blog || {}; +const spamPrivateBlock = spam.private_block || {}; const spamGlobalBlock = spam.global_block || {}; const spamGlobalReset = spam.global_reset || {}; const spamUserReset = spam.user_reset || {}; @@ -190,8 +190,8 @@ const privateBlog = () => { logging.error(new errors.TooManyRequestsError({ message: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.error', { - rateSigninAttempts: spamPrivateBlog.freeRetries + 1 || 5, - rateSigninPeriod: spamPrivateBlog.lifetime || 60 * 60 + rateSigninAttempts: spamPrivateBlock.freeRetries + 1 || 5, + rateSigninPeriod: spamPrivateBlock.lifetime || 60 * 60 }), context: i18n.t('errors.middleware.spamprevention.tooManySigninAttempts.context') })); @@ -201,7 +201,7 @@ const privateBlog = () => { })); }, handleStoreError: handleStoreError - }, pick(spamPrivateBlog, spamConfigKeys)) + }, pick(spamPrivateBlock, spamConfigKeys)) ); return privateBlogInstance; diff --git a/package.json b/package.json index 3ac772f82d..4f52502c39 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghost", - "version": "3.13.3", + "version": "3.13.4", "description": "The professional publishing platform", "author": "Ghost Foundation", "homepage": "https://ghost.org", @@ -41,25 +41,25 @@ "dependencies": { "@nexes/nql": "0.3.0", "@sentry/node": "5.15.4", - "@tryghost/adapter-manager": "0.1.2", - "@tryghost/errors": "0.1.1", + "@tryghost/adapter-manager": "0.1.3", + "@tryghost/errors": "0.1.2", "@tryghost/helpers": "1.1.27", - "@tryghost/image-transform": "0.2.0", + "@tryghost/image-transform": "0.2.1", "@tryghost/kg-card-factory": "1.0.2", "@tryghost/kg-default-atoms": "1.0.0", - "@tryghost/kg-default-cards": "1.1.0", + "@tryghost/kg-default-cards": "1.1.1", "@tryghost/kg-markdown-html-renderer": "1.0.3", - "@tryghost/kg-mobiledoc-html-renderer": "2.0.0", - "@tryghost/members-api": "0.18.0", - "@tryghost/members-ssr": "0.7.4", - "@tryghost/mw-session-from-token": "0.1.0", - "@tryghost/session-service": "0.1.0", + "@tryghost/kg-mobiledoc-html-renderer": "2.0.1", + "@tryghost/members-api": "0.18.1", + "@tryghost/members-ssr": "0.7.5", + "@tryghost/mw-session-from-token": "0.1.1", + "@tryghost/session-service": "0.1.1", "@tryghost/social-urls": "0.1.9", "@tryghost/string": "0.1.9", "@tryghost/url-utils": "0.6.18", - "@tryghost/vhost-middleware": "1.0.2", - "@tryghost/zip": "1.0.0", - "ajv": "6.12.0", + "@tryghost/vhost-middleware": "1.0.3", + "@tryghost/zip": "1.0.1", + "ajv": "6.12.2", "amperize": "0.6.1", "analytics-node": "3.4.0-beta.1", "bcryptjs": "2.4.3", @@ -81,7 +81,7 @@ "express-hbs": "2.3.3", "express-jwt": "5.3.3", "express-query-boolean": "2.0.0", - "express-session": "1.17.0", + "express-session": "1.17.1", "fs-extra": "9.0.0", "ghost-ignition": "4.1.0", "ghost-storage-base": "0.0.4", @@ -97,7 +97,7 @@ "jsonwebtoken": "8.5.1", "juice": "6.0.0", "keypair": "1.0.1", - "knex": "0.20.14", + "knex": "0.20.15", "knex-migrator": "3.4.4", "lodash": "4.17.15", "mailgun-js": "0.22.0", @@ -134,10 +134,10 @@ "sqlite3": "4.1.1" }, "devDependencies": { - "@lodder/grunt-postcss": "2.0.1", + "@lodder/grunt-postcss": "2.0.2", "cssnano": "4.1.10", "eslint": "6.8.0", - "eslint-plugin-ghost": "1.1.0", + "eslint-plugin-ghost": "1.2.0", "grunt": "1.1.0", "grunt-bg-shell": "2.3.3", "grunt-contrib-clean": "2.0.0", diff --git a/yarn.lock b/yarn.lock index 57ba287f57..5f1a16af3f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -69,15 +69,15 @@ dependencies: "@hapi/hoek" "8.x.x" -"@lodder/grunt-postcss@2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@lodder/grunt-postcss/-/grunt-postcss-2.0.1.tgz#d294ce121d3cfcd99150a8276067ee8599fd798d" - integrity sha512-7ylMEhMadrLDrSbXfEDL3is2YUJ33uwKrPIkwI39Hf6G+ggyvRzLgmjNyoj/+IOPVAjCfXlNOi3R/nmnbew97Q== +"@lodder/grunt-postcss@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@lodder/grunt-postcss/-/grunt-postcss-2.0.2.tgz#2815e178c154fc0d5597e9a1894a7f996966aab8" + integrity sha512-zWPI9w+6bUyVn2R3yDJhYfy19WJFNUeq4ZU4OPGdqxGkPOvkNMRLUorF9iuQXG2gKdUd3zQf78I2gnuspDDRVw== dependencies: - diff "^4.0.1" + diff "^4.0.2" kleur "^3.0.3" maxmin "^2.1.0" - postcss "^7.0.24" + postcss "^7.0.27" "@metascraper/helpers@^5.11.9": version "5.11.9" @@ -346,17 +346,17 @@ dependencies: defer-to-connect "^2.0.0" -"@tryghost/adapter-manager@0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@tryghost/adapter-manager/-/adapter-manager-0.1.2.tgz#29bcbe220f70603b51d30a9ee734f257a4fe3dbc" - integrity sha512-vYG//0zXqPMzZZkw3vZXeyShsKggzPDPEaDaHwByLqbTHi8kj3bQVRq3GkmoQhx01KJB0eQwMaz8tZihU2KsyA== +"@tryghost/adapter-manager@0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@tryghost/adapter-manager/-/adapter-manager-0.1.3.tgz#035ab063c1339fce6faf0587dcd3071353ff59ba" + integrity sha512-ag5nKtIpi62nvpV7yk7U/lFSSdOkulOu2r855rk/9jmQEf0cztXClpR7L8IVbIjTMgcL6l5ImMU1yce73n0H6Q== dependencies: - "@tryghost/errors" "^0.1.1" + "@tryghost/errors" "^0.1.2" -"@tryghost/errors@0.1.1", "@tryghost/errors@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@tryghost/errors/-/errors-0.1.1.tgz#c140f8558fc54cf69ac7e7ea719a189c763fea04" - integrity sha512-8gmWGDLbwGhrMJ6psn8uubanntfxCvywufzJyDFgB/Kjh6bjd2CYEL84nA3rzfnxLpuY7vL/i4sFjpF1MZ15KA== +"@tryghost/errors@0.1.2", "@tryghost/errors@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@tryghost/errors/-/errors-0.1.2.tgz#aaf6c54923920825477f403839cb6551ad37b6d9" + integrity sha512-wwareSxmIprkNuFb+sFYBZ9vl8EEnIbV7an+35C3JBH0D1TUQ2LzaK6IFOowfc7JOQPxACeo+1Or8NHC1B/H0A== dependencies: ghost-ignition "^4.1.0" lodash "^4.17.15" @@ -377,12 +377,12 @@ "@tryghost/mobiledoc-kit" "^0.12.4-ghost.1" jsdom "16.2.2" -"@tryghost/image-transform@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@tryghost/image-transform/-/image-transform-0.2.0.tgz#c617c87634d4f1e79194f7f1ca04ee308f70e0c1" - integrity sha512-RspIBD1Sm9IDWTGyEUKk63sT1ed2uvduB26Mb8owhAmurw3lDJh5DFiG5S/7Fy/QiWoK07KPBHPMMIWT3wPDkA== +"@tryghost/image-transform@0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@tryghost/image-transform/-/image-transform-0.2.1.tgz#39a4faf730afeb47c7304c4b8aea5b3d71a1711c" + integrity sha512-Mdjqg34MMCWv2lXCYMRkCj/qdy/eLNWNucgJE0zcbMh0GnASe2ZhpTfusx80H0+xYNNH0vtpEFn/D9Vh3lG8pA== dependencies: - "@tryghost/errors" "^0.1.1" + "@tryghost/errors" "^0.1.2" bluebird "^3.7.2" fs-extra "^9.0.0" optionalDependencies: @@ -403,10 +403,10 @@ resolved "https://registry.yarnpkg.com/@tryghost/kg-default-atoms/-/kg-default-atoms-1.0.0.tgz#d423a0f19a6989051bd6bbc9c8f104c88bd5c738" integrity sha512-f6a8zIoL2w7aeZbeBj+0UPvFzE1Dd/zf3RGO+L4j/Kb4Z/yqOtoBWQun6I2H37XXoaqiiQc6Z3eW+L4iYSw1Ow== -"@tryghost/kg-default-cards@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@tryghost/kg-default-cards/-/kg-default-cards-1.1.0.tgz#0a67380c801fe9bb8957284471c2dd40e2ace4c9" - integrity sha512-TrmEiku1t6Wn4dSSVoFM5+vGsBxU6A0dWtZBt+sbygLt0wVH85aLtJWkVe/bLmmkeypHTBFT7j4FBV/xFZExFA== +"@tryghost/kg-default-cards@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@tryghost/kg-default-cards/-/kg-default-cards-1.1.1.tgz#0ece69f3c6d727daa866bed00d97ebb322812098" + integrity sha512-naa2MXQACiSTt/08dPAgZm61OHE4h4jXPtV7vl8TtYieiTylYbhWEE/LYNUxGdiF69iDYxurgbg0Rg8cm8TgpA== dependencies: "@tryghost/kg-markdown-html-renderer" "^1.0.3" "@tryghost/url-utils" "^0.6.14" @@ -421,10 +421,10 @@ markdown-it-lazy-headers "^0.1.3" markdown-it-mark "^3.0.0" -"@tryghost/kg-mobiledoc-html-renderer@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@tryghost/kg-mobiledoc-html-renderer/-/kg-mobiledoc-html-renderer-2.0.0.tgz#c7799110306b64858ba90c477bce117e13f59950" - integrity sha512-YH1VoCrPRf1Ze1CWH34FOP00e/KJ61Bf71E0SazDN92oIF2DXzBqpyycSNHin/+gOfik3wCqxJSFMbhDqGt8+A== +"@tryghost/kg-mobiledoc-html-renderer@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@tryghost/kg-mobiledoc-html-renderer/-/kg-mobiledoc-html-renderer-2.0.1.tgz#163eb693d6d3d4f6d1747ba13cd95acb5b912fcd" + integrity sha512-lcxEBLWQCplFo3/8q3rXPCJKimBHBatrAm7Tqj6BN6iOzNHjBrykDfemB1YiE7pQzn14VR+Jrm8waSfcTdjPyA== dependencies: mobiledoc-dom-renderer "^0.7.0" simple-dom "^1.4.0" @@ -436,22 +436,22 @@ dependencies: "@tryghost/kg-clean-basic-html" "^0.1.8" -"@tryghost/magic-link@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@tryghost/magic-link/-/magic-link-0.4.1.tgz#2abdab02538f8b8adbe1940b4fd2479510480e26" - integrity sha512-KprbecOkSK0iB4Q0Eav9R5fYF+KO0YQRcOoXdw+Vd77bx36vU15PzOVqO1lg931s172KVWpEhQoh6t5n58QrkQ== +"@tryghost/magic-link@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@tryghost/magic-link/-/magic-link-0.4.2.tgz#4b01a391ccb504bb6da529d4ec9aed4f7323d6ca" + integrity sha512-Fz+0u9uIQ6OdVTTZcmrPfi4dsO2pL9/TZaRro/t0hUSFINw/GDfitZgWqs02sOCulQ+XnRWt3PLOvn9SyCgkAQ== dependencies: bluebird "^3.5.5" ghost-ignition "^3.1.0" jsonwebtoken "^8.5.1" lodash "^4.17.15" -"@tryghost/members-api@0.18.0": - version "0.18.0" - resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-0.18.0.tgz#7a7bd1b36d793c65f3cb687ff52649c79c6c7114" - integrity sha512-aymN/i26GHCQI8TtoAyHejJjPrsl+PYSaFTvIq+O57F/Gg8uAH7EJCXKQYUoZKz/95VbpwE3o7QdRWpRMBjEDg== +"@tryghost/members-api@0.18.1": + version "0.18.1" + resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-0.18.1.tgz#0fe82efd5249eb91d7c40a8653995a11fded6601" + integrity sha512-HkOgyzf73NhaRD482l8VJKver9boMCzzG6ORqQQqz9cf/HBYiK+YKnLFVs85lSSbiZZqjYjtorXq+XFciQ/akQ== dependencies: - "@tryghost/magic-link" "^0.4.1" + "@tryghost/magic-link" "^0.4.2" bluebird "^3.5.4" body-parser "^1.19.0" cookies "^0.8.0" @@ -463,10 +463,10 @@ node-jose "^1.1.3" stripe "^7.4.0" -"@tryghost/members-ssr@0.7.4": - version "0.7.4" - resolved "https://registry.yarnpkg.com/@tryghost/members-ssr/-/members-ssr-0.7.4.tgz#6e86ae1c37e06bd97c451bcf0410545a6750a813" - integrity sha512-7sJZqMD13YkS85eD3817xyHgudgteNxMJTTdtng9UvkQmLmDn5iNHGZ+b2Sf6k1DcGCVj87qutXMZEWgfNWweQ== +"@tryghost/members-ssr@0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@tryghost/members-ssr/-/members-ssr-0.7.5.tgz#0e75e830411c0542c3b2c822e077087410d8167e" + integrity sha512-5F51OUgboZyJDvBOqtNMko+YnuwNeCVn5fiZm09Yz1BURmRqRMYKqhHIh6wtvCYiEIb3B6RHgJqwVkuq/BxtNQ== dependencies: bluebird "^3.5.3" concat-stream "^2.0.0" @@ -483,10 +483,10 @@ mobiledoc-dom-renderer "0.7.0" mobiledoc-text-renderer "0.4.0" -"@tryghost/mw-session-from-token@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@tryghost/mw-session-from-token/-/mw-session-from-token-0.1.0.tgz#ad73da936d3cc3abdfc7753a5098e76ae5dc271e" - integrity sha512-t6a9YMMHaQ2Uypl+WaGLc4mFKjwhfyfA+l7V9H5DwFeAFIYWcRssy/D3e+gTT3rbLC39W0vqkmZFNE2JQZuuEQ== +"@tryghost/mw-session-from-token@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@tryghost/mw-session-from-token/-/mw-session-from-token-0.1.1.tgz#c6dc0d1d8b8b26169490bad5b7264150e36938c0" + integrity sha512-0uRnZyX32ivK4r5EriI3BQJQh++RHDc15mtXC/inQyIHv3J5n3X+hQWeOcTsI+v1ftjbgU+Im5ZOe0YTpPu7Ig== "@tryghost/pretty-cli@1.2.4": version "1.2.4" @@ -496,12 +496,12 @@ chalk "^3.0.0" sywac "^1.2.1" -"@tryghost/session-service@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@tryghost/session-service/-/session-service-0.1.0.tgz#3e37f1047b6404cbac59de0953ef1246657e742d" - integrity sha512-yAnJ0Bnl5FReA8mrL+J7nc7S9QWobegaOqK0lTHQpbCHdlkXaDdkNYFniztE8BClWmHrRrtRfHLTN+eovEpenA== +"@tryghost/session-service@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@tryghost/session-service/-/session-service-0.1.1.tgz#520ba12494e761777a3303a04299e7dfb284affc" + integrity sha512-yBLk+UOrl0hC5RX2rD+l4WfHtrAENSsndEHP6ye+Qx8KkrPA5SbhTwz4mCUg8cO6RXtP774l0GrYj1AWmfA5rg== dependencies: - "@tryghost/errors" "^0.1.1" + "@tryghost/errors" "^0.1.2" "@tryghost/social-urls@0.1.9": version "0.1.9" @@ -542,16 +542,26 @@ remark "^11.0.1" unist-util-visit "^2.0.0" -"@tryghost/vhost-middleware@1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tryghost/vhost-middleware/-/vhost-middleware-1.0.2.tgz#9fd34ddbb453771c4ecb1a1e2bea786396d09181" - integrity sha512-ZUS9N4UFPCylKf0sv/c78E5Rfjf2V6OrUp6105d9k+XZ0tPXEl5mEoptQXi5hSp79hHIZfoLC65HC8HHVkVVqA== +"@tryghost/vhost-middleware@1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tryghost/vhost-middleware/-/vhost-middleware-1.0.3.tgz#c2779a3e15c21393a69a380daf95205e030eb979" + integrity sha512-nPKGrL+frenlyVOIKN9f59DR7JGP5azi+8GkWxvZsDmjic+Yh8osJgXJ9luNU35w5eIGpOvQSh9Wo8YZfsZBFw== dependencies: bluebird "^3.7.1" ghost-ignition "^4.0.0" lodash "^4.17.15" -"@tryghost/zip@1.0.0", "@tryghost/zip@^1.0.0": +"@tryghost/zip@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tryghost/zip/-/zip-1.0.1.tgz#9943a816a26cca015fc344c32e5dd2aa7301150e" + integrity sha512-TfGzmTSPPcjovNr/1qihMhyAhRS1LU4f7Nf5UT99wMgUwSpHuSKldP9i37DtDOGUvw76lYK/6A7VV96b6HxUUw== + dependencies: + archiver "^3.1.1" + bluebird "^3.7.2" + extract-zip "^2.0.0" + fs-extra "^9.0.0" + +"@tryghost/zip@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@tryghost/zip/-/zip-1.0.0.tgz#4f13e6626e963a263cc60c16f9a13ab5f3956884" integrity sha512-6QW7NAZzWRdjRIgG7S+gJzLVn6UkGVMmFVv4Np6AEoMhcc8aU75QvRNZK+SDWvipqmX7xijB5te9HsCONuNkdA== @@ -757,10 +767,10 @@ agent-base@~4.2.1: dependencies: es6-promisify "^5.0.0" -ajv@6.12.0: - version "6.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7" - integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw== +ajv@6.12.2: + version "6.12.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" + integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== dependencies: fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" @@ -2497,7 +2507,7 @@ diff@3.5.0: resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== -diff@^4.0.1, diff@^4.0.2: +diff@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== @@ -2838,10 +2848,10 @@ eslint-plugin-ember@7.10.1: ember-rfc176-data "^0.3.12" snake-case "^3.0.3" -eslint-plugin-ghost@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-ghost/-/eslint-plugin-ghost-1.1.0.tgz#c8aba0287ea4b41e4c6ca93c6c2098f2c497e265" - integrity sha512-5Q/fnEQVdVvLz+Q4XVSqTBLBACMwNCxajsOnPFPsLHfcgS/m118t/p36HxvDmAge6Gc8jH7W5ouAJT8SpHWJcg== +eslint-plugin-ghost@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-ghost/-/eslint-plugin-ghost-1.2.0.tgz#fdb69f16ffba72e1f5f3a0a7b1c6719cbaea0491" + integrity sha512-Oeqo5SwflgGv9JkbsBwqCJTuvbnl2wSNW4FdfDMJ7b4JR+xpNo0tm+2wIDhQarzc5wXMTZd5IfaBCEySYF1+Ng== dependencies: eslint-plugin-ember "7.10.1" eslint-plugin-mocha "6.3.0" @@ -3073,10 +3083,10 @@ express-query-boolean@2.0.0: resolved "https://registry.yarnpkg.com/express-query-boolean/-/express-query-boolean-2.0.0.tgz#ea56ac8138e2b95b171b8eee2af88738302941c3" integrity sha512-4dU/1HPm8lkTPR12+HFUXqCarcsC19OKOkb4otLOuADfPYrQMaugPJkSmxNsqwmWYjozvT6vdTiqkgeBHkzOow== -express-session@1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.0.tgz#9b50dbb5e8a03c3537368138f072736150b7f9b3" - integrity sha512-t4oX2z7uoSqATbMfsxWMbNjAL0T5zpvcJCk3Z9wnPPN7ibddhnmDZXHfEcoBMG2ojKXZoCyPMc5FbtK+G7SoDg== +express-session@1.17.1: + version "1.17.1" + resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.1.tgz#36ecbc7034566d38c8509885c044d461c11bf357" + integrity sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q== dependencies: cookie "0.4.0" cookie-signature "1.0.6" @@ -5223,6 +5233,27 @@ knex@0.20.14: uuid "^7.0.1" v8flags "^3.1.3" +knex@0.20.15: + version "0.20.15" + resolved "https://registry.yarnpkg.com/knex/-/knex-0.20.15.tgz#b7e9e1efd9cf35d214440d9439ed21153574679d" + integrity sha512-WHmvgfQfxA5v8pyb9zbskxCS1L1WmYgUbwBhHojlkmdouUOazvroUWlCr6KIKMQ8anXZh1NXOOtIUMnxENZG5Q== + dependencies: + colorette "1.1.0" + commander "^4.1.1" + debug "4.1.1" + esm "^3.2.25" + getopts "2.2.5" + inherits "~2.0.4" + interpret "^2.0.0" + liftoff "3.1.0" + lodash "^4.17.15" + mkdirp "^0.5.1" + pg-connection-string "2.1.0" + tarn "^2.0.0" + tildify "2.0.0" + uuid "^7.0.1" + v8flags "^3.1.3" + knex@^0.17: version "0.17.6" resolved "https://registry.yarnpkg.com/knex/-/knex-0.17.6.tgz#80220cf159cd52768d5b29118c70b18aaf5138fe" @@ -7231,7 +7262,7 @@ postcss-value-parser@^4.0.2: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz#651ff4593aa9eda8d5d0d66593a2417aeaeb325d" integrity sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg== -postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.24, postcss@^7.0.27: +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.27: version "7.0.27" resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.27.tgz#cc67cdc6b0daa375105b7c424a85567345fc54d9" integrity sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==