Ghost/core/server/services/members/api.js
Sam Lord 97451a93cb
Extract logging from DI patterns, only use @tryghost/logging package
refs: https://github.com/TryGhost/Toolbox/issues/146

Switched to @tryghost/logging instead of passing around the library. The main sticking points of this change are jobs. When jobs are launched we don't want them to use a separate @tryghost/logging instance because they would start parallel rotation jobs. @tryghost/logging v2.x passes all logs to the parent process if run in a child process, so that we can use the same patterns in jobs and the rest of the codebase.
2021-12-06 18:00:55 +00:00

216 lines
8.4 KiB
JavaScript

const stripeService = require('../stripe');
const settingsCache = require('../../../shared/settings-cache');
const MembersApi = require('@tryghost/members-api');
const logging = require('@tryghost/logging');
const mail = require('../mail');
const models = require('../../models');
const signinEmail = require('./emails/signin');
const signupEmail = require('./emails/signup');
const signupPaidEmail = require('./emails/signup-paid');
const subscribeEmail = require('./emails/subscribe');
const updateEmail = require('./emails/updateEmail');
const SingleUseTokenProvider = require('./SingleUseTokenProvider');
const urlUtils = require('../../../shared/url-utils');
const labsService = require('../../../shared/labs');
const offersService = require('../offers');
const MAGIC_LINK_TOKEN_VALIDITY = 24 * 60 * 60 * 1000;
const ghostMailer = new mail.GhostMailer();
module.exports = createApiInstance;
function createApiInstance(config) {
const membersApiInstance = MembersApi({
tokenConfig: config.getTokenConfig(),
auth: {
getSigninURL: config.getSigninURL.bind(config),
allowSelfSignup: config.getAllowSelfSignup(),
tokenProvider: new SingleUseTokenProvider(models.SingleUseToken, MAGIC_LINK_TOKEN_VALIDITY)
},
mail: {
transporter: {
sendMail(message) {
if (process.env.NODE_ENV !== 'production') {
logging.warn(message.text);
}
let msg = Object.assign({
from: config.getAuthEmailFromAddress(),
subject: 'Signin',
forceTextContent: true
}, message);
return ghostMailer.send(msg);
}
},
getSubject(type) {
const siteTitle = settingsCache.get('title');
switch (type) {
case 'subscribe':
return `📫 Confirm your subscription to ${siteTitle}`;
case 'signup':
return `🙌 Complete your sign up to ${siteTitle}!`;
case 'signup-paid':
return `🙌 Thank you for signing up to ${siteTitle}!`;
case 'updateEmail':
return `📫 Confirm your email update for ${siteTitle}!`;
case 'signin':
default:
return `🔑 Secure sign in link for ${siteTitle}`;
}
},
getText(url, type, email) {
const siteTitle = settingsCache.get('title');
switch (type) {
case 'subscribe':
return `
Hey there,
You're one tap away from subscribing to ${siteTitle} — please confirm your email address with this link:
${url}
For your security, the link will expire in 24 hours time.
All the best!
---
Sent to ${email}
If you did not make this request, you can simply delete this message. You will not be subscribed.
`;
case 'signup':
return `
Hey there!
Tap the link below to complete the signup process for ${siteTitle}, and be automatically signed in:
${url}
For your security, the link will expire in 24 hours time.
See you soon!
---
Sent to ${email}
If you did not make this request, you can simply delete this message. You will not be signed up, and no account will be created for you.
`;
case 'signup-paid':
return `
Hey there!
Thank you for subscribing to ${siteTitle}. Tap the link below to be automatically signed in:
${url}
For your security, the link will expire in 24 hours time.
See you soon!
---
Sent to ${email}
Thank you for subscribing to ${siteTitle}!
`;
case 'updateEmail':
return `
Hey there,
Please confirm your email address with this link:
${url}
For your security, the link will expire in 24 hours time.
---
Sent to ${email}
If you did not make this request, you can simply delete this message. This email address will not be used.
`;
case 'signin':
default:
return `
Hey there,
Welcome back! Use this link to securely sign in to your ${siteTitle} account:
${url}
For your security, the link will expire in 24 hours time.
See you soon!
---
Sent to ${email}
If you did not make this request, you can safely ignore this email.
`;
}
},
getHTML(url, type, email) {
const siteTitle = settingsCache.get('title');
const siteUrl = urlUtils.urlFor('home', true);
const domain = urlUtils.urlFor('home', true).match(new RegExp('^https?://([^/:?#]+)(?:[/:?#]|$)', 'i'));
const siteDomain = (domain && domain[1]);
const accentColor = settingsCache.get('accent_color');
switch (type) {
case 'subscribe':
return subscribeEmail({url, email, siteTitle, accentColor, siteDomain, siteUrl});
case 'signup':
return signupEmail({url, email, siteTitle, accentColor, siteDomain, siteUrl});
case 'signup-paid':
return signupPaidEmail({url, email, siteTitle, accentColor, siteDomain, siteUrl});
case 'updateEmail':
return updateEmail({url, email, siteTitle, accentColor, siteDomain, siteUrl});
case 'signin':
default:
return signinEmail({url, email, siteTitle, accentColor, siteDomain, siteUrl});
}
}
},
paymentConfig: {
stripe: config.getStripePaymentConfig()
},
models: {
/**
* Settings do not have their own models, so we wrap the webhook in a "fake" model
*/
StripeWebhook: {
async upsert(data, options) {
const settings = [{
key: 'members_stripe_webhook_id',
value: data.webhook_id
}, {
key: 'members_stripe_webhook_secret',
value: data.secret
}];
await models.Settings.edit(settings, options);
}
},
StripeCustomer: models.MemberStripeCustomer,
StripeCustomerSubscription: models.StripeCustomerSubscription,
Member: models.Member,
MemberSubscribeEvent: models.MemberSubscribeEvent,
MemberPaidSubscriptionEvent: models.MemberPaidSubscriptionEvent,
MemberLoginEvent: models.MemberLoginEvent,
MemberEmailChangeEvent: models.MemberEmailChangeEvent,
MemberPaymentEvent: models.MemberPaymentEvent,
MemberStatusEvent: models.MemberStatusEvent,
MemberProductEvent: models.MemberProductEvent,
MemberAnalyticEvent: models.MemberAnalyticEvent,
OfferRedemption: models.OfferRedemption,
Offer: models.Offer,
StripeProduct: models.StripeProduct,
StripePrice: models.StripePrice,
Product: models.Product,
Settings: models.Settings
},
stripeAPIService: stripeService.api,
offersAPI: offersService.api,
labsService: labsService
});
return membersApiInstance;
}