mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-20 17:32:15 +03:00
a302ff1597
https://github.com/TryGhost/Team/issues/530 This option will check to see if a subscription is in an unpaid or past due state, and if so, will cancel the subscription immediately, rather than cancelling at the period end.
132 lines
4.8 KiB
JavaScript
132 lines
4.8 KiB
JavaScript
const errors = require('ghost-ignition').errors;
|
|
|
|
/**
|
|
* MemberController
|
|
*
|
|
* @param {object} deps
|
|
* @param {any} deps.memberRepository
|
|
* @param {any} deps.stripePlansService
|
|
* @param {any} deps.tokenService
|
|
*/
|
|
module.exports = class MemberController {
|
|
constructor({
|
|
memberRepository,
|
|
stripePlansService,
|
|
tokenService
|
|
}) {
|
|
this._memberRepository = memberRepository;
|
|
this._stripePlansService = stripePlansService;
|
|
this._tokenService = tokenService;
|
|
}
|
|
|
|
async updateSubscription(req, res) {
|
|
try {
|
|
const identity = req.body.identity;
|
|
const subscriptionId = req.params.id;
|
|
const cancelAtPeriodEnd = req.body.cancel_at_period_end;
|
|
const smartCancel = req.body.smart_cancel;
|
|
const cancellationReason = req.body.cancellation_reason;
|
|
const planName = req.body.planName;
|
|
|
|
if (cancelAtPeriodEnd === undefined && planName === undefined && smartCancel === undefined) {
|
|
throw new errors.BadRequestError({
|
|
message: 'Updating subscription failed!',
|
|
help: 'Request should contain "cancel_at_period_end" or "planName" or "smart_cancel" field.'
|
|
});
|
|
}
|
|
|
|
if ((cancelAtPeriodEnd === undefined || cancelAtPeriodEnd === false) && !smartCancel && cancellationReason !== undefined) {
|
|
throw new errors.BadRequestError({
|
|
message: 'Updating subscription failed!',
|
|
help: '"cancellation_reason" field requires the "cancel_at_period_end" or "smart_cancel" field to be true.'
|
|
});
|
|
}
|
|
|
|
if (cancellationReason && cancellationReason.length > 500) {
|
|
throw new errors.BadRequestError({
|
|
message: 'Updating subscription failed!',
|
|
help: '"cancellation_reason" field can be a maximum of 500 characters.'
|
|
});
|
|
}
|
|
|
|
let email;
|
|
try {
|
|
if (!identity) {
|
|
throw new errors.BadRequestError({
|
|
message: 'Updating subscription failed! Could not find member'
|
|
});
|
|
}
|
|
|
|
const claims = await this._tokenService.decodeToken(identity);
|
|
email = claims && claims.sub;
|
|
} catch (err) {
|
|
res.writeHead(401);
|
|
return res.end('Unauthorized');
|
|
}
|
|
|
|
if (!email) {
|
|
throw new errors.BadRequestError({
|
|
message: 'Invalid token'
|
|
});
|
|
}
|
|
|
|
if (planName !== undefined) {
|
|
const plan = this._stripePlansService.getPlan(planName);
|
|
if (!plan) {
|
|
throw new errors.BadRequestError({
|
|
message: 'Updating subscription failed! Could not find plan'
|
|
});
|
|
}
|
|
await this._memberRepository.updateSubscription({
|
|
email,
|
|
subscription: {
|
|
subscription_id: subscriptionId,
|
|
plan: plan.id
|
|
}
|
|
});
|
|
} else if (cancelAtPeriodEnd !== undefined) {
|
|
await this._memberRepository.updateSubscription({
|
|
email,
|
|
subscription: {
|
|
subscription_id: subscriptionId,
|
|
cancel_at_period_end: cancelAtPeriodEnd,
|
|
cancellationReason
|
|
}
|
|
});
|
|
} else if (smartCancel) {
|
|
const currentSubscription = await this._memberRepository.getSubscription({
|
|
email,
|
|
subscription: {
|
|
subscription_id: subscriptionId
|
|
}
|
|
});
|
|
|
|
if (['past_due', 'unpaid'].includes(currentSubscription.status)) {
|
|
await this._memberRepository.cancelSubscription({
|
|
email,
|
|
subscription: {
|
|
subscription_id: subscriptionId,
|
|
cancellationReason
|
|
}
|
|
});
|
|
} else {
|
|
await this._memberRepository.updateSubscription({
|
|
email,
|
|
subscription: {
|
|
subscription_id: subscriptionId,
|
|
cancel_at_period_end: true,
|
|
cancellationReason
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
res.writeHead(204);
|
|
res.end();
|
|
} catch (err) {
|
|
res.writeHead(err.statusCode || 500);
|
|
res.end(err.message);
|
|
}
|
|
}
|
|
};
|