Ghost/core/server/services/members/api.js
Rishabh Garg c03ca79c66
Added Admin API for deleting members (#10673)
no issue

- Added new API to delete members
- Added methods to handle e2e member deletion
- Deleting member via Admin leads to
  - Removal of member from payment processor and cancelling all active subscriptions immediately
  - Removal of member information from DB
2019-04-13 10:38:56 +05:30

218 lines
6.2 KiB
JavaScript

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({
name,
email,
password
}).then((member) => {
return member.toJSON();
});
}
function updateMember(member, newData) {
return models.Member.findOne(member, {
require: true
}).then(({id}) => {
return models.Member.edit(newData, {id});
}).then((member) => {
return member.toJSON();
});
}
function getMember(data, options) {
options = options || {};
return models.Member.findOne(data, options).then((model) => {
if (!model) {
return null;
}
return model.toJSON(options);
});
}
function deleteMember(options) {
options = options || {};
return models.Member.destroy(options).catch(models.Member.NotFoundError, () => {
throw new common.errors.NotFoundError({
message: common.i18n.t('errors.api.resource.resourceNotFound', {
resource: 'Member'
})
});
});
}
function listMembers(options) {
return models.Member.findPage(options).then((models) => {
return {
members: models.data.map(model => model.toJSON(options)),
meta: models.meta
};
});
}
function validateMember({email, password}) {
return models.Member.findOne({email}, {
require: true
}).then((member) => {
return member.comparePassword(password).then((res) => {
if (!res) {
throw new Error('Password is incorrect');
}
return member;
});
}).then((member) => {
return member.toJSON();
});
}
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');
const passwordResetUrl = config.get('url');
const {protocol, host} = url.parse(config.get('url'));
const siteOrigin = `${protocol}//${host}`;
const issuer = siteOrigin;
const ssoOrigin = siteOrigin;
let mailer;
const membersConfig = config.get('members');
const membersSettings = parseMembersSettings();
function validateAudience({audience, origin}) {
if (audience === origin) {
return Promise.resolve();
}
if (audience === siteOrigin) {
if (membersConfig.contentApiAccess.includes(origin)) {
return Promise.resolve();
}
}
return Promise.reject();
}
function sendEmail(member, {token}) {
if (!(mailer instanceof mail.GhostMailer)) {
mailer = new mail.GhostMailer();
}
const message = {
to: member.email,
subject: 'Reset password',
html: `
Hi ${member.name},
To reset your password, click the following link and follow the instructions:
${passwordResetUrl}#reset-password?token=${token}
If you didn't request a password change, just ignore this email.
`
};
/* eslint-disable */
// @TODO remove this
console.log(message.html);
/* eslint-enable */
return mailer.send(message).catch((err) => {
return Promise.reject(err);
});
}
const defaultBlogTitle = settingsCache.get('title') ? settingsCache.get('title').replace(/"/g, '\\"') : 'Publication';
const blogIconUrl = blogIcon.getIconUrl();
const api = MembersApi({
authConfig: {
issuer,
publicKey,
privateKey,
sessionSecret,
ssoOrigin
},
paymentConfig: {
processors: membersSettings.paymentProcessors
},
siteConfig: {
title: defaultBlogTitle,
icon: blogIconUrl
},
validateAudience,
createMember,
getMember,
deleteMember,
listMembers,
validateMember,
updateMember,
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.isPaymentConfigured = function () {
let membersSettings = parseMembersSettings();
return !!membersSettings.paymentProcessors.length;
};