0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00
ghost/core/server/services/members/service.js
Simon Backx ad1ebe6a47
Fixed error when firing Members webhooks (#14645)
refs https://github.com/TryGhost/Team/issues/1577

The last seen at was being updated via the model rather than the
respository, which mean that the default relations were not being
loaded.

This fix updates the repository to load the newseletters relation,
updates the last seen at updated to use the repository and updates the
output serializer to handle missing newsletter relation.

We also update all packages relying on the domain-events package to
ensure that they're all using the same version.

Co-authored-by: Fabien 'egg' O'Carroll <fabien@allou.is>
2022-05-04 12:42:27 +02:00

208 lines
7 KiB
JavaScript

const _ = require('lodash');
const errors = require('@tryghost/errors');
const tpl = require('@tryghost/tpl');
const MembersSSR = require('@tryghost/members-ssr');
const db = require('../../data/db');
const MembersConfigProvider = require('./config');
const MembersCSVImporter = require('@tryghost/members-importer');
const MembersStats = require('./stats/members-stats');
const createMembersSettingsInstance = require('./settings');
const logging = require('@tryghost/logging');
const urlUtils = require('../../../shared/url-utils');
const labsService = require('../../../shared/labs');
const settingsCache = require('../../../shared/settings-cache');
const config = require('../../../shared/config');
const models = require('../../models');
const {GhostMailer} = require('../mail');
const jobsService = require('../jobs');
const VerificationTrigger = require('@tryghost/verification-trigger');
const DomainEvents = require('@tryghost/domain-events');
const {LastSeenAtUpdater} = require('@tryghost/members-events-service');
const events = require('../../lib/common/events');
const DatabaseInfo = require('@tryghost/database-info');
const messages = {
noLiveKeysInDevelopment: 'Cannot use live stripe keys in development. Please restart in production mode.',
sslRequiredForStripe: 'Cannot run Ghost without SSL when Stripe is connected. Please update your url config to use "https://".',
remoteWebhooksInDevelopment: 'Cannot use remote webhooks in development. See https://ghost.org/docs/webhooks/#stripe-webhooks for developing with Stripe.'
};
const ghostMailer = new GhostMailer();
const membersConfig = new MembersConfigProvider({
config,
settingsCache,
urlUtils
});
const membersStats = new MembersStats({
db: db,
settingsCache: settingsCache,
isSQLite: DatabaseInfo.isSQLite(db.knex)
});
let membersApi;
let membersSettings;
let verificationTrigger;
const membersImporter = new MembersCSVImporter({
storagePath: config.getContentPath('data'),
getTimezone: () => settingsCache.get('timezone'),
getMembersApi: () => module.exports.api,
sendEmail: ghostMailer.send.bind(ghostMailer),
isSet: labsService.isSet.bind(labsService),
addJob: jobsService.addJob.bind(jobsService),
knex: db.knex,
urlFor: urlUtils.urlFor.bind(urlUtils),
context: {
importer: true
}
});
const processImport = async (options) => {
const result = await membersImporter.process(options);
// Check whether all imports in last 30 days > threshold
await verificationTrigger.testImportThreshold();
return result;
};
module.exports = {
async init() {
const stripeService = require('../stripe');
const createMembersApiInstance = require('./api');
const env = config.get('env');
events.on('settings.edited', async function (settingModel) {
if (labsService.isSet('multipleProducts')) {
return;
}
const key = settingModel.get('key');
const value = settingModel.get('value');
if (key === 'members_free_signup_redirect') {
try {
await models.Product.forge().query().update('welcome_page_url', value).where('type', 'free');
} catch (err) {
logging.error(err);
}
return;
}
if (key === 'members_paid_signup_redirect') {
try {
await models.Product.forge().query().update('welcome_page_url', value).where('type', 'paid');
} catch (err) {
logging.error(err);
}
return;
}
});
// @TODO Move to stripe service
if (env !== 'production') {
if (stripeService.api.configured && stripeService.api.mode === 'live') {
throw new errors.IncorrectUsageError({
message: tpl(messages.noLiveKeysInDevelopment)
});
}
} else {
const siteUrl = urlUtils.getSiteUrl();
if (!/^https/.test(siteUrl) && stripeService.api.configured) {
throw new errors.IncorrectUsageError({
message: tpl(messages.sslRequiredForStripe)
});
}
}
if (!membersApi) {
membersApi = createMembersApiInstance(membersConfig);
membersApi.bus.on('error', function (err) {
logging.error(err);
});
}
module.exports.ssr = MembersSSR({
cookieSecure: urlUtils.isSSL(urlUtils.getSiteUrl()),
cookieKeys: [settingsCache.get('theme_session_secret')],
cookieName: 'ghost-members-ssr',
getMembersApi: () => module.exports.api
});
verificationTrigger = new VerificationTrigger({
configThreshold: _.get(config.get('hostSettings'), 'emailVerification.importThreshold'),
isVerified: () => config.get('hostSettings:emailVerification:verified') === true,
isVerificationRequired: () => settingsCache.get('email_verification_required') === true,
sendVerificationEmail: ({subject, message, amountImported}) => {
const escalationAddress = config.get('hostSettings:emailVerification:escalationAddress');
const fromAddress = config.get('user_email');
if (escalationAddress) {
ghostMailer.send({
subject,
html: tpl(message, {
importedNumber: amountImported,
siteUrl: urlUtils.getSiteUrl()
}),
forceTextContent: true,
from: fromAddress,
to: escalationAddress
});
}
},
membersStats,
Settings: models.Settings,
eventRepository: membersApi.events
});
new LastSeenAtUpdater({
services: {
domainEvents: DomainEvents,
settingsCache
},
async getMembersApi() {
return membersApi;
}
});
(async () => {
try {
const collection = await models.SingleUseToken.fetchAll();
await collection.invokeThen('destroy');
} catch (err) {
logging.error(err);
}
})();
try {
await stripeService.migrations.execute();
} catch (err) {
logging.error(err);
}
},
contentGating: require('./content-gating'),
config: membersConfig,
get api() {
return membersApi;
},
get settings() {
if (!membersSettings) {
membersSettings = createMembersSettingsInstance(membersConfig);
}
return membersSettings;
},
ssr: null,
stripeConnect: require('./stripe-connect'),
processImport: processImport,
stats: membersStats
};
module.exports.middleware = require('./middleware');