diff --git a/core/frontend/services/themes/middleware.js b/core/frontend/services/themes/middleware.js index 69d3f0ca97..67a07d43f9 100644 --- a/core/frontend/services/themes/middleware.js +++ b/core/frontend/services/themes/middleware.js @@ -78,10 +78,15 @@ function updateLocalTemplateOptions(req, res, next) { url: urlUtils.urlFor('home', {secure: req.secure, trailingSlash: false}, true) }; + const member = req.member ? { + email: req.member.email, + subscribed: req.member.plans.length !== 0 + } : null; + hbs.updateLocalTemplateOptions(res.locals, _.merge({}, localTemplateOptions, { // @TODO: remove blog if we drop v2 (Ghost 4.0) data: { - member: req.member, + member: member, site: siteData, blog: siteData } diff --git a/core/server/public/members.js b/core/server/public/members.js index 6481b380bd..484bc9eeb4 100644 --- a/core/server/public/members.js +++ b/core/server/public/members.js @@ -1,15 +1,22 @@ Array.prototype.forEach.call(document.querySelectorAll('form[data-members-form]'), function (form){ - form.addEventListener('submit', function (event) { + var errorEl = form.querySelector('[data-members-error]'); + function submitHandler(event) { + form.removeEventListener('submit', submitHandler); event.preventDefault(); + if (errorEl) { + errorEl.innerText = ''; + } form.classList.remove('success', 'invalid', 'error'); var input = event.target.querySelector('input[data-members-email]'); var email = input.value; if (!email.includes('@')) { form.classList.add('invalid') + form.addEventListener('submit', submitHandler); return; } + form.classList.add('loading'); fetch('{{admin-url}}/api/canary/members/send-magic-link/', { method: 'POST', headers: { @@ -19,21 +26,33 @@ Array.prototype.forEach.call(document.querySelectorAll('form[data-members-form]' email: email }) }).then(function (res) { + form.addEventListener('submit', submitHandler); + form.classList.remove('loading'); if (res.ok) { form.classList.add('success') } else { + if (errorEl) { + errorEl.innerText = 'There was an error sending the email, please try again'; + } form.classList.add('error') } }); - }); + } + form.addEventListener('submit', submitHandler); }); -Array.prototype.forEach.call(document.querySelectorAll('[data-members-subscription]'), function (button) { - button.addEventListener('click', function (event) { +Array.prototype.forEach.call(document.querySelectorAll('[data-members-plan]'), function (el) { + var errorEl = el.querySelector('[data-members-error]'); + function clickHandler(event) { + el.removeEventListener('click', clickHandler); event.preventDefault(); - var plan = event.target.dataset.membersSubscriptionPlan; + var plan = el.dataset.membersPlan; + if (errorEl) { + errorEl.innerText = ''; + } + el.classList.add('loading'); fetch('{{blog-url}}/members/ssr', { credentials: 'same-origin' }).then(function (res) { @@ -62,8 +81,42 @@ Array.prototype.forEach.call(document.querySelectorAll('[data-members-subscripti return stripe.redirectToCheckout({ sessionId: result.sessionId }); + }).then(function (result) { + if (result.error) { + throw new Error(result.error.message); + } + }).catch(function (err) { + console.error(err); + el.addEventListener('click', clickHandler); + el.classList.remove('loading'); + if (errorEl) { + errorEl.innerText = err.message; + } + el.classList.add('error'); }); - }); + } + el.addEventListener('click', clickHandler); +}); + +Array.prototype.forEach.call(document.querySelectorAll('[data-members-signout]'), function (el) { + function clickHandler(event) { + el.removeEventListener('click', clickHandler); + event.preventDefault(); + el.classList.remove('error'); + el.classList.add('loading'); + fetch('{{blog-url}}/members/ssr', { + method: 'DELETE' + }).then(function (res) { + if (res.ok) { + window.location.reload(); + } else { + el.addEventListener('click', clickHandler); + el.classList.remove('loading'); + el.classList.add('error'); + } + }); + } + el.addEventListener('click', clickHandler); }); var magicLinkRegEx = /token=([a-zA-Z0-9_\-]+\.[a-zA-Z0-9_\-]+\.[a-zA-Z0-9_\-]+)/; diff --git a/core/server/public/members.min.js b/core/server/public/members.min.js index 88cfb10ea6..beb17e89b3 100644 --- a/core/server/public/members.min.js +++ b/core/server/public/members.min.js @@ -1 +1 @@ -Array.prototype.forEach.call(document.querySelectorAll("form[data-members-form]"),function(form){form.addEventListener("submit",function(event){event.preventDefault(),form.classList.remove("success","invalid","error");var email=event.target.querySelector("input[data-members-email]").value;email.includes("@")?fetch("{{admin-url}}/api/canary/members/send-magic-link/",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:email})}).then(function(res){res.ok?form.classList.add("success"):form.classList.add("error")}):form.classList.add("invalid")})}),Array.prototype.forEach.call(document.querySelectorAll("[data-members-subscription]"),function(button){button.addEventListener("click",function(event){event.preventDefault();var plan=event.target.dataset.membersSubscriptionPlan;fetch("{{blog-url}}/members/ssr",{credentials:"same-origin"}).then(function(res){if(!res.ok)throw new Error("Could not get identity token");return res.text()}).then(function(identity){return fetch("{{admin-url}}/api/canary/members/create-stripe-checkout-session/",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plan:plan,identity:identity})}).then(function(res){if(!res.ok)throw new Error("Could not create stripe checkout session");return res.json()})}).then(function(result){return Stripe(result.publicKey).redirectToCheckout({sessionId:result.sessionId})})})});var magicLinkRegEx=/token=([a-zA-Z0-9_\-]+\.[a-zA-Z0-9_\-]+\.[a-zA-Z0-9_\-]+)/,match=location.search.match(magicLinkRegEx),isMagicLink=!!match,token=match&&match[1];isMagicLink&&fetch("{{blog-url}}/members/ssr",{method:"POST",body:token}).then(function(res){res.ok&&(window.location.search=window.location.search.replace(magicLinkRegEx,""))}); +Array.prototype.forEach.call(document.querySelectorAll("form[data-members-form]"),function(form){var errorEl=form.querySelector("[data-members-error]");function submitHandler(event){form.removeEventListener("submit",submitHandler);event.preventDefault();if(errorEl){errorEl.innerText=""}form.classList.remove("success","invalid","error");var input=event.target.querySelector("input[data-members-email]");var email=input.value;if(!email.includes("@")){form.classList.add("invalid");form.addEventListener("submit",submitHandler);return}form.classList.add("loading");fetch("{{admin-url}}/api/canary/members/send-magic-link/",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:email})}).then(function(res){form.addEventListener("submit",submitHandler);form.classList.remove("loading");if(res.ok){form.classList.add("success")}else{if(errorEl){errorEl.innerText="There was an error sending the email, please try again"}form.classList.add("error")}})}form.addEventListener("submit",submitHandler)});Array.prototype.forEach.call(document.querySelectorAll("[data-members-plan]"),function(el){var errorEl=el.querySelector("[data-members-error]");function clickHandler(event){el.removeEventListener("click",clickHandler);event.preventDefault();var plan=el.dataset.membersPlan;if(errorEl){errorEl.innerText=""}el.classList.add("loading");fetch("{{blog-url}}/members/ssr",{credentials:"same-origin"}).then(function(res){if(!res.ok){throw new Error("Could not get identity token")}return res.text()}).then(function(identity){return fetch("{{admin-url}}/api/canary/members/create-stripe-checkout-session/",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({plan:plan,identity:identity})}).then(function(res){if(!res.ok){throw new Error("Could not create stripe checkout session")}return res.json()})}).then(function(result){var stripe=Stripe(result.publicKey);return stripe.redirectToCheckout({sessionId:result.sessionId})}).then(function(result){if(result.error){throw new Error(result.error.message)}}).catch(function(err){console.error(err);el.addEventListener("click",clickHandler);el.classList.remove("loading");if(errorEl){errorEl.innerText=err.message}el.classList.add("error")})}el.addEventListener("click",clickHandler)});Array.prototype.forEach.call(document.querySelectorAll("[data-members-signout]"),function(el){function clickHandler(event){el.removeEventListener("click",clickHandler);event.preventDefault();el.classList.remove("error");el.classList.add("loading");fetch("{{blog-url}}/members/ssr",{method:"DELETE"}).then(function(res){if(res.ok){window.location.reload()}else{el.addEventListener("click",clickHandler);el.classList.remove("loading");el.classList.add("error")}})}el.addEventListener("click",clickHandler)});var magicLinkRegEx=/token=([a-zA-Z0-9_\-]+\.[a-zA-Z0-9_\-]+\.[a-zA-Z0-9_\-]+)/;var match=location.search.match(magicLinkRegEx);var isMagicLink=!!match;var token=match&&match[1];if(isMagicLink){fetch("{{blog-url}}/members/ssr",{method:"POST",body:token}).then(function(res){if(res.ok){window.location.search=window.location.search.replace(magicLinkRegEx,"")}})} diff --git a/core/server/services/members/api.js b/core/server/services/members/api.js index 06ddb6ee06..b5b528f3d0 100644 --- a/core/server/services/members/api.js +++ b/core/server/services/members/api.js @@ -102,6 +102,9 @@ function createApiInstance() { mail: { transporter: { sendMail(message) { + if (process.env.NODE_ENV !== 'production') { + common.logging.warn(message.text); + } return ghostMailer.send(Object.assign({subject: 'Signin'}, message)); } } diff --git a/package.json b/package.json index 049eea5b22..182c459ece 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "dependencies": { "@nexes/nql": "0.3.0", "@tryghost/helpers": "1.1.9", - "@tryghost/members-api": "0.5.0", + "@tryghost/members-api": "0.5.2", "@tryghost/members-ssr": "0.4.0", "@tryghost/social-urls": "0.1.2", "@tryghost/string": "^0.1.3", @@ -81,14 +81,14 @@ "got": "9.6.0", "gscan": "2.7.0", "html-to-text": "5.1.1", - "image-size": "0.7.4", + "image-size": "0.7.5", "intl": "1.2.5", "intl-messageformat": "5.4.3", "js-yaml": "3.13.1", "jsonpath": "1.0.2", "jsonwebtoken": "8.5.1", "keypair": "1.0.1", - "knex": "0.19.3", + "knex": "0.19.4", "knex-migrator": "3.3.3", "lodash": "4.17.15", "markdown-it": "9.1.0", @@ -153,12 +153,12 @@ "matchdep": "2.0.0", "mocha": "6.2.0", "mock-knex": "0.4.6", - "nock": "11.3.3", + "nock": "11.3.4", "proxyquire": "2.1.3", "rewire": "4.0.1", "should": "13.2.3", "should-http": "0.1.1", - "sinon": "7.4.1", + "sinon": "7.4.2", "supertest": "4.0.2", "tmp": "0.0.33" }, diff --git a/yarn.lock b/yarn.lock index 75c9c0111b..83c8ba6a29 100644 --- a/yarn.lock +++ b/yarn.lock @@ -130,7 +130,7 @@ "@sinonjs/commons" "^1" "@sinonjs/samsam" "^3.1.0" -"@sinonjs/samsam@^3.1.0", "@sinonjs/samsam@^3.3.2": +"@sinonjs/samsam@^3.1.0", "@sinonjs/samsam@^3.3.3": version "3.3.3" resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-3.3.3.tgz#46682efd9967b259b81136b9f120fd54585feb4a" integrity sha512-bKCMKZvWIjYD0BLGnNrxVuw4dkWCYsLqFOUWw8VgKF/+5Y+mE7LfHWPIYoDXowH+3a9LsWDMo0uAP8YDosPvHQ== @@ -189,7 +189,7 @@ dependencies: "@tryghost/kg-clean-basic-html" "^0.1.3" -"@tryghost/magic-link@^0.1.0": +"@tryghost/magic-link@^0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@tryghost/magic-link/-/magic-link-0.1.1.tgz#717bc4b6cd87ab4bab97d081c5ff82b59c72a0b7" integrity sha512-X1qE+/5ihAhY5CzzqttXoHNp9cLrT32WjBn45ddBkE1iTrEckq5Q1k74NomEkEtPnjkymyFXeMX+/sY+Nu2v3A== @@ -199,12 +199,12 @@ jsonwebtoken "^8.5.1" lodash "^4.17.15" -"@tryghost/members-api@0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-0.5.0.tgz#3d45847831082a8345a20b251c234e125223030c" - integrity sha512-l8X67ixWRsqoJMPTRBYxx5OrhbKQSXuyH7rD70w4JJMVT5+89QGBkCpSBtFsIuscuorXEACEA0rBSDAJR97E3A== +"@tryghost/members-api@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-0.5.2.tgz#3b4551f8788c8d25dbff13da8b142069995c23cc" + integrity sha512-QSliRpCaGNhyPT0JvHUghhh113hFgbl2/3jN7vIswq+agMXDZV/OvLATTgThHV7/KsBO9eJZ010YLRjyVAbOhw== dependencies: - "@tryghost/magic-link" "^0.1.0" + "@tryghost/magic-link" "^0.1.1" bluebird "^3.5.4" body-parser "^1.19.0" cookies "^0.7.3" @@ -1448,6 +1448,11 @@ commander@^2.19.0, commander@^2.20.0, commander@^2.9.0, commander@~2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== +commander@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-3.0.1.tgz#4595aec3530525e671fb6f85fb173df8ff8bf57a" + integrity sha512-UNgvDd+csKdc9GD4zjtkHKQbT8Aspt2jCBqNSPp53vAS0L1tS9sXB2TCEOPHJ7kt9bN/niWkYj8T3RQSoMXdSQ== + common-tags@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" @@ -3965,7 +3970,12 @@ image-extensions@~1.1.0: resolved "https://registry.yarnpkg.com/image-extensions/-/image-extensions-1.1.0.tgz#b8e6bf6039df0056e333502a00b6637a3105d894" integrity sha1-uOa/YDnfAFbjM1AqALZjejEF2JQ= -image-size@0.7.4, image-size@^0.7.4: +image-size@0.7.5: + version "0.7.5" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.7.5.tgz#269f357cf5797cb44683dfa99790e54c705ead04" + integrity sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g== + +image-size@^0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.7.4.tgz#092c1e541a93511917bfc957a1fc7add21c72e87" integrity sha512-GqPgxs+VkOr12aWwjSkyRzf5atzObWpFtiRuDgxCl2I/SDpZOKZFRD3iIAeAN6/usmn8SeLWRt7a8JRYK0Whbw== @@ -4684,14 +4694,14 @@ knex-migrator@3.3.3: mysql "^2.16.0" sqlite3 "^4.0.6" -knex@0.19.3: - version "0.19.3" - resolved "https://registry.yarnpkg.com/knex/-/knex-0.19.3.tgz#b5d85b29a127f631a6924e8727c76e53e26cc713" - integrity sha512-HN32QB5PVkUYfvE4UoK/Tbf6UQ7CLEgS0PL8EP6xfonsP0IPZr2M84dy1dIy2KnB5dx+XO6NNEPgfzo8Y8BYzA== +knex@0.19.4: + version "0.19.4" + resolved "https://registry.yarnpkg.com/knex/-/knex-0.19.4.tgz#cf62f8824392387152a0a188a6585d5dea6832bb" + integrity sha512-FRnR2iWEAoKkrVo3KyiEYeGwUjZOZT2WDko/tn3nCKzQdn6m8+5qSUeYLGa9zM8SwFGJriYKQSSMiDJKLILcMQ== dependencies: bluebird "^3.5.5" colorette "1.1.0" - commander "^2.20.0" + commander "^3.0.1" debug "4.1.1" getopts "2.2.5" inherits "~2.0.4" @@ -5749,7 +5759,7 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -nise@^1.5.1: +nise@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/nise/-/nise-1.5.2.tgz#b6d29af10e48b321b307e10e065199338eeb2652" integrity sha512-/6RhOUlicRCbE9s+94qCUsyE+pKlVJ5AhIv+jEE7ESKwnbXqulKZ1FYU+XAtHHWE9TinYvAxDUJAb912PwPoWA== @@ -5767,10 +5777,10 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" -nock@11.3.3: - version "11.3.3" - resolved "https://registry.yarnpkg.com/nock/-/nock-11.3.3.tgz#f4553d87ac8e501d7a995a50df7e24857f879f58" - integrity sha512-SrRux5onbWf2ItpmietnLYis+C2QYF08hAo9wv/3QLqaLJVHBSVBTL0EvlD8Hjrm7lTH4vExTzr9gQUsPqy5Cg== +nock@11.3.4: + version "11.3.4" + resolved "https://registry.yarnpkg.com/nock/-/nock-11.3.4.tgz#b3d8fde986da8f8484f4b8958e270fbb91250430" + integrity sha512-Mqjk3DeOkuji8eYaveUku+vMswxzVyhrKAz1J9jE86IsEHQg4136Z/PHz81lcjyz9F3yrJXu56Gb/S+LFUOZVg== dependencies: chai "^4.1.2" debug "^4.1.0" @@ -7627,17 +7637,17 @@ simple-swizzle@^0.2.2: rai "~0.1.11" xoauth2 "~0.1.8" -sinon@7.4.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.4.1.tgz#bcd0c63953893e87fa0cc502f52489c32a83d4d9" - integrity sha512-7s9buHGHN/jqoy/v4bJgmt0m1XEkCEd/tqdHXumpBp0JSujaT4Ng84JU5wDdK4E85ZMq78NuDe0I3NAqXY8TFg== +sinon@7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.4.2.tgz#ecd54158fef2fcfbdb231a3fa55140e8cb02ad6c" + integrity sha512-pY5RY99DKelU3pjNxcWo6XqeB1S118GBcVIIdDi6V+h6hevn1izcg2xv1hTHW/sViRXU7sUOxt4wTUJ3gsW2CQ== dependencies: "@sinonjs/commons" "^1.4.0" "@sinonjs/formatio" "^3.2.1" - "@sinonjs/samsam" "^3.3.2" + "@sinonjs/samsam" "^3.3.3" diff "^3.5.0" lolex "^4.2.0" - nise "^1.5.1" + nise "^1.5.2" supports-color "^5.5.0" slash@^2.0.0: