2023-01-04 16:30:35 +03:00
|
|
|
const {agentProvider, mockManager, fixtureManager, matchers} = require('../../utils/e2e-framework');
|
2022-08-18 18:38:42 +03:00
|
|
|
const should = require('should');
|
2022-10-05 13:42:42 +03:00
|
|
|
const settingsCache = require('../../../core/shared/settings-cache');
|
2023-01-04 16:30:35 +03:00
|
|
|
const DomainEvents = require('@tryghost/domain-events');
|
2022-10-05 13:42:42 +03:00
|
|
|
const {anyErrorId} = matchers;
|
2022-08-18 18:38:42 +03:00
|
|
|
|
|
|
|
let membersAgent, membersService;
|
|
|
|
|
|
|
|
describe('sendMagicLink', function () {
|
|
|
|
before(async function () {
|
|
|
|
const agents = await agentProvider.getAgentsForMembers();
|
|
|
|
membersAgent = agents.membersAgent;
|
|
|
|
|
|
|
|
membersService = require('../../../core/server/services/members');
|
|
|
|
|
|
|
|
await fixtureManager.init('members');
|
|
|
|
});
|
|
|
|
|
|
|
|
beforeEach(function () {
|
|
|
|
mockManager.mockMail();
|
2022-10-05 13:42:42 +03:00
|
|
|
|
|
|
|
// Reset settings
|
|
|
|
settingsCache.set('members_signup_access', {value: 'all'});
|
2022-08-18 18:38:42 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(function () {
|
|
|
|
mockManager.restore();
|
|
|
|
});
|
|
|
|
|
2022-10-04 19:17:26 +03:00
|
|
|
it('Errors when passed multiple emails', async function () {
|
|
|
|
await membersAgent.post('/api/send-magic-link')
|
|
|
|
.body({
|
|
|
|
email: 'one@test.com,two@test.com',
|
|
|
|
emailType: 'signup'
|
|
|
|
})
|
|
|
|
.expectStatus(400);
|
|
|
|
});
|
2022-10-05 14:33:12 +03:00
|
|
|
|
2022-10-05 13:42:42 +03:00
|
|
|
it('Throws an error when logging in to a email that does not exist', async function () {
|
|
|
|
const email = 'this-member-does-not-exist@test.com';
|
|
|
|
await membersAgent.post('/api/send-magic-link')
|
|
|
|
.body({
|
|
|
|
email,
|
|
|
|
emailType: 'signin'
|
|
|
|
})
|
|
|
|
.expectStatus(400)
|
|
|
|
.matchBodySnapshot({
|
|
|
|
errors: [{
|
|
|
|
id: anyErrorId,
|
|
|
|
// Add this here because it is easy to be overlooked (we need a human readable error!)
|
|
|
|
// 'Please sign up first' should be included only when invite only is disabled.
|
|
|
|
message: 'No member exists with this e-mail address. Please sign up first.'
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Throws an error when logging in to a email that does not exist (invite only)', async function () {
|
|
|
|
settingsCache.set('members_signup_access', {value: 'invite'});
|
|
|
|
|
|
|
|
const email = 'this-member-does-not-exist@test.com';
|
|
|
|
await membersAgent.post('/api/send-magic-link')
|
|
|
|
.body({
|
|
|
|
email,
|
|
|
|
emailType: 'signin'
|
|
|
|
})
|
|
|
|
.expectStatus(400)
|
|
|
|
.matchBodySnapshot({
|
|
|
|
errors: [{
|
|
|
|
id: anyErrorId,
|
|
|
|
// Add this here because it is easy to be overlooked (we need a human readable error!)
|
|
|
|
// 'Please sign up first' should NOT be included
|
|
|
|
message: 'No member exists with this e-mail address.'
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Throws an error when trying to sign up on an invite only site', async function () {
|
|
|
|
settingsCache.set('members_signup_access', {value: 'invite'});
|
|
|
|
|
|
|
|
const email = 'this-member-does-not-exist@test.com';
|
|
|
|
await membersAgent.post('/api/send-magic-link')
|
|
|
|
.body({
|
|
|
|
email,
|
|
|
|
emailType: 'signup'
|
|
|
|
})
|
|
|
|
.expectStatus(400)
|
|
|
|
.matchBodySnapshot({
|
|
|
|
errors: [{
|
|
|
|
id: anyErrorId
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-08-18 18:38:42 +03:00
|
|
|
it('Creates a valid magic link with tokenData, and without urlHistory', async function () {
|
|
|
|
const email = 'newly-created-user-magic-link-test@test.com';
|
|
|
|
await membersAgent.post('/api/send-magic-link')
|
|
|
|
.body({
|
|
|
|
email,
|
|
|
|
emailType: 'signup'
|
|
|
|
})
|
|
|
|
.expectEmptyBody()
|
|
|
|
.expectStatus(201);
|
|
|
|
|
|
|
|
// Check email is sent
|
|
|
|
const mail = mockManager.assert.sentEmail({
|
|
|
|
to: email,
|
|
|
|
subject: /Complete your sign up to Ghost!/
|
|
|
|
});
|
|
|
|
|
|
|
|
// Get link from email
|
|
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
|
|
const parsed = new URL(url);
|
|
|
|
const token = parsed.searchParams.get('token');
|
|
|
|
|
|
|
|
// Get data
|
|
|
|
const data = await membersService.api.getTokenDataFromMagicLinkToken(token);
|
2022-08-25 10:28:26 +03:00
|
|
|
|
2022-08-18 18:38:42 +03:00
|
|
|
should(data).match({
|
|
|
|
email,
|
|
|
|
attribution: {
|
|
|
|
id: null,
|
|
|
|
url: null,
|
|
|
|
type: null
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-09-06 15:36:06 +03:00
|
|
|
it('Creates a valid magic link from custom signup with redirection', async function () {
|
|
|
|
const customSignupUrl = 'http://localhost:2368/custom-signup-form-page';
|
|
|
|
const email = 'newly-created-user-magic-link-test@test.com';
|
|
|
|
await membersAgent
|
|
|
|
.post('/api/send-magic-link')
|
|
|
|
.header('Referer', customSignupUrl)
|
|
|
|
.body({
|
|
|
|
email,
|
|
|
|
emailType: 'signup',
|
|
|
|
autoRedirect: true
|
|
|
|
})
|
|
|
|
.expectEmptyBody()
|
|
|
|
.expectStatus(201);
|
|
|
|
|
|
|
|
const mail = await mockManager.assert.sentEmail({
|
|
|
|
to: email,
|
|
|
|
subject: /Complete your sign up to Ghost!/
|
|
|
|
});
|
|
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
|
|
const parsed = new URL(url);
|
|
|
|
const redirect = parsed.searchParams.get('r');
|
|
|
|
should(redirect).equal(customSignupUrl);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('Creates a valid magic link from custom signup with redirection disabled', async function () {
|
|
|
|
const customSignupUrl = 'http://localhost:2368/custom-signup-form-page';
|
|
|
|
const email = 'newly-created-user-magic-link-test@test.com';
|
|
|
|
await membersAgent
|
|
|
|
.post('/api/send-magic-link')
|
|
|
|
.header('Referer', customSignupUrl)
|
|
|
|
.body({
|
|
|
|
email,
|
|
|
|
emailType: 'signup',
|
|
|
|
autoRedirect: false
|
|
|
|
})
|
|
|
|
.expectEmptyBody()
|
|
|
|
.expectStatus(201);
|
|
|
|
|
|
|
|
const mail = await mockManager.assert.sentEmail({
|
|
|
|
to: email,
|
|
|
|
subject: /Complete your sign up to Ghost!/
|
|
|
|
});
|
|
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
|
|
const parsed = new URL(url);
|
|
|
|
const redirect = parsed.searchParams.get('r');
|
|
|
|
should(redirect).equal(null);
|
|
|
|
});
|
|
|
|
|
2022-08-25 10:28:26 +03:00
|
|
|
it('triggers email alert for free member signup', async function () {
|
|
|
|
const email = 'newly-created-user-magic-link-test@test.com';
|
|
|
|
await membersAgent.post('/api/send-magic-link')
|
|
|
|
.body({
|
|
|
|
email,
|
|
|
|
emailType: 'signup'
|
|
|
|
})
|
|
|
|
.expectEmptyBody()
|
|
|
|
.expectStatus(201);
|
|
|
|
|
|
|
|
// Check email is sent
|
|
|
|
const mail = mockManager.assert.sentEmail({
|
|
|
|
to: email,
|
|
|
|
subject: /Complete your sign up to Ghost!/
|
|
|
|
});
|
|
|
|
|
|
|
|
// Get link from email
|
|
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
|
|
const parsed = new URL(url);
|
|
|
|
const token = parsed.searchParams.get('token');
|
|
|
|
|
|
|
|
// Get member data from token
|
|
|
|
const data = await membersService.api.getMemberDataFromMagicLinkToken(token);
|
|
|
|
|
2022-09-09 17:29:06 +03:00
|
|
|
// Wait for the dispatched events (because this happens async)
|
2023-01-04 16:30:35 +03:00
|
|
|
await DomainEvents.allSettled();
|
2022-08-25 10:28:26 +03:00
|
|
|
// Check member alert is sent to site owners
|
|
|
|
mockManager.assert.sentEmail({
|
|
|
|
to: 'jbloggs@example.com',
|
|
|
|
subject: /🥳 Free member signup: newly-created-user-magic-link-test@test.com/
|
|
|
|
});
|
|
|
|
|
|
|
|
// Check member data is returned
|
|
|
|
should(data).match({
|
|
|
|
email
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-08-18 18:38:42 +03:00
|
|
|
it('Converts the urlHistory to the attribution and stores it in the token', async function () {
|
|
|
|
const email = 'newly-created-user-magic-link-test-2@test.com';
|
|
|
|
await membersAgent.post('/api/send-magic-link')
|
|
|
|
.body({
|
|
|
|
email,
|
|
|
|
emailType: 'signup',
|
|
|
|
urlHistory: [
|
|
|
|
{
|
|
|
|
path: '/test-path',
|
2022-08-25 19:21:41 +03:00
|
|
|
time: Date.now()
|
2022-08-18 18:38:42 +03:00
|
|
|
}
|
|
|
|
]
|
|
|
|
})
|
|
|
|
.expectEmptyBody()
|
|
|
|
.expectStatus(201);
|
|
|
|
|
|
|
|
// Check email is sent
|
|
|
|
const mail = mockManager.assert.sentEmail({
|
|
|
|
to: email,
|
|
|
|
subject: /Complete your sign up to Ghost!/
|
|
|
|
});
|
|
|
|
|
|
|
|
// Get link from email
|
|
|
|
const [url] = mail.text.match(/https?:\/\/[^\s]+/);
|
|
|
|
const parsed = new URL(url);
|
|
|
|
const token = parsed.searchParams.get('token');
|
|
|
|
|
|
|
|
// Get data
|
|
|
|
const data = await membersService.api.getTokenDataFromMagicLinkToken(token);
|
2022-08-25 10:28:26 +03:00
|
|
|
|
2022-08-18 18:38:42 +03:00
|
|
|
should(data).match({
|
|
|
|
email,
|
|
|
|
attribution: {
|
|
|
|
id: null,
|
|
|
|
url: '/test-path',
|
|
|
|
type: 'url'
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|