mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-03 23:00:14 -05:00
96bb441fb3
refs https://github.com/TryGhost/Team/issues/1599 - portal now uses offer content api to read offer details from id
207 lines
6.8 KiB
JavaScript
207 lines
6.8 KiB
JavaScript
const _ = require('lodash');
|
|
const logging = require('@tryghost/logging');
|
|
const membersService = require('./service');
|
|
const models = require('../../models');
|
|
const urlUtils = require('../../../shared/url-utils');
|
|
const {formattedMemberResponse} = require('./utils');
|
|
|
|
// @TODO: This piece of middleware actually belongs to the frontend, not to the member app
|
|
// Need to figure a way to separate these things (e.g. frontend actually talks to members API)
|
|
const loadMemberSession = async function (req, res, next) {
|
|
try {
|
|
const member = await membersService.ssr.getMemberDataFromSession(req, res);
|
|
Object.assign(req, {member});
|
|
res.locals.member = req.member;
|
|
next();
|
|
} catch (err) {
|
|
Object.assign(req, {member: null});
|
|
next();
|
|
}
|
|
};
|
|
|
|
const getIdentityToken = async function (req, res) {
|
|
try {
|
|
const token = await membersService.ssr.getIdentityTokenForMemberFromSession(req, res);
|
|
res.writeHead(200);
|
|
res.end(token);
|
|
} catch (err) {
|
|
res.writeHead(204);
|
|
res.end();
|
|
}
|
|
};
|
|
|
|
const deleteSession = async function (req, res) {
|
|
try {
|
|
await membersService.ssr.deleteSession(req, res);
|
|
res.writeHead(204);
|
|
res.end();
|
|
} catch (err) {
|
|
res.writeHead(err.statusCode);
|
|
res.end(err.message);
|
|
}
|
|
};
|
|
|
|
const getMemberData = async function (req, res) {
|
|
try {
|
|
const member = await membersService.ssr.getMemberDataFromSession(req, res);
|
|
if (member) {
|
|
res.json(formattedMemberResponse(member));
|
|
} else {
|
|
res.json(null);
|
|
}
|
|
} catch (err) {
|
|
res.writeHead(204);
|
|
res.end();
|
|
}
|
|
};
|
|
|
|
const getMemberNewsletters = async function (req, res) {
|
|
try {
|
|
const memberUuid = req.query.uuid;
|
|
|
|
if (!memberUuid) {
|
|
res.writeHead(400);
|
|
return res.end('Invalid member uuid');
|
|
}
|
|
|
|
const memberData = await membersService.api.members.get({
|
|
uuid: memberUuid
|
|
}, {
|
|
withRelated: ['newsletters']
|
|
});
|
|
|
|
if (!memberData) {
|
|
res.writeHead(404);
|
|
return res.end('Email address not found.');
|
|
}
|
|
|
|
const data = _.pick(memberData.toJSON(), 'uuid', 'email', 'name', 'newsletters', 'status');
|
|
return res.json(data);
|
|
} catch (err) {
|
|
res.writeHead(400);
|
|
res.end('Failed to unsubscribe this email address');
|
|
}
|
|
};
|
|
|
|
const updateMemberNewsletters = async function (req, res) {
|
|
try {
|
|
const memberUuid = req.query.uuid;
|
|
if (!memberUuid) {
|
|
res.writeHead(400);
|
|
return res.end('Invalid member uuid');
|
|
}
|
|
|
|
const data = _.pick(req.body, 'newsletters');
|
|
const memberData = await membersService.api.members.get({
|
|
uuid: memberUuid
|
|
});
|
|
if (!memberData) {
|
|
res.writeHead(404);
|
|
return res.end('Email address not found.');
|
|
}
|
|
|
|
const options = {
|
|
id: memberData.get('id'),
|
|
withRelated: ['newsletters']
|
|
};
|
|
|
|
const updatedMember = await membersService.api.members.update(data, options);
|
|
const updatedMemberData = _.pick(updatedMember.toJSON(), ['uuid', 'email', 'name', 'newsletters', 'status']);
|
|
res.json(updatedMemberData);
|
|
} catch (err) {
|
|
res.writeHead(400);
|
|
res.end('Failed to update newsletters');
|
|
}
|
|
};
|
|
|
|
const updateMemberData = async function (req, res) {
|
|
try {
|
|
const data = _.pick(req.body, 'name', 'subscribed', 'newsletters');
|
|
const member = await membersService.ssr.getMemberDataFromSession(req, res);
|
|
if (member) {
|
|
const options = {
|
|
id: member.id,
|
|
withRelated: ['stripeSubscriptions', 'stripeSubscriptions.customer', 'stripeSubscriptions.stripePrice', 'newsletters']
|
|
};
|
|
const updatedMember = await membersService.api.members.update(data, options);
|
|
|
|
res.json(formattedMemberResponse(updatedMember.toJSON()));
|
|
} else {
|
|
res.json(null);
|
|
}
|
|
} catch (err) {
|
|
res.writeHead(err.statusCode);
|
|
res.end(err.message);
|
|
}
|
|
};
|
|
|
|
const createSessionFromMagicLink = async function (req, res, next) {
|
|
if (!req.url.includes('token=')) {
|
|
return next();
|
|
}
|
|
|
|
// req.query is a plain object, copy it to a URLSearchParams object so we can call toString()
|
|
const searchParams = new URLSearchParams('');
|
|
Object.keys(req.query).forEach((param) => {
|
|
// don't copy the token param
|
|
if (param !== 'token') {
|
|
searchParams.set(param, req.query[param]);
|
|
}
|
|
});
|
|
|
|
try {
|
|
const member = await membersService.ssr.exchangeTokenForSession(req, res);
|
|
const subscriptions = member && member.subscriptions || [];
|
|
|
|
const action = req.query.action;
|
|
|
|
if (action === 'signup' || action === 'signup-paid' || action === 'subscribe') {
|
|
let customRedirect = '';
|
|
const mostRecentActiveSubscription = subscriptions
|
|
.sort((a, b) => {
|
|
const aStartDate = new Date(a.start_date);
|
|
const bStartDate = new Date(b.start_date);
|
|
return bStartDate.valueOf() - aStartDate.valueOf();
|
|
})
|
|
.find(sub => ['active', 'trialing'].includes(sub.status));
|
|
if (mostRecentActiveSubscription) {
|
|
customRedirect = mostRecentActiveSubscription.tier.welcome_page_url;
|
|
} else {
|
|
const freeTier = await models.Product.findOne({type: 'free'});
|
|
customRedirect = freeTier && freeTier.get('welcome_page_url') || '';
|
|
}
|
|
|
|
if (customRedirect && customRedirect !== '/') {
|
|
const baseUrl = urlUtils.getSiteUrl();
|
|
const ensureEndsWith = (string, endsWith) => (string.endsWith(endsWith) ? string : string + endsWith);
|
|
const removeLeadingSlash = string => string.replace(/^\//, '');
|
|
|
|
const redirectUrl = new URL(removeLeadingSlash(ensureEndsWith(customRedirect, '/')), ensureEndsWith(baseUrl, '/'));
|
|
|
|
return res.redirect(redirectUrl.href);
|
|
}
|
|
}
|
|
|
|
// Do a standard 302 redirect to the homepage, with success=true
|
|
searchParams.set('success', true);
|
|
res.redirect(`${urlUtils.getSubdir()}/?${searchParams.toString()}`);
|
|
} catch (err) {
|
|
logging.warn(err.message);
|
|
|
|
// Do a standard 302 redirect to the homepage, with success=false
|
|
searchParams.set('success', false);
|
|
res.redirect(`${urlUtils.getSubdir()}/?${searchParams.toString()}`);
|
|
}
|
|
};
|
|
|
|
// Set req.member & res.locals.member if a cookie is set
|
|
module.exports = {
|
|
loadMemberSession,
|
|
createSessionFromMagicLink,
|
|
getIdentityToken,
|
|
getMemberNewsletters,
|
|
getMemberData,
|
|
updateMemberData,
|
|
updateMemberNewsletters,
|
|
deleteSession
|
|
};
|