this.changePlan(e)}>
{
plans.map((plan) => this.renderPlan(plan))
}
@@ -87,13 +86,7 @@ export default class StripePaymentPage extends Component {
renderPlansSection() {
return (
)
@@ -102,18 +95,21 @@ export default class StripePaymentPage extends Component {
render({ error, handleSubmit, stripeConfig }) {
const publicKey = stripeConfig.config.publicKey || '';
return (
-
+
-
-
-
-
-
-
-
-
+
+
+ { this.renderPlansSection() }
+
+
Card details
+
+
+
+
+
+
+
- {this.renderPlansSection()}
)
}
diff --git a/core/server/lib/members/static/auth/styles/components.css b/core/server/lib/members/static/auth/styles/components.css
index 84b08d8007..6775ae3ba6 100644
--- a/core/server/lib/members/static/auth/styles/components.css
+++ b/core/server/lib/members/static/auth/styles/components.css
@@ -12,7 +12,7 @@
height: 100vh;
position: fixed;
overflow-y: scroll;
- background: rgba(10, 17, 23, 0.9);
+ background: linear-gradient(45deg, rgba(13,25,40,0.96) 0%,rgba(0,0,0,0.96) 100%);
animation: fadeInOverlay 0.2s ease 1 forwards;
}
@@ -21,36 +21,35 @@
}
.gm-page-overlay.close .gm-modal {
- animation: closeModal 0.5s ease-in 1 forwards;
+ animation: closeModal 0.4s ease-in-out 1 forwards;
}
.gm-modal-container {
position: relative;
- top: 50%;
- transform: translateY(-50%);
+ top: 25vh;
display: flex;
}
.gm-modal {
position: relative;
- background: white;
margin: 0 auto;
- border-radius: 8px;
- box-shadow: var(--box-shadow-base);
animation: openModal 0.6s ease 1 forwards;
}
-.gm-modal-form {
- width: 300px;
- padding: 48px;
-}
-
.gm-modal-close {
position: absolute;
top: 8px;
right: 8px;
display: block;
padding: 8px;
+ z-index: 9999;
+ padding: 20px;
+ cursor: pointer;
+}
+
+.gm-modal-close svg {
+ width: 32px;
+ height: 32px;
}
.gm-modal-close svg path {
@@ -72,35 +71,25 @@
to {opacity: 0;}
}
-@keyframes openModal { /* Safari and Chrome */
+@keyframes openModal {
0% {
- opacity: 0;
- transform: translateY(25px) scale(0.85);
- }
-
- 40% {
- opacity: 1.0;
- transform: translateY(-8px) scale(1.04);
+ /* opacity: 0; */
+ transform: scale(1.1);
}
100% {
- transform: translateY(0) scale(1.0);
+ /* opacity: 1.0; */
+ transform: scale(1.0);
}
}
-@keyframes closeModal { /* Safari and Chrome */
- 0% {
- transform: translateY(0);
+@keyframes closeModal {
+ 90% {
+ opacity: 0;
+ transform: scale(0.95);
}
-
- 40% {
- opacity: 1.0;
- transform: translateY(-8px);
- }
-
100% {
opacity: 0;
- transform: translateY(85px);
}
}
@@ -110,7 +99,7 @@
padding: 0;
top: 0;
transform: none;
- height: 100vh;
+ min-height: 100vh;
}
.gm-modal {
@@ -121,7 +110,7 @@
}
.gm-page-overlay {
- background: rgba(10, 17, 23, 0.0);
+ background: linear-gradient(45deg, rgba(13,25,40,0.96) 0%,rgba(0,0,0,0.96) 100%);
}
@keyframes openModal {
@@ -163,8 +152,8 @@ button {
text-align: center;
cursor: pointer;
white-space: nowrap;
- padding: 13px 16px 14px;
- border-radius: 4px;
+ padding: 15px 16px 16px;
+ border-radius: 6px;
outline: none;
transition: all var(--animation-speed-f1) ease-in-out;
position: relative;
@@ -231,107 +220,87 @@ select:-webkit-autofill:active {
::-moz-placeholder,
:-ms-input-placeholder,
:-moz-placeholder {
- color: var(--grey);
+ color: var(--grey-d1);
}
.gm-form-element {
- margin: 24px 0 0;
position: relative;
}
.gm-input {
position: relative;
+ border-bottom: 1px solid var(--grey-l1);
+}
+
+.gm-input.last,
+.gm-input.single {
+ border-bottom: none;
+}
+
+.gm-input.first input {
+ border-radius: 6px 6px 0 0;
+}
+
+.gm-input.last input {
+ border-radius: 0 0 6px 6px;
+}
+
+.gm-input.single input {
+ border-radius: 6px;
}
.gm-input input {
- font-size: var(--text-s);
+ font-size: var(--text-base);
color: var(--grey-d3);
border: none;
- border-radius: 4px;
- border: 1px solid var(--grey-l1);
-webkit-appearance: none;
box-sizing: border-box;
background: var(--white);
width: 100%;
outline: none;
- transition: border var(--animation-speed-f1) ease-in-out;
- padding: 12px 14px 12px 38px; /* 1px bottom padding fixes jump that's caused by the border change */
+ padding: 15px 14px 15px 38px;
letter-spacing: 0.2px;
vertical-align: middle;
line-height: 18px;
}
-.gm-input input:hover {
- border: 1px solid var(--grey);
-}
-
-.gm-input input.gm-error {
- border: 1px solid color-mod(var(--red) a(0.8));
- background: color-mod(var(--red) a(0.02))
-}
-
.gm-input input:focus {
- border: 1px solid color-mod(var(--blue) a(0.8));
- box-shadow: 0 0 6px rgba(62, 176, 239, 0.3), 0 0 0px 40px #FFF inset;
+
}
-.gm-input label {
- display: flex;
- align-items: center;
- position: absolute;
- font-size: var(--text-s);
- padding: 0 0 2px 0;
- width: 100%;
- top: 14px;
- left: 38px;
- color: var(--grey);
- transition: all var(--animation-speed-base) ease-in-out;
- pointer-events: none;
- letter-spacing: 0.4px;
- font-weight: 400;
-}
-
-.gm-input input:hover + label {
- color: var(--grey-d1);
-}
-
-.gm-input input.gm-input-filled + label,
-.gm-input input:focus + label {
- opacity: 0;
- transition-delay: 0s;
-}
-
-.gm-input input.gm-error + label {
- color: color-mod(var(--red) a(0.5));
-}
-
-.gm-input label i svg {
+.gm-input i svg {
width: 16px;
height: 16px;
}
-.gm-input label i svg path,
.gm-input i svg path {
- stroke: var(--grey);
+ stroke: var(--grey-d1);
transition: stroke var(--animation-speed-base) ease-in-out;
}
-.gm-input input:hover + label + i svg path {
- stroke: var(--grey-d1);
+.gm-input input.gm-error {
+ background: #FEEBE6;
+ box-shadow: 0 0 1px rgba(255, 0, 0, 1);
}
-.gm-input input.gm-error + label + i svg path {
+.gm-input input.gm-error + i svg path {
stroke: color-mod(var(--red) a(0.5));
}
-.gm-input input.gm-input-filled + label + i svg path,
-.gm-input input:focus + label + i svg path {
+.gm-input input.gm-error::-webkit-input-placeholder,
+.gm-input input.gm-error::-moz-placeholder,
+.gm-input input.gm-error:-ms-input-placeholder,
+.gm-input input.gm-error:-moz-placeholder {
+ color: color-mod(var(--red) a(0.75));
+}
+
+.gm-input input.gm-input-filled + i svg path {
stroke: var(--grey-d2);
}
.gm-input i {
position: absolute;
- top: 14px;
+ top: 16px;
left: 14px;
opacity: 1.0;
transition: all var(--animation-speed-base) ease-in-out;
@@ -377,13 +346,12 @@ select:-webkit-autofill:active {
}
.gm-form-errortext {
- color: var(--red);
- font-size: var(--text-s);
+ color: #FF7254;
letter-spacing: 0.4px;
- margin: 40px -2px -12px;
- background: color-mod(var(--red) a(0.08));
- padding: 11px 14px;
- font-weight: 500;
+ margin: 24px -2px 0px;
+ border: 1px solid color-mod(var(--red) a(0.4));
+ padding: 13px 14px;
+ font-weight: 400;
display: flex;
justify-content: center;
align-items: start;
@@ -396,4 +364,8 @@ select:-webkit-autofill:active {
.gm-form-errortext i {
margin: 1px 8px 0 0;
+}
+
+.gm-form-errortext i svg path {
+ stroke: #FF7254;
}
\ No newline at end of file
diff --git a/core/server/lib/members/static/auth/styles/screen.css b/core/server/lib/members/static/auth/styles/screen.css
index d8499b7d6e..93f5443c95 100644
--- a/core/server/lib/members/static/auth/styles/screen.css
+++ b/core/server/lib/members/static/auth/styles/screen.css
@@ -6,7 +6,7 @@ html {
html, body {
font-family: var(--default-font);
- color: var(--black);
+ color: var(--white);
}
body {
@@ -22,15 +22,13 @@ p {
h1 {
margin: 0;
padding: 0;
- color: var(--grey-d3);
- font-size: var(--text-2xl);
- font-weight: 700;
+ font-size: var(--text-3xl);
+ font-weight: 500;
}
h4 {
margin: 0;
padding: 0;
- color: var(--grey-d3);
font-size: var(--text-base);
}
@@ -57,10 +55,28 @@ a:hover {
.gm-logo {
width: 44px;
height: 44px;
- border-radius: 8px;
flex-shrink: 0;
margin: 0 auto;
- background: #343F44 url('../assets/images/ghost-logo.svg') center center no-repeat;
+}
+
+.gm-modal-header {
+ position: absolute;
+ top: 20px;
+ left: 24px;
+ display: flex;
+ align-items: center;
+}
+
+.gm-modal-header .gm-logo {
+ width: 38px;
+ height: 38px;
+ margin: 0 12px 0 0;
+}
+
+.gm-modal-header h2 {
+ font-size: var(--text-l);
+ color: var(--grey-l1);
+ font-weight: 400;
}
.gm-auth-header,
@@ -72,21 +88,33 @@ a:hover {
}
.gm-auth-header h1 {
- font-size: var(--text-2xl);
+ font-size: var(--text-3xl);
+ font-weight: 500;
+ color: var(--white);
+ white-space: nowrap;
}
-.gm-auth-header h4,
-.gm-auth-footer h4 {
+.gm-auth-footer {
+ margin: 24px 0 0;
+}
+
+.gm-auth-cta {
+ margin: 5px 0 0;
+ font-size: var(--text-s);
+ display: flex;
+ align-items: center;
+}
+
+.gm-auth-cta h4 {
font-weight: normal;
font-size: var(--text-s);
letter-spacing: 0.4px;
+ color: var(--grey-d1);
}
-.gm-auth-header a,
-.gm-auth-footer a {
+.gm-auth-cta a {
display: flex;
align-items: center;
- font-size: var(--text-s);
letter-spacing: 0.4px;
padding: 8px;
margin: -8px -8px -8px -2px;
@@ -95,116 +123,203 @@ a:hover {
white-space: nowrap;
}
-.gm-auth-header a:hover,
-.gm-auth-footer a:hover {
+.gm-auth-cta a:hover {
color: var(--blue-d3);
}
-.gm-auth-header a svg {
+.gm-auth-cta a svg {
width: 12px;
height: 12px;
margin: 0 0 0 4px;
}
-.gm-auth-header a svg g,
-.gm-auth-header a svg path {
+.gm-auth-cta a svg g,
+.gm-auth-cta a svg path {
fill: var(--blue);
transition: fill var(--animation-speed-f1) ease-in-out;
}
-.gm-auth-header a:hover svg g,
-.gm-auth-header a:hover svg path {
+.gm-auth-cta a:hover svg g,
+.gm-auth-cta a:hover svg path {
fill: var(--blue-d3);
}
-.gm-auth-footer {
- margin: 24px 0 0;
-}
-
.gm-forgot-link {
position: absolute;
top: 14px;
right: 14px;
z-index: 9999;
- font-size: var(--text-s);
letter-spacing: 0.4px;
}
.gm-reset-sent {
- margin: 24px 0 0;
- background: color-mod(var(--green) a(0.2));
- border-radius: 4px;
- color: color-mod(var(--green) l(-30%) s(+8%));
- padding: 12px 14px 14px;
+ padding: 24px;
+ border: 1px solid rgba(255, 255, 255, 0.3);
+ border-radius: 6px;
+ color: var(--grey-l1);
+ font-size: var(--text-base);
}
/* Custom forms */
+.gm-form-section {
+ margin: 0;
+ padding: 0;
+ font-size: var(--text-l);
+ font-weight: 400;
+ color: var(--grey-d1);
+}
.gm-floating-input .gm-forgot-input {
padding-right: 60px;
}
+.gm-modal-form {
+ width: 350px;
+}
+
@media (max-width: 440px) {
+ .gm-modal-form {
+ width: 100%;
+ /* margin-top: 60px; */
+ }
+
h4 {
display: none;
}
}
+/* Pages */
+@keyframes fadeInPage {
+ from {opacity: 0;}
+ to {opacity: 1;}
+}
+
+@keyframes fadeOutPage {
+ from {opacity: 1;}
+ to {opacity: 0;}
+}
+
+@keyframes showPlans {
+ from {left: -280px;}
+ to {left: 40px;}
+}
+
+@keyframes showPlansContainer {
+ from {width: 0px;}
+ to {width: 380px;}
+}
+
+@keyframes showPlansDivider {
+ from {margin-left: -1px; opacity: 0;}
+ to {margin-left: 40px; opacity: 0.3;}
+}
+
+
+/* Subscribe page */
+.gm-signin-page,
+.gm-signup-page,
+.gm-subscribe-page,
+.gm-reset-pwd-page {
+ animation: fadeInPage 0.6s ease 1;
+}
+
+.gm-subscribe-header {
+ display: flex;
+ width: 340px;
+ justify-content: space-between;
+ align-items: baseline;
+}
+
+.gm-subscribe-form-wrapper {
+ display: flex;
+ justify-content: stretch;
+}
+
.gm-subscribe-form {
width: 340px;
}
.gm-plans-container {
- background: var(--grey-l3);
- border-left: 1px solid var(--grey-l2);
- padding: 48px;
- min-width: 240px;
- border-top-right-radius: 8px;
- border-bottom-right-radius: 8px;
+ padding: 0;
+ width: 0px;
+ overflow: hidden;
+ position: relative;
+ display: flex;
+ justify-items: start;
+ animation: showPlansContainer 0.6s ease 0.1s forwards;
+}
+
+.gm-upgrade-page .gm-plans-container {
+ width: 100%;
+ justify-content: stretch;
+ flex-direction: column;
+ animation: none;
+ margin-top: -4px;
+}
+
+.gm-plans-divider {
+ background: linear-gradient(to bottom, rgba(255,255,255,0) 0%,rgba(255,255,255,1) 20%,rgba(255,255,255,1) 80%,rgba(255,255,255,0) 100%);
+ width: 1px;
+ margin-left: -1px;
+ opacity: 0;
+ animation: showPlansDivider 0.6s ease 0.1s forwards;
+}
+
+.gm-signin-page .gm-publication-name h2 {
+ margin: 0;
+ font-size: var(--text-2xl);
+ font-weight: 400;
+ text-align: center;
+}
+
+.gm-plans-container .gm-publication-name {
+ margin: 0 0 0 12px;
+ flex-grow: 1;
}
.gm-plans-container .gm-publication-info {
display: flex;
align-items: center;
justify-content: flex-start;
- margin: 92px 0 0;
+ margin: 0 0 24px;
}
-.gm-publication-name {
- margin: 0 0 0 12px;
- flex-grow: 1;
-}
-
-.gm-publication-name h2 {
+.gm-plans-container .gm-publication-name h2 {
padding: 0;
margin: 0;
font-size: var(--text-l);
- color: var(--grey-d3);
+ color: var(--white);
word-wrap: none;
white-space: nowrap;
+ font-weight: 400;
}
-.gm-publication-name span {
+.gm-plans-container .gm-publication-name span {
color: var(--grey-d1);
font-size: var(--text-s);
}
.gm-plans {
- border: 1px solid var(--grey-l1);
- border-radius: 8px;
- margin: 26px 0 0;
+ width: 270px;
+ margin: 70px 0 0;
+ position: absolute;
+ top: -5px;
+ left: -270px;
+ animation: showPlans 0.75s ease 0.25s forwards;
}
.gm-plan {
display: flex;
align-items: center;
- padding: 13px 16px;
- border-bottom: 1px solid var(--grey-l1);
- margin: 0;
+ padding: 13px 18px;
+ border: 1px solid var(--grey-d3);
+ margin: 0 0 20px 0;
+ border-radius: 8px;
}
-.gm-plan:last-child {
- border-bottom: none;
+.gm-plan.selected {
+ background: color-mod(var(--blue) alpha(15%));
+ border: 1px solid color-mod(var(--blue) alpha(80%));
}
.gm-plan input[type="radio"] {
@@ -222,7 +337,7 @@ a:hover {
font-size: var(--text-s);
color: var(--grey-d1);
padding: 0 0 0 9px;
- margin: 0 0 0 6px;
+ margin: 8px 0 0 6px;
}
.gm-plan .gm-interval::before {
@@ -237,16 +352,80 @@ a:hover {
transform: rotate(25deg);
}
+.gm-plan .gm-currency {
+ text-transform: uppercase;
+}
+
+@media (max-width: 440px) {
+ .gm-subscribe-form-wrapper {
+ flex-direction: column;
+ justify-content: start;
+ }
+
+ .gm-subscribe-form {
+ order: 2;
+ width: 100%;
+ }
+
+ .gm-plans-divider {
+ display: none;
+ }
+
+ .gm-plans-container {
+ order: 1;
+ width: 100%;
+ animation: none;
+ }
+
+ .gm-plans {
+ position: relative;
+ top: unset;
+ left: unset;
+ animation: none;
+ width: 100%;
+ }
+
+ .gm-plans .gm-publication-info {
+ display: none;
+ }
+
+ .gm-auth-header {
+ margin-top: 70px;
+ }
+}
+
+.gm-powered-by {
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
+ bottom: 32px;
+}
+
+.gm-powered-by a {
+ display: flex;
+ align-items: center;
+}
+
+.gm-powered-by svg {
+ height: 18px;
+ width: 72px;
+}
+
+.gm-powered-by span {
+ display: inline-block;
+ margin-left: 6px;
+ margin-bottom: 1px;
+ color: var(--grey-d2);
+}
+
/**
* The CSS shown here will not be introduced in the Quickstart guide, but shows
* how you can use CSS to style your Element's container.
*/
.StripeElement {
- font-size: var(--text-s);
color: var(--grey-d3);
border: none;
- border-radius: 4px;
- border: 1px solid var(--grey-l1);
+ border-radius: 0 0 6px 6px;
-webkit-appearance: none;
box-sizing: border-box;
background: var(--white);
@@ -255,23 +434,21 @@ a:hover {
transition: border var(--animation-speed-f1) ease-in-out;
letter-spacing: 0.2px;
line-height: 18px;
- padding: 14px 12px 14px 10px;
-}
-
-.StripeElement:hover {
- border: 1px solid var(--grey);
+ padding: 16px 12px 16px 10px;
}
.StripeElement--focus {
- border: 1px solid color-mod(var(--blue) a(0.8));
- box-shadow: 0 0 6px rgba(62, 176, 239, 0.3), 0 0 0px 40px #FFF inset;
+ /* box-shadow: 0 0 6px rgba(62, 176, 239, 0.3), 0 0 0px 40px #FFF inset; */
}
.StripeElement--invalid {
- border: 1px solid color-mod(var(--red) a(0.8));
- background: color-mod(var(--red) a(0.02))
+ background: #FEEBE6;
}
.StripeElement--webkit-autofill {
background-color: #fefde5 !important;
+}
+
+.gm-upgrade-page .StripeElement {
+ border-radius: 6px;
}
\ No newline at end of file
diff --git a/core/server/services/labs.js b/core/server/services/labs.js
index ed905997fa..fb88d4b941 100644
--- a/core/server/services/labs.js
+++ b/core/server/services/labs.js
@@ -7,14 +7,13 @@ const config = require('../config');
let labs = module.exports = {};
labs.isSet = function isSet(flag) {
+ var labsConfig = settingsCache.get('labs');
/**
* TODO: Uses hard-check for members prototype, removed here when added to settings
*/
- if (flag === 'members' && config.get('enableDeveloperExperiments')) {
- return true;
+ if (flag === 'members') {
+ return config.get('enableDeveloperExperiments') && labsConfig && labsConfig[flag] && labsConfig[flag] === true;
}
-
- var labsConfig = settingsCache.get('labs');
return labsConfig && labsConfig[flag] && labsConfig[flag] === true;
};
diff --git a/core/server/services/members/api.js b/core/server/services/members/api.js
index 7e149e41be..3a3eea793f 100644
--- a/core/server/services/members/api.js
+++ b/core/server/services/members/api.js
@@ -2,8 +2,10 @@ const url = require('url');
const settingsCache = require('../settings/cache');
const config = require('../../config');
const MembersApi = require('../../lib/members');
+const common = require('../../lib/common');
const models = require('../../models');
const mail = require('../mail');
+const blogIcon = require('../../lib/image/blog-icon');
function createMember({name, email, password}) {
return models.Member.add({
@@ -59,6 +61,43 @@ function validateMember({email, password}) {
});
}
+function parseMembersSettings() {
+ let membersSettings = settingsCache.get('members_subscription_settings');
+ if (!membersSettings) {
+ membersSettings = {
+ isPaid: false,
+ paymentProcessors: [{
+ adapter: 'stripe',
+ config: {
+ secret_token: '',
+ public_token: '',
+ product: {
+ name: 'Ghost Subscription'
+ },
+ plans: [
+ {
+ name: 'Monthly',
+ currency: 'usd',
+ interval: 'month',
+ amount: ''
+ },
+ {
+ name: 'Yearly',
+ currency: 'usd',
+ interval: 'year',
+ amount: ''
+ }
+ ]
+ }
+ }]
+ };
+ }
+ if (!membersSettings.isPaid) {
+ membersSettings.paymentProcessors = [];
+ }
+ return membersSettings;
+}
+
const publicKey = settingsCache.get('members_public_key');
const privateKey = settingsCache.get('members_private_key');
const sessionSecret = settingsCache.get('members_session_secret');
@@ -70,6 +109,7 @@ const ssoOrigin = siteOrigin;
let mailer;
const membersConfig = config.get('members');
+const membersSettings = parseMembersSettings();
function validateAudience({audience, origin}) {
if (audience === origin) {
@@ -110,6 +150,8 @@ function sendEmail(member, {token}) {
});
}
+const defaultBlogTitle = settingsCache.get('title') ? settingsCache.get('title').replace(/"/g, '\\"') : 'Publication';
+const blogIconUrl = blogIcon.getIconUrl();
const api = MembersApi({
authConfig: {
issuer,
@@ -119,7 +161,11 @@ const api = MembersApi({
ssoOrigin
},
paymentConfig: {
- processors: membersConfig.paymentProcessors
+ processors: membersSettings.paymentProcessors
+ },
+ siteConfig: {
+ title: defaultBlogTitle,
+ icon: blogIconUrl
},
validateAudience,
createMember,
@@ -130,6 +176,31 @@ const api = MembersApi({
sendEmail
});
+const updateSettingFromModel = function updateSettingFromModel(settingModel) {
+ if (settingModel.get('key') === 'members_subscription_settings'
+ || settingModel.get('key') === 'title'
+ || settingModel.get('key') === 'icon') {
+ let membersSettings = parseMembersSettings();
+ const defaultBlogTitle = settingsCache.get('title') ? settingsCache.get('title').replace(/"/g, '\\"') : 'Publication';
+ const blogIconUrl = blogIcon.getIconUrl();
+ api.reconfigureSettings({
+ paymentConfig: {
+ processors: membersSettings.paymentProcessors
+ },
+ siteConfig: {
+ title: defaultBlogTitle,
+ icon: blogIconUrl
+ }
+ });
+ }
+};
+
+// Bind to events to automatically keep subscription info up-to-date from settings
+common.events.on('settings.edited', updateSettingFromModel);
+
module.exports = api;
module.exports.publicKey = publicKey;
-module.exports.paymentConfigured = !!membersConfig.paymentProcessors.length;
+module.exports.isPaymentConfigured = function () {
+ let membersSettings = parseMembersSettings();
+ return !!membersSettings.paymentProcessors.length;
+};
\ No newline at end of file
diff --git a/core/server/services/members/index.js b/core/server/services/members/index.js
index 7a291e280c..44c7e4aa0c 100644
--- a/core/server/services/members/index.js
+++ b/core/server/services/members/index.js
@@ -1,8 +1,17 @@
-const labs = require('../labs');
+const config = require('../../config/index.js');
+const common = require('../../lib/common');
+
module.exports = {
get api() {
- if (!labs.isSet('members')) {
- return {};
+ if (!config.get('enableDeveloperExperiments')) {
+ return {
+ apiRouter: function (req, res, next) {
+ return next(new common.errors.NotFoundError());
+ },
+ staticRouter: function (req, res, next) {
+ return next(new common.errors.NotFoundError());
+ }
+ };
}
return require('./api');
}
diff --git a/core/server/web/api/index.js b/core/server/web/api/index.js
index 4adf90cff9..2d2d433e5b 100644
--- a/core/server/web/api/index.js
+++ b/core/server/web/api/index.js
@@ -4,7 +4,7 @@ const urlUtils = require('../../services/url/utils');
const errorHandler = require('../shared/middlewares/error-handler');
const membersService = require('../../services/members');
-const labs = require('../../services/labs');
+const labs = require('../shared/middlewares/labs');
module.exports = function setupApiApp() {
debug('Parent API setup start');
@@ -14,9 +14,7 @@ module.exports = function setupApiApp() {
apiApp.use(urlUtils.getVersionPath({version: 'v0.1'}), require('./v0.1/app')());
apiApp.use(urlUtils.getVersionPath({version: 'v2', type: 'content'}), require('./v2/content/app')());
apiApp.use(urlUtils.getVersionPath({version: 'v2', type: 'admin'}), require('./v2/admin/app')());
- if (labs.isSet('members')) {
- apiApp.use(urlUtils.getVersionPath({version: 'v2', type: 'members'}), membersService.api.apiRouter);
- }
+ apiApp.use(urlUtils.getVersionPath({version: 'v2', type: 'members'}), labs.members, membersService.api.apiRouter);
// Error handling for requests to non-existent API versions
apiApp.use(errorHandler.resourceNotFound);
diff --git a/core/server/web/parent-app.js b/core/server/web/parent-app.js
index b9b28bef5a..1673792d18 100644
--- a/core/server/web/parent-app.js
+++ b/core/server/web/parent-app.js
@@ -4,7 +4,7 @@ const config = require('../config');
const compress = require('compression');
const netjet = require('netjet');
const shared = require('./shared');
-const labs = require('../services/labs');
+const labs = require('./shared/middlewares/labs');
const membersService = require('../services/members');
module.exports = function setupParentApp(options = {}) {
@@ -49,9 +49,7 @@ module.exports = function setupParentApp(options = {}) {
parentApp.use('/ghost', require('./admin')());
// MEMBERS
- if (labs.isSet('members')) {
- parentApp.use('/members', membersService.api.staticRouter);
- }
+ parentApp.use('/members', labs.members, membersService.api.staticRouter);
// BLOG
parentApp.use(require('./site')(options));