mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-23 02:41:50 +03:00
Improved webmention receiving E2E test reliability
refs https://github.com/TryGhost/Team/issues/2596
This commit is contained in:
parent
1b3d19ba81
commit
f45d1810a6
@ -56,7 +56,8 @@ module.exports = class RoutingService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await this.#externalRequest.head(url, {
|
const response = await this.#externalRequest.head(url, {
|
||||||
followRedirect: false
|
followRedirect: false,
|
||||||
|
throwHttpErrors: false
|
||||||
});
|
});
|
||||||
if (response.statusCode < 400 && response.statusCode > 199) {
|
if (response.statusCode < 400 && response.statusCode > 199) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -12,367 +12,38 @@ const nock = require('nock');
|
|||||||
const jobsService = require('../../../core/server/services/mentions-jobs');
|
const jobsService = require('../../../core/server/services/mentions-jobs');
|
||||||
const DomainEvents = require('@tryghost/domain-events');
|
const DomainEvents = require('@tryghost/domain-events');
|
||||||
|
|
||||||
|
async function allSettled() {
|
||||||
|
await jobsService.allSettled();
|
||||||
|
await DomainEvents.allSettled();
|
||||||
|
}
|
||||||
|
|
||||||
describe('Webmentions (receiving)', function () {
|
describe('Webmentions (receiving)', function () {
|
||||||
let agent;
|
let agent;
|
||||||
let emailMockReceiver;
|
let emailMockReceiver;
|
||||||
|
|
||||||
before(async function () {
|
before(async function () {
|
||||||
agent = await agentProvider.getWebmentionsAPIAgent();
|
agent = await agentProvider.getWebmentionsAPIAgent();
|
||||||
await fixtureManager.init('posts');
|
await fixtureManager.init('posts');
|
||||||
nock.disableNetConnect();
|
});
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
await allSettled();
|
||||||
|
mockManager.disableNetwork();
|
||||||
mockManager.mockLabsEnabled('webmentions');
|
mockManager.mockLabsEnabled('webmentions');
|
||||||
});
|
|
||||||
|
|
||||||
after(function () {
|
|
||||||
nock.enableNetConnect();
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(function () {
|
|
||||||
emailMockReceiver = mockManager.mockMail();
|
emailMockReceiver = mockManager.mockMail();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(async function () {
|
afterEach(async function () {
|
||||||
nock.cleanAll();
|
await allSettled();
|
||||||
await DomainEvents.allSettled();
|
|
||||||
mockManager.restore();
|
mockManager.restore();
|
||||||
await dbUtils.truncate('brute');
|
await dbUtils.truncate('brute');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can receive a webmention', async function () {
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article/');
|
|
||||||
const html = `
|
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
|
||||||
.head(targetUrl.pathname)
|
|
||||||
.reply(200);
|
|
||||||
|
|
||||||
nock(sourceUrl.origin)
|
|
||||||
.get(sourceUrl.pathname)
|
|
||||||
.reply(200, html, {'Content-Type': 'text/html'});
|
|
||||||
await agent.post('/receive')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href,
|
|
||||||
withExtension: true // test payload recorded
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
|
|
||||||
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article/'});
|
|
||||||
assert(mention);
|
|
||||||
assert.equal(mention.get('target'), urlUtils.getSiteUrl() + 'integrations/');
|
|
||||||
assert.ok(mention.get('resource_id'));
|
|
||||||
assert.equal(mention.get('resource_type'), 'post');
|
|
||||||
assert.equal(mention.get('source_title'), 'Test Page');
|
|
||||||
assert.equal(mention.get('source_excerpt'), 'Test description');
|
|
||||||
assert.equal(mention.get('source_author'), 'John Doe');
|
|
||||||
assert.equal(mention.get('payload'), JSON.stringify({
|
|
||||||
withExtension: true
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('will update a mentions source metadata', async function () {
|
|
||||||
const targetUrl = new URL(urlUtils.getSiteUrl());
|
|
||||||
const sourceUrl = new URL('http://testpage.com/update-mention-test-1/');
|
|
||||||
|
|
||||||
testCreatingTheMention: {
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
const html = `
|
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
|
||||||
.head(targetUrl.pathname)
|
|
||||||
.reply(200);
|
|
||||||
|
|
||||||
nock(sourceUrl.origin)
|
|
||||||
.get(sourceUrl.pathname)
|
|
||||||
.reply(200, html, {'Content-Type': 'text/html'});
|
|
||||||
|
|
||||||
await agent.post('/receive')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
|
|
||||||
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-1/'});
|
|
||||||
assert(mention);
|
|
||||||
assert.equal(mention.get('source_title'), 'Test Page');
|
|
||||||
assert.equal(mention.get('source_excerpt'), 'Test description');
|
|
||||||
assert.equal(mention.get('source_author'), 'John Doe');
|
|
||||||
|
|
||||||
break testCreatingTheMention;
|
|
||||||
}
|
|
||||||
|
|
||||||
testUpdatingTheMention: {
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
const html = `
|
|
||||||
<html><head><title>New Title</title><meta name="description" content="New Description"><meta name="author" content="big man with a beard"></head><body></body></html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
|
||||||
.head(targetUrl.pathname)
|
|
||||||
.reply(200);
|
|
||||||
|
|
||||||
nock(sourceUrl.origin)
|
|
||||||
.get(sourceUrl.pathname)
|
|
||||||
.reply(200, html, {'Content-Type': 'text/html'});
|
|
||||||
|
|
||||||
await agent.post('/receive')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
|
|
||||||
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-1/'});
|
|
||||||
assert(mention);
|
|
||||||
assert.equal(mention.get('source_title'), 'New Title');
|
|
||||||
assert.equal(mention.get('source_excerpt'), 'New Description');
|
|
||||||
assert.equal(mention.get('source_author'), 'big man with a beard');
|
|
||||||
|
|
||||||
break testUpdatingTheMention;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('will delete a mention when the target in Ghost was deleted', async function () {
|
|
||||||
const post = await models.Post.findOne({id: fixtureManager.get('posts', 0).id});
|
|
||||||
const targetUrl = new URL(urlUtils.getSiteUrl() + post.get('slug') + '/');
|
|
||||||
const sourceUrl = new URL('http://testpage.com/update-mention-test-2/');
|
|
||||||
const html = `
|
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
|
||||||
`;
|
|
||||||
nock(sourceUrl.origin)
|
|
||||||
.get(sourceUrl.pathname)
|
|
||||||
.reply(200, html, {'Content-Type': 'text/html'});
|
|
||||||
|
|
||||||
testCreatingTheMention: {
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
await agent.post('/receive')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
|
|
||||||
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-2/'});
|
|
||||||
assert(mention);
|
|
||||||
assert.equal(mention.get('resource_id'), post.id);
|
|
||||||
assert.equal(mention.get('source_title'), 'Test Page');
|
|
||||||
assert.equal(mention.get('source_excerpt'), 'Test description');
|
|
||||||
assert.equal(mention.get('source_author'), 'John Doe');
|
|
||||||
|
|
||||||
break testCreatingTheMention;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move post to draft and mark page as 404
|
|
||||||
await models.Post.edit({status: 'draft'}, {id: post.id});
|
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
|
||||||
.head(targetUrl.pathname)
|
|
||||||
.reply(404);
|
|
||||||
|
|
||||||
testUpdatingTheMention: {
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
|
|
||||||
await agent.post('/receive')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
|
|
||||||
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-2/'});
|
|
||||||
assert(mention);
|
|
||||||
|
|
||||||
// Check resource id was not cleared
|
|
||||||
assert.equal(mention.get('resource_id'), post.id);
|
|
||||||
|
|
||||||
// Check deleted
|
|
||||||
assert.equal(mention.get('deleted'), true);
|
|
||||||
|
|
||||||
break testUpdatingTheMention;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can receive a webmention to homepage', async function () {
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
const targetUrl = new URL(urlUtils.getSiteUrl());
|
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article-2/');
|
|
||||||
const html = `
|
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
|
||||||
.head(targetUrl.pathname)
|
|
||||||
.reply(200);
|
|
||||||
|
|
||||||
nock(sourceUrl.origin)
|
|
||||||
.get(sourceUrl.pathname)
|
|
||||||
.reply(200, html, {'Content-Type': 'text/html'});
|
|
||||||
|
|
||||||
await agent.post('/receive')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
|
|
||||||
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
|
|
||||||
assert(mention);
|
|
||||||
assert.equal(mention.get('target'), urlUtils.getSiteUrl());
|
|
||||||
assert.ok(!mention.get('resource_id'));
|
|
||||||
assert.equal(mention.get('resource_type'), null);
|
|
||||||
assert.equal(mention.get('source_title'), 'Test Page');
|
|
||||||
assert.equal(mention.get('source_excerpt'), 'Test description');
|
|
||||||
assert.equal(mention.get('source_author'), 'John Doe');
|
|
||||||
assert.equal(mention.get('payload'), JSON.stringify({}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can send an email notification for a new webmention', async function () {
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article-123-email-test/');
|
|
||||||
const html = `
|
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
|
||||||
.head(targetUrl.pathname)
|
|
||||||
.reply(200);
|
|
||||||
|
|
||||||
nock(sourceUrl.origin)
|
|
||||||
.get(sourceUrl.pathname)
|
|
||||||
.reply(200, html, {'Content-Type': 'text/html'});
|
|
||||||
|
|
||||||
await agent.post('/receive/')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
await DomainEvents.allSettled();
|
|
||||||
|
|
||||||
const users = await models.User.getEmailAlertUsers('mention-received');
|
|
||||||
for (const user of users) {
|
|
||||||
await mockManager.assert.sentEmail({
|
|
||||||
subject: /New mention from/,
|
|
||||||
to: user.email
|
|
||||||
});
|
|
||||||
}
|
|
||||||
emailMockReceiver.sentEmailCount(users.length);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can display post title in notification email', async function () {
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article-1234-email-test/');
|
|
||||||
const html = `
|
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
|
||||||
.head(targetUrl.pathname)
|
|
||||||
.reply(200);
|
|
||||||
|
|
||||||
nock(sourceUrl.origin)
|
|
||||||
.get(sourceUrl.pathname)
|
|
||||||
.reply(200, html, {'Content-Type': 'text/html'});
|
|
||||||
|
|
||||||
await agent.post('/receive/')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
await DomainEvents.allSettled();
|
|
||||||
|
|
||||||
emailMockReceiver.matchHTMLSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can display page title in notification email', async function () {
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
const targetUrl = new URL('about/', urlUtils.getSiteUrl());
|
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article-12345-email-test/');
|
|
||||||
const html = `
|
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
|
||||||
.head(targetUrl.pathname)
|
|
||||||
.reply(200);
|
|
||||||
|
|
||||||
nock(sourceUrl.origin)
|
|
||||||
.get(sourceUrl.pathname)
|
|
||||||
.reply(200, html, {'Content-Type': 'text/html'});
|
|
||||||
|
|
||||||
await agent.post('/receive/')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
await DomainEvents.allSettled();
|
|
||||||
|
|
||||||
emailMockReceiver.matchHTMLSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('does not send notification with flag disabled', async function () {
|
|
||||||
mockManager.mockLabsDisabled('webmentions');
|
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article-123-email-test/');
|
|
||||||
const html = `
|
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
|
||||||
`;
|
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
|
||||||
.head(targetUrl.pathname)
|
|
||||||
.reply(200);
|
|
||||||
|
|
||||||
nock(sourceUrl.origin)
|
|
||||||
.get(sourceUrl.pathname)
|
|
||||||
.reply(200, html, {'Content-Type': 'text/html'});
|
|
||||||
|
|
||||||
await agent.post('/receive/')
|
|
||||||
.body({
|
|
||||||
source: sourceUrl.href,
|
|
||||||
target: targetUrl.href
|
|
||||||
})
|
|
||||||
.expectStatus(202);
|
|
||||||
|
|
||||||
await processWebmentionJob;
|
|
||||||
await DomainEvents.allSettled();
|
|
||||||
|
|
||||||
emailMockReceiver.sentEmailCount(0);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('is rate limited against spamming mention requests', async function () {
|
it('is rate limited against spamming mention requests', async function () {
|
||||||
await dbUtils.truncate('brute');
|
await dbUtils.truncate('brute');
|
||||||
const webmentionBlock = configUtils.config.get('spam').webmentions_block;
|
const webmentionBlock = configUtils.config.get('spam').webmentions_block;
|
||||||
const targetUrl = new URL(urlUtils.getSiteUrl());
|
const targetUrl = new URL(urlUtils.getSiteUrl());
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article-2/');
|
const sourceUrl = new URL('http://testpage.com/external-article-brute-test/');
|
||||||
const html = `
|
const html = `
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
||||||
`;
|
`;
|
||||||
@ -408,16 +79,59 @@ describe('Webmentions (receiving)', function () {
|
|||||||
payload: {}
|
payload: {}
|
||||||
})
|
})
|
||||||
.expectStatus(429);
|
.expectStatus(429);
|
||||||
|
await allSettled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can verify a webmention <a> link', async function () {
|
it('can receive a webmention', async function () {
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
||||||
const targetUrl = new URL(urlUtils.getSiteUrl());
|
const sourceUrl = new URL('http://testpage.com/external-article/');
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article-2/');
|
|
||||||
const html = `
|
const html = `
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body><a href="${urlUtils.getSiteUrl()}">your cool website mentioned</a></body></html>
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
nock(targetUrl.origin)
|
nock(targetUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
await agent.post('/receive')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href,
|
||||||
|
withExtension: true // test payload recorded
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article/'});
|
||||||
|
assert(mention);
|
||||||
|
assert.equal(mention.get('target'), urlUtils.getSiteUrl() + 'integrations/');
|
||||||
|
assert.ok(mention.get('resource_id'));
|
||||||
|
assert.equal(mention.get('resource_type'), 'post');
|
||||||
|
assert.equal(mention.get('source_title'), 'Test Page');
|
||||||
|
assert.equal(mention.get('source_excerpt'), 'Test description');
|
||||||
|
assert.equal(mention.get('source_author'), 'John Doe');
|
||||||
|
assert.equal(mention.get('payload'), JSON.stringify({
|
||||||
|
withExtension: true
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will update a mentions source metadata', async function () {
|
||||||
|
const targetUrl = new URL(urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/update-mention-test-1/');
|
||||||
|
|
||||||
|
testCreatingTheMention: {
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
nock(targetUrl.origin)
|
||||||
|
.persist()
|
||||||
.head(targetUrl.pathname)
|
.head(targetUrl.pathname)
|
||||||
.reply(200);
|
.reply(200);
|
||||||
|
|
||||||
@ -433,7 +147,293 @@ describe('Webmentions (receiving)', function () {
|
|||||||
})
|
})
|
||||||
.expectStatus(202);
|
.expectStatus(202);
|
||||||
|
|
||||||
await processWebmentionJob;
|
await allSettled();
|
||||||
|
|
||||||
|
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-1/'});
|
||||||
|
assert(mention);
|
||||||
|
assert.equal(mention.get('source_title'), 'Test Page');
|
||||||
|
assert.equal(mention.get('source_excerpt'), 'Test description');
|
||||||
|
assert.equal(mention.get('source_author'), 'John Doe');
|
||||||
|
|
||||||
|
break testCreatingTheMention;
|
||||||
|
}
|
||||||
|
|
||||||
|
nock.cleanAll();
|
||||||
|
|
||||||
|
testUpdatingTheMention: {
|
||||||
|
const html = `
|
||||||
|
<html><head><title>New Title</title><meta name="description" content="New Description"><meta name="author" content="big man with a beard"></head><body></body></html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
nock(targetUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-1/'});
|
||||||
|
assert(mention);
|
||||||
|
assert.equal(mention.get('source_title'), 'New Title');
|
||||||
|
assert.equal(mention.get('source_excerpt'), 'New Description');
|
||||||
|
assert.equal(mention.get('source_author'), 'big man with a beard');
|
||||||
|
|
||||||
|
break testUpdatingTheMention;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('will delete a mention when the target in Ghost was deleted', async function () {
|
||||||
|
const post = await models.Post.findOne({id: fixtureManager.get('posts', 0).id});
|
||||||
|
const targetUrl = new URL(urlUtils.getSiteUrl() + post.get('slug') + '/');
|
||||||
|
const sourceUrl = new URL('http://testpage.com/update-mention-test-2/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
testCreatingTheMention: {
|
||||||
|
await agent.post('/receive')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-2/'});
|
||||||
|
assert(mention);
|
||||||
|
assert.equal(mention.get('resource_id'), post.id);
|
||||||
|
assert.equal(mention.get('source_title'), 'Test Page');
|
||||||
|
assert.equal(mention.get('source_excerpt'), 'Test description');
|
||||||
|
assert.equal(mention.get('source_author'), 'John Doe');
|
||||||
|
|
||||||
|
break testCreatingTheMention;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move post to draft and mark page as 404
|
||||||
|
await models.Post.edit({status: 'draft'}, {id: post.id});
|
||||||
|
|
||||||
|
nock(targetUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(404);
|
||||||
|
|
||||||
|
testUpdatingTheMention: {
|
||||||
|
await agent.post('/receive')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
const mention = await models.Mention.findOne({source: 'http://testpage.com/update-mention-test-2/'});
|
||||||
|
assert(mention);
|
||||||
|
|
||||||
|
// Check resource id was not cleared
|
||||||
|
assert.equal(mention.get('resource_id'), post.id);
|
||||||
|
|
||||||
|
// Check deleted
|
||||||
|
assert.equal(mention.get('deleted'), true);
|
||||||
|
|
||||||
|
break testUpdatingTheMention;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can receive a webmention to homepage', async function () {
|
||||||
|
const targetUrl = new URL(urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/external-article-2/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
nock(targetUrl.origin)
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
|
||||||
|
assert(mention);
|
||||||
|
assert.equal(mention.get('target'), urlUtils.getSiteUrl());
|
||||||
|
assert.ok(!mention.get('resource_id'));
|
||||||
|
assert.equal(mention.get('resource_type'), null);
|
||||||
|
assert.equal(mention.get('source_title'), 'Test Page');
|
||||||
|
assert.equal(mention.get('source_excerpt'), 'Test description');
|
||||||
|
assert.equal(mention.get('source_author'), 'John Doe');
|
||||||
|
assert.equal(mention.get('payload'), JSON.stringify({}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can send an email notification for a new webmention', async function () {
|
||||||
|
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/external-article-123-email-test/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
nock(targetUrl.origin)
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive/')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
const users = await models.User.getEmailAlertUsers('mention-received');
|
||||||
|
for (const user of users) {
|
||||||
|
await mockManager.assert.sentEmail({
|
||||||
|
subject: /New mention from/,
|
||||||
|
to: user.email
|
||||||
|
});
|
||||||
|
}
|
||||||
|
emailMockReceiver.sentEmailCount(users.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can display post title in notification email', async function () {
|
||||||
|
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/external-article-1234-email-test/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
nock(targetUrl.origin).persist()
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin).persist()
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive/')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
emailMockReceiver.matchHTMLSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can display page title in notification email', async function () {
|
||||||
|
const targetUrl = new URL('about/', urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/external-article-12345-email-test/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
nock(targetUrl.origin).persist()
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin).persist()
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive/')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
emailMockReceiver.matchHTMLSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not send notification with flag disabled', async function () {
|
||||||
|
mockManager.mockLabsDisabled('webmentions');
|
||||||
|
|
||||||
|
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/external-article-123-email-test/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body></body></html>
|
||||||
|
`;
|
||||||
|
|
||||||
|
nock(targetUrl.origin)
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive/')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
emailMockReceiver.sentEmailCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can verify a webmention <a> link', async function () {
|
||||||
|
const targetUrl = new URL(urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/external-article-2/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body><a href="${urlUtils.getSiteUrl()}">your cool website mentioned</a></body></html>
|
||||||
|
`;
|
||||||
|
nock(targetUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
|
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
|
||||||
|
|
||||||
@ -441,14 +441,14 @@ describe('Webmentions (receiving)', function () {
|
|||||||
assert.equal(mention.get('verified'), true);
|
assert.equal(mention.get('verified'), true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('can verifiy a webmention <img> link', async function () {
|
it('can verify a webmention <a> link to post', async function () {
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
||||||
const targetUrl = new URL(urlUtils.getSiteUrl());
|
const sourceUrl = new URL('http://testpage.com/external-article-3/');
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article-2/');
|
|
||||||
const html = `
|
const html = `
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body><img src="${urlUtils.getSiteUrl()}"></body></html>
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body><a href="${targetUrl.toString()}">your cool website mentioned</a></body></html>
|
||||||
`;
|
`;
|
||||||
nock(targetUrl.origin)
|
nock(targetUrl.origin)
|
||||||
|
.persist()
|
||||||
.head(targetUrl.pathname)
|
.head(targetUrl.pathname)
|
||||||
.reply(200);
|
.reply(200);
|
||||||
|
|
||||||
@ -464,7 +464,98 @@ describe('Webmentions (receiving)', function () {
|
|||||||
})
|
})
|
||||||
.expectStatus(202);
|
.expectStatus(202);
|
||||||
|
|
||||||
await processWebmentionJob;
|
await allSettled();
|
||||||
|
|
||||||
|
const mention = await models.Mention.findOne({source: sourceUrl.href});
|
||||||
|
|
||||||
|
assert(mention);
|
||||||
|
assert.equal(mention.get('verified'), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can verify a webmention <a> link to post with tracking parameters', async function () {
|
||||||
|
const targetUrl = new URL('integrations/', urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/external-article-4/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body><a href="${targetUrl.toString()}?ref=1234-working">your cool website mentioned</a></body></html>
|
||||||
|
`;
|
||||||
|
nock(targetUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
const mention = await models.Mention.findOne({source: sourceUrl.href});
|
||||||
|
|
||||||
|
assert(mention);
|
||||||
|
assert.equal(mention.get('verified'), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('marks as unverified if url not present on source', async function () {
|
||||||
|
const targetUrl = new URL('html-ipsum', urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/external-article-not-present/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body><a href="${urlUtils.getSiteUrl()}">your cool website mentioned</a></body></html>
|
||||||
|
`;
|
||||||
|
nock(targetUrl.origin).persist()
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
|
const mention = await models.Mention.findOne({source: sourceUrl.toString()});
|
||||||
|
|
||||||
|
assert(mention);
|
||||||
|
assert.equal(mention.get('verified'), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can verifiy a webmention <img> link', async function () {
|
||||||
|
const targetUrl = new URL(urlUtils.getSiteUrl());
|
||||||
|
const sourceUrl = new URL('http://testpage.com/external-article-2/');
|
||||||
|
const html = `
|
||||||
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body><img src="${urlUtils.getSiteUrl()}"></body></html>
|
||||||
|
`;
|
||||||
|
nock(targetUrl.origin).persist()
|
||||||
|
.head(targetUrl.pathname)
|
||||||
|
.reply(200);
|
||||||
|
|
||||||
|
nock(sourceUrl.origin)
|
||||||
|
.persist()
|
||||||
|
.get(sourceUrl.pathname)
|
||||||
|
.reply(200, html, {'Content-Type': 'text/html'});
|
||||||
|
|
||||||
|
await agent.post('/receive')
|
||||||
|
.body({
|
||||||
|
source: sourceUrl.href,
|
||||||
|
target: targetUrl.href
|
||||||
|
})
|
||||||
|
.expectStatus(202);
|
||||||
|
|
||||||
|
await allSettled();
|
||||||
|
|
||||||
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
|
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
|
||||||
|
|
||||||
@ -473,13 +564,12 @@ describe('Webmentions (receiving)', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('can verify a webmention <video> link', async function () {
|
it('can verify a webmention <video> link', async function () {
|
||||||
const processWebmentionJob = jobsService.awaitCompletion('processWebmention');
|
|
||||||
const targetUrl = new URL(urlUtils.getSiteUrl());
|
const targetUrl = new URL(urlUtils.getSiteUrl());
|
||||||
const sourceUrl = new URL('http://testpage.com/external-article-2/');
|
const sourceUrl = new URL('http://testpage.com/external-article-2/');
|
||||||
const html = `
|
const html = `
|
||||||
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body><video src="${urlUtils.getSiteUrl()}"></body></html>
|
<html><head><title>Test Page</title><meta name="description" content="Test description"><meta name="author" content="John Doe"></head><body><video src="${urlUtils.getSiteUrl()}"></body></html>
|
||||||
`;
|
`;
|
||||||
nock(targetUrl.origin)
|
nock(targetUrl.origin).persist()
|
||||||
.head(targetUrl.pathname)
|
.head(targetUrl.pathname)
|
||||||
.reply(200);
|
.reply(200);
|
||||||
|
|
||||||
@ -495,7 +585,7 @@ describe('Webmentions (receiving)', function () {
|
|||||||
})
|
})
|
||||||
.expectStatus(202);
|
.expectStatus(202);
|
||||||
|
|
||||||
await processWebmentionJob;
|
await allSettled();
|
||||||
|
|
||||||
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
|
const mention = await models.Mention.findOne({source: 'http://testpage.com/external-article-2/'});
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ const originalMailServiceSend = mailService.GhostMailer.prototype.send;
|
|||||||
const labs = require('../../core/shared/labs');
|
const labs = require('../../core/shared/labs');
|
||||||
const events = require('../../core/server/lib/common/events');
|
const events = require('../../core/server/lib/common/events');
|
||||||
const settingsCache = require('../../core/shared/settings-cache');
|
const settingsCache = require('../../core/shared/settings-cache');
|
||||||
|
const dnsPromises = require('dns').promises;
|
||||||
|
|
||||||
let fakedLabsFlags = {};
|
let fakedLabsFlags = {};
|
||||||
const originalLabsIsSet = labs.isSet;
|
const originalLabsIsSet = labs.isSet;
|
||||||
@ -38,6 +39,15 @@ const mockStripe = () => {
|
|||||||
nock.disableNetConnect();
|
nock.disableNetConnect();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const disableNetwork = () => {
|
||||||
|
nock.disableNetConnect();
|
||||||
|
|
||||||
|
// externalRequest does dns lookup; stub to make sure we don't fail with fake domain names
|
||||||
|
sinon.stub(dnsPromises, 'lookup').callsFake(() => {
|
||||||
|
return Promise.resolve({address: '123.123.123.123', family: 4});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Email Mocks & Assertions
|
* Email Mocks & Assertions
|
||||||
*/
|
*/
|
||||||
@ -211,6 +221,7 @@ module.exports = {
|
|||||||
mockLabsDisabled,
|
mockLabsDisabled,
|
||||||
mockWebhookRequests,
|
mockWebhookRequests,
|
||||||
mockSetting,
|
mockSetting,
|
||||||
|
disableNetwork,
|
||||||
restore,
|
restore,
|
||||||
assert: {
|
assert: {
|
||||||
sentEmailCount,
|
sentEmailCount,
|
||||||
|
@ -127,6 +127,16 @@ class JobManager {
|
|||||||
// Clear the listeners
|
// Clear the listeners
|
||||||
this.#completionPromises.delete(name);
|
this.#completionPromises.delete(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.queue.length() <= 1) {
|
||||||
|
if (this.#completionPromises.has('all')) {
|
||||||
|
for (const listeners of this.#completionPromises.get('all')) {
|
||||||
|
listeners.resolve();
|
||||||
|
}
|
||||||
|
// Clear the listeners
|
||||||
|
this.#completionPromises.delete('all');
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (typeof message === 'object' && this.#domainEvents) {
|
if (typeof message === 'object' && this.#domainEvents) {
|
||||||
// Is this an event?
|
// Is this an event?
|
||||||
@ -157,6 +167,16 @@ class JobManager {
|
|||||||
// Clear the listeners
|
// Clear the listeners
|
||||||
this.#completionPromises.delete(jobMeta.name);
|
this.#completionPromises.delete(jobMeta.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.queue.length() <= 1) {
|
||||||
|
if (this.#completionPromises.has('all')) {
|
||||||
|
for (const listeners of this.#completionPromises.get('all')) {
|
||||||
|
listeners.reject(error);
|
||||||
|
}
|
||||||
|
// Clear the listeners
|
||||||
|
this.#completionPromises.delete('all');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -339,6 +359,25 @@ class JobManager {
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for all inline jobs to be completed.
|
||||||
|
*/
|
||||||
|
async allSettled() {
|
||||||
|
const name = 'all';
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (this.queue.idle()) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#completionPromises.set(name, [
|
||||||
|
...(this.#completionPromises.get(name) ?? []),
|
||||||
|
{resolve, reject}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes an "offloaded" job from scheduled jobs queue.
|
* Removes an "offloaded" job from scheduled jobs queue.
|
||||||
* It's NOT yet possible to remove "inline" jobs (will be possible when scheduling is added https://github.com/breejs/bree/issues/68).
|
* It's NOT yet possible to remove "inline" jobs (will be possible when scheduling is added https://github.com/breejs/bree/issues/68).
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const errors = require('@tryghost/errors');
|
const errors = require('@tryghost/errors');
|
||||||
|
const logging = require('@tryghost/logging');
|
||||||
const Mention = require('./Mention');
|
const Mention = require('./Mention');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -199,7 +200,11 @@ module.exports = class MentionsAPI {
|
|||||||
|
|
||||||
const responseBody = await this.#webmentionRequest.fetch(webmention.source);
|
const responseBody = await this.#webmentionRequest.fetch(webmention.source);
|
||||||
if (responseBody?.html) {
|
if (responseBody?.html) {
|
||||||
|
try {
|
||||||
mention.verify(responseBody.html);
|
mention.verify(responseBody.html);
|
||||||
|
} catch (e) {
|
||||||
|
logging.error(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.#repository.save(mention);
|
await this.#repository.save(mention);
|
||||||
|
@ -6,6 +6,7 @@ const externalRequest = require('../../core/core/server/lib/request-external.js'
|
|||||||
const sinon = require('sinon');
|
const sinon = require('sinon');
|
||||||
const logging = require('@tryghost/logging');
|
const logging = require('@tryghost/logging');
|
||||||
const {createModel} = require('./utils/index.js');
|
const {createModel} = require('./utils/index.js');
|
||||||
|
const dnsPromises = require('dns').promises;
|
||||||
|
|
||||||
// mock up job service
|
// mock up job service
|
||||||
let jobService = {
|
let jobService = {
|
||||||
@ -21,6 +22,11 @@ describe('MentionSendingService', function () {
|
|||||||
nock.disableNetConnect();
|
nock.disableNetConnect();
|
||||||
sinon.stub(logging, 'info');
|
sinon.stub(logging, 'info');
|
||||||
errorLogStub = sinon.stub(logging, 'error');
|
errorLogStub = sinon.stub(logging, 'error');
|
||||||
|
|
||||||
|
// externalRequest does dns lookup; stub to make sure we don't fail with fake domain names
|
||||||
|
sinon.stub(dnsPromises, 'lookup').callsFake(function () {
|
||||||
|
return Promise.resolve({address: '123.123.123.123', family: 4});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function () {
|
afterEach(function () {
|
||||||
|
Loading…
Reference in New Issue
Block a user