mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 22:11:09 +03:00
Removed lib/subscriptions
no-issue This is no longer used
This commit is contained in:
parent
1c5ba6056a
commit
7376a333c2
@ -1,90 +0,0 @@
|
||||
const stripe = require('./payment-processors/stripe');
|
||||
|
||||
const adapters = {
|
||||
stripe
|
||||
};
|
||||
|
||||
module.exports = class PaymentProcessorService {
|
||||
constructor(config) {
|
||||
this._ready = new Promise((resolve, reject) => {
|
||||
this._resolveReady = resolve;
|
||||
this._rejectReady = reject;
|
||||
});
|
||||
process.nextTick(() => this.configure(config));
|
||||
}
|
||||
|
||||
configure({processors}) {
|
||||
this._processors = {};
|
||||
Promise.all(processors.map(({
|
||||
adapter,
|
||||
config
|
||||
}) => {
|
||||
this._processors[adapter] = new adapters[adapter];
|
||||
return this._processors[adapter].configure(config);
|
||||
})).then(() => {
|
||||
return Object.keys(this._processors);
|
||||
}).then(this._resolveReady, this._rejectReady);
|
||||
|
||||
return this._ready;
|
||||
}
|
||||
|
||||
getAdapters() {
|
||||
return this._ready;
|
||||
}
|
||||
|
||||
getConfig(adapter) {
|
||||
if (!adapter) {
|
||||
return Promise.reject(new Error('getConfig(adapter) requires an adapter'));
|
||||
}
|
||||
|
||||
return this._ready.then(() => {
|
||||
return this._processors[adapter].getConfig();
|
||||
});
|
||||
}
|
||||
|
||||
getPublicConfig(adapter) {
|
||||
if (!adapter) {
|
||||
return Promise.reject(new Error('getPublicConfig(adapter) requires an adapter'));
|
||||
}
|
||||
|
||||
return this._ready.then(() => {
|
||||
return this._processors[adapter].getPublicConfig();
|
||||
});
|
||||
}
|
||||
|
||||
createSubscription(member, metadata) {
|
||||
if (!metadata.adapter) {
|
||||
return Promise.reject(new Error('createSubscription(member, { adapter }) requires an adapter'));
|
||||
}
|
||||
return this._ready.then(() => {
|
||||
return this._processors[metadata.adapter].createSubscription(member, metadata);
|
||||
});
|
||||
}
|
||||
|
||||
getSubscription(member, metadata) {
|
||||
if (!metadata.adapter) {
|
||||
return Promise.reject(new Error('getSubscription(member, { adapter }) requires an adapter'));
|
||||
}
|
||||
return this._ready.then(() => {
|
||||
return this._processors[metadata.adapter].getSubscription(member, metadata);
|
||||
});
|
||||
}
|
||||
|
||||
removeSubscription(member, metadata) {
|
||||
if (!metadata.adapter) {
|
||||
return Promise.reject(new Error('removeSubscription(member, { adapter }) requires an adapter'));
|
||||
}
|
||||
return this._ready.then(() => {
|
||||
return this._processors[metadata.adapter].removeSubscription(member, metadata);
|
||||
});
|
||||
}
|
||||
|
||||
removeCustomer(member, metadata) {
|
||||
if (!metadata.adapter) {
|
||||
return Promise.reject(new Error('removeCustomer(member, { adapter }) requires an adapter'));
|
||||
}
|
||||
return this._ready.then(() => {
|
||||
return this._processors[metadata.adapter].removeCustomer(member, metadata);
|
||||
});
|
||||
}
|
||||
};
|
@ -1,75 +0,0 @@
|
||||
const hash = data => require('crypto').createHash('sha256').update(data).digest('hex');
|
||||
const {
|
||||
del: stripeDel,
|
||||
create: stripeCreate,
|
||||
retrieve: stripeRetrieve
|
||||
} = require('./stripeRequests');
|
||||
|
||||
function createDeterministicApi(resource, validResult, getAttrs, generateHashSeed) {
|
||||
const get = createGetter(resource, validResult);
|
||||
const create = createCreator(resource, getAttrs);
|
||||
const remove = createRemover(resource, get, generateHashSeed);
|
||||
const ensure = createEnsurer(get, create, generateHashSeed);
|
||||
|
||||
return {
|
||||
get, create, remove, ensure
|
||||
};
|
||||
}
|
||||
|
||||
function prefixHashSeed(stripe, seed) {
|
||||
const prefix = stripe.__TEST_MODE__ ? 'test_' : 'prod_';
|
||||
return prefix + seed;
|
||||
}
|
||||
|
||||
function createGetter(resource, validResult) {
|
||||
return function get(stripe, object, idSeed) {
|
||||
const id = hash(prefixHashSeed(stripe, idSeed));
|
||||
return stripeRetrieve(stripe, resource, id)
|
||||
.then((result) => {
|
||||
if (validResult(result)) {
|
||||
return result;
|
||||
}
|
||||
return get(stripe, object, id);
|
||||
}, (err) => {
|
||||
err.id_requested = id;
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function createCreator(resource, getAttrs) {
|
||||
return function create(stripe, id, object, ...rest) {
|
||||
return stripeCreate(
|
||||
stripe,
|
||||
resource,
|
||||
Object.assign(getAttrs(object, ...rest), {id})
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
function createRemover(resource, get, generateHashSeed) {
|
||||
return function remove(stripe, object, ...rest) {
|
||||
return get(stripe, object, generateHashSeed(object, ...rest)).then((res) => {
|
||||
return stripeDel(stripe, resource, res.id);
|
||||
}).catch((err) => {
|
||||
if (err.code !== 'resource_missing') {
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function createEnsurer(get, create, generateHashSeed) {
|
||||
return function ensure(stripe, object, ...rest) {
|
||||
return get(stripe, object, generateHashSeed(object, ...rest))
|
||||
.catch((err) => {
|
||||
if (err.code !== 'resource_missing') {
|
||||
throw err;
|
||||
}
|
||||
const id = err.id_requested;
|
||||
return create(stripe, id, object, ...rest);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = createDeterministicApi;
|
@ -1,56 +0,0 @@
|
||||
module.exports = function createStripeRequest(makeRequest) {
|
||||
return function stripeRequest(...args) {
|
||||
const errorHandler = (err) => {
|
||||
switch (err.type) {
|
||||
case 'StripeCardError':
|
||||
// Card declined
|
||||
throw err;
|
||||
case 'RateLimitError':
|
||||
// Ronseal
|
||||
return exponentiallyBackoff(makeRequest, ...args).catch((err) => {
|
||||
// We do not want to recurse further if we get RateLimitError
|
||||
// after running the exponential backoff
|
||||
if (err.type === 'RateLimitError') {
|
||||
throw err;
|
||||
}
|
||||
return errorHandler(err);
|
||||
});
|
||||
case 'StripeInvalidRequestError':
|
||||
// Invalid params to the request
|
||||
throw err;
|
||||
case 'StripeAPIError':
|
||||
// Rare internal server error from stripe
|
||||
throw err;
|
||||
case 'StripeConnectionError':
|
||||
// Weird network/https issue
|
||||
throw err;
|
||||
case 'StripeAuthenticationError':
|
||||
// Invalid API Key (probably)
|
||||
throw err;
|
||||
default:
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
return makeRequest(...args).catch(errorHandler);
|
||||
};
|
||||
};
|
||||
|
||||
function exponentiallyBackoff(makeRequest, ...args) {
|
||||
function backoffRequest(timeout, ...args) {
|
||||
return new Promise(resolve => setTimeout(resolve, timeout)).then(() => {
|
||||
return makeRequest(...args).catch((err) => {
|
||||
if (err.type !== 'RateLimitError') {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (timeout > 30000) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
return backoffRequest(timeout * 2, ...args);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return backoffRequest(1000, ...args);
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
const createDeterministicApi = require('./createDeterministicApi');
|
||||
|
||||
const isNotDeleted = x => !x.deleted;
|
||||
const getCustomerAttr = ({email}) => ({email});
|
||||
const getCustomerHashSeed = member => member.email;
|
||||
|
||||
module.exports = createDeterministicApi(
|
||||
'customers',
|
||||
isNotDeleted,
|
||||
getCustomerAttr,
|
||||
getCustomerHashSeed
|
||||
);
|
@ -1,6 +0,0 @@
|
||||
module.exports = {
|
||||
customers: require('./customers'),
|
||||
products: require('./products'),
|
||||
plans: require('./plans'),
|
||||
subscriptions: require('./subscriptions')
|
||||
};
|
@ -1,21 +0,0 @@
|
||||
const createDeterministicApi = require('./createDeterministicApi');
|
||||
|
||||
const isActive = x => x.active;
|
||||
const getPlanAttr = ({name, amount, interval, currency}, product) => ({
|
||||
nickname: name,
|
||||
amount,
|
||||
interval,
|
||||
currency,
|
||||
product: product.id,
|
||||
billing_scheme: 'per_unit'
|
||||
});
|
||||
const getPlanHashSeed = (plan, product) => {
|
||||
return product.id + plan.interval + plan.currency + plan.amount;
|
||||
};
|
||||
|
||||
module.exports = createDeterministicApi(
|
||||
'plans',
|
||||
isActive,
|
||||
getPlanAttr,
|
||||
getPlanHashSeed
|
||||
);
|
@ -1,12 +0,0 @@
|
||||
const createDeterministicApi = require('./createDeterministicApi');
|
||||
|
||||
const isActive = x => x.active;
|
||||
const getProductAttr = ({name}) => ({name, type: 'service'});
|
||||
const getProductHashSeed = () => 'Ghost Subscription';
|
||||
|
||||
module.exports = createDeterministicApi(
|
||||
'products',
|
||||
isActive,
|
||||
getProductAttr,
|
||||
getProductHashSeed
|
||||
);
|
@ -1,26 +0,0 @@
|
||||
const createStripeRequest = require('./createStripeRequest');
|
||||
|
||||
const createSource = createStripeRequest(function (stripe, customerId, stripeToken) {
|
||||
return stripe.customers.createSource(customerId, {
|
||||
source: stripeToken
|
||||
});
|
||||
});
|
||||
|
||||
const retrieve = createStripeRequest(function (stripe, resource, id) {
|
||||
return stripe[resource].retrieve(id);
|
||||
});
|
||||
|
||||
const create = createStripeRequest(function (stripe, resource, object) {
|
||||
return stripe[resource].create(object);
|
||||
});
|
||||
|
||||
const del = createStripeRequest(function (stripe, resource, id) {
|
||||
return stripe[resource].del(id);
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
createSource,
|
||||
retrieve,
|
||||
create,
|
||||
del
|
||||
};
|
@ -1,64 +0,0 @@
|
||||
const customers = require('./customers');
|
||||
const {del, create, createSource} = require('./stripeRequests');
|
||||
|
||||
function removeSubscription(stripe, member) {
|
||||
return customers.get(stripe, member, member.email).then((customer) => {
|
||||
// CASE customer has no subscriptions
|
||||
if (!customer.subscriptions || customer.subscriptions.total_count === 0) {
|
||||
throw new Error('Cannot remove subscription');
|
||||
}
|
||||
|
||||
const subscription = customer.subscriptions.data[0];
|
||||
|
||||
return del(stripe, 'subscriptions', subscription.id);
|
||||
});
|
||||
}
|
||||
|
||||
function getSubscription(stripe, member) {
|
||||
return customers.get(stripe, member, member.email).then((customer) => {
|
||||
// CASE customer has either none or multiple subscriptions
|
||||
if (!customer.subscriptions || customer.subscriptions.total_count !== 1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const subscription = customer.subscriptions.data[0];
|
||||
|
||||
// CASE subscription has multiple plans
|
||||
if (subscription.items.total_count !== 1) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const plan = subscription.plan;
|
||||
|
||||
return {
|
||||
validUntil: subscription.current_period_end,
|
||||
plan: plan.nickname,
|
||||
amount: plan.amount,
|
||||
status: subscription.status
|
||||
};
|
||||
}).catch(() => {
|
||||
return {};
|
||||
});
|
||||
}
|
||||
|
||||
function createSubscription(stripe, member, metadata) {
|
||||
return customers.ensure(stripe, member, member.email).then((customer) => {
|
||||
if (customer.subscriptions && customer.subscriptions.total_count !== 0) {
|
||||
throw new Error('Customer already has a subscription');
|
||||
}
|
||||
|
||||
return createSource(stripe, customer.id, metadata.stripeToken).then(() => {
|
||||
return create(stripe, 'subscriptions', {
|
||||
customer: customer.id,
|
||||
items: [{plan: metadata.plan.id}],
|
||||
coupon: metadata.coupon
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
create: createSubscription,
|
||||
get: getSubscription,
|
||||
remove: removeSubscription
|
||||
};
|
@ -1,119 +0,0 @@
|
||||
const api = require('./api');
|
||||
|
||||
module.exports = class StripePaymentProcessor {
|
||||
constructor() {
|
||||
this._ready = new Promise((resolve, reject) => {
|
||||
this._resolveReady = resolve;
|
||||
this._rejectReady = reject;
|
||||
});
|
||||
}
|
||||
|
||||
configure(config) {
|
||||
const stripe = require('stripe')(config.secret_token);
|
||||
stripe.__TEST_MODE__ = config.secret_token.startsWith('sk_test_');
|
||||
|
||||
api.products.ensure(stripe, config.product).then((product) => {
|
||||
return Promise.all(
|
||||
config.plans.map(plan => api.plans.ensure(stripe, plan, product))
|
||||
).then((plans) => {
|
||||
this._stripe = stripe;
|
||||
this._product = product;
|
||||
this._plans = plans;
|
||||
this._public_token = config.public_token;
|
||||
return {
|
||||
product,
|
||||
plans
|
||||
};
|
||||
});
|
||||
}).then(this._resolveReady, this._rejectReady);
|
||||
|
||||
return this._ready;
|
||||
}
|
||||
|
||||
getConfig() {
|
||||
if (!this._plans) {
|
||||
throw new Error('StripePaymentProcessor must be configured()');
|
||||
}
|
||||
|
||||
return this._ready.then(() => {
|
||||
return this._plans;
|
||||
});
|
||||
}
|
||||
|
||||
getPublicConfig() {
|
||||
if (!this._plans) {
|
||||
throw new Error('StripePaymentProcessor must be configured()');
|
||||
}
|
||||
|
||||
return this._ready.then(() => {
|
||||
return {
|
||||
adapter: 'stripe',
|
||||
config: {
|
||||
publicKey: this._public_token,
|
||||
plans: this._plans.map(({id, currency, amount, interval, nickname}) => ({
|
||||
id, currency, amount, interval,
|
||||
name: nickname
|
||||
}))
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
createSubscription(member, metadata) {
|
||||
if (!this._stripe) {
|
||||
throw new Error('StripePaymentProcessor must be configured()');
|
||||
}
|
||||
|
||||
if (!metadata.stripeToken) {
|
||||
throw new Error('createSubscription(member, {stripeToken}) missing stripeToken');
|
||||
}
|
||||
|
||||
if (!metadata.plan) {
|
||||
throw new Error('createSubscription(member, {plan}) missing plan');
|
||||
}
|
||||
|
||||
return this._ready.then(() => {
|
||||
const plan = this._plans.find(plan => plan.nickname === metadata.plan);
|
||||
|
||||
if (!plan) {
|
||||
throw new Error('Unknown plan');
|
||||
}
|
||||
|
||||
return api.subscriptions.create(this._stripe, member, {
|
||||
plan,
|
||||
stripeToken: metadata.stripeToken,
|
||||
coupon: metadata.coupon
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getSubscription(member) {
|
||||
if (!this._stripe) {
|
||||
throw new Error('StripePaymentProcessor must be configured()');
|
||||
}
|
||||
|
||||
return this._ready.then(() => {
|
||||
return api.subscriptions.get(this._stripe, member);
|
||||
});
|
||||
}
|
||||
|
||||
removeSubscription(member) {
|
||||
if (!this._stripe) {
|
||||
throw new Error('StripePaymentProcessor must be configured()');
|
||||
}
|
||||
|
||||
return this._ready.then(() => {
|
||||
return api.subscriptions.remove(this._stripe, member);
|
||||
});
|
||||
}
|
||||
|
||||
removeCustomer(member) {
|
||||
if (!this._stripe) {
|
||||
throw new Error('StripePaymentProcessor must be configured()');
|
||||
}
|
||||
|
||||
return this._ready.then(() => {
|
||||
return api.customers.remove(this._stripe, member);
|
||||
});
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user