diff --git a/src/topics/create.js b/src/topics/create.js index c96dadbd4b..d2b709333c 100644 --- a/src/topics/create.js +++ b/src/topics/create.js @@ -259,14 +259,14 @@ module.exports = function (Topics) { return postData; }; - async function onNewPost({ pid, tid, uid: postOwner }, { uid, handle }) { + async function onNewPost({ pid, tid, content, uid: postOwner }, { uid, handle }) { const [[postData], [userInfo]] = await Promise.all([ posts.getPostSummaryByPids([pid], uid, { extraFields: ['attachments'] }), posts.getUserInfoForPosts([postOwner], uid), ]); await Promise.all([ Topics.addParentPosts([postData], uid), - Topics.syncBacklinks(postData), + Topics.syncBacklinks({ ...postData, content }), Topics.markAsRead([tid], uid), ]); if (utils.isNumber(postOwner) && postData.category.cid === -1) { diff --git a/src/topics/posts.js b/src/topics/posts.js index 535d53ff1d..6b4473f361 100644 --- a/src/topics/posts.js +++ b/src/topics/posts.js @@ -14,7 +14,7 @@ const plugins = require('../plugins'); const utils = require('../utils'); const privileges = require('../privileges'); -const backlinkRegex = new RegExp(`(?:${nconf.get('url').replace('/', '\\/')}|\b|\\s)\\/topic\\/(\\d+)(?:\\/\\w+)?`, 'g'); +const backlinkRegex = new RegExp(`(?:${nconf.get('url').replace('/', '\\/')}|\b|\\s)\\/topic\\/([a-fA-F0-9-]+)(?=\\/|$|\\s)?`, 'g'); module.exports = function (Topics) { Topics.onNewPostMade = async function (postData) { @@ -447,29 +447,27 @@ module.exports = function (Topics) { throw new Error('[[error:invalid-data]]'); } - - let { content } = postData; + let { pid, uid, content } = postData; // ignore lines that start with `>` content = (content || '').split('\n').filter(line => !line.trim().startsWith('>')).join('\n'); // Scan post content for topic links const matches = [...content.matchAll(backlinkRegex)]; - if (!matches) { - return 0; - } - const { pid, uid, tid } = postData; - let add = _.uniq(matches.map(match => match[1]).map(tid => parseInt(tid, 10))); + let add = _.uniq(matches.map(match => match[1])); - const now = Date.now(); - const topicsExist = await Topics.exists(add); - const current = (await db.getSortedSetMembers(`pid:${pid}:backlinks`)).map(tid => parseInt(tid, 10)); + const [topicsExist, current] = await Promise.all([ + Topics.exists(add), + db.getSortedSetMembers(`pid:${pid}:backlinks`), + ]); const remove = current.filter(tid => !add.includes(tid)); - add = add.filter((_tid, idx) => topicsExist[idx] && !current.includes(_tid) && tid !== _tid); + const postTid = String(postData.tid); + add = add.filter((_tid, idx) => topicsExist[idx] && !current.includes(_tid) && postTid !== _tid); // Remove old backlinks await db.sortedSetRemove(`pid:${pid}:backlinks`, remove); // Add new backlinks + const now = Date.now(); await db.sortedSetAdd(`pid:${pid}:backlinks`, add.map(() => now), add); await Promise.all(add.map(async (tid) => { await Topics.events.log(tid, { @@ -479,6 +477,6 @@ module.exports = function (Topics) { }); })); - return add.length + (current - remove); + return add.length + (current.length - remove.length); }; }; diff --git a/test/posts.js b/test/posts.js index 9ca3809fa8..83f4fca899 100644 --- a/test/posts.js +++ b/test/posts.js @@ -1152,12 +1152,10 @@ describe('Post\'s', () => { describe('.syncBacklinks()', () => { it('should error on invalid data', async () => { - try { - await topics.syncBacklinks(); - } catch (e) { - assert(e); - assert.strictEqual(e.message, '[[error:invalid-data]]'); - } + await assert.rejects( + topics.syncBacklinks(), + { message: '[[error:invalid-data]]' }, + ); }); it('should do nothing if the post does not contain a link to a topic', async () => { @@ -1192,9 +1190,7 @@ describe('Post\'s', () => { const backlinks = await db.getSortedSetMembers('pid:2:backlinks'); assert.strictEqual(count, 0); - assert(events); assert.strictEqual(events.length, 1); - assert(backlinks); assert.strictEqual(backlinks.length, 0); }); @@ -1219,6 +1215,17 @@ describe('Post\'s', () => { assert(backlinks); assert.strictEqual(backlinks.length, 0); }); + + it('should not create a wrong backlink to topic/1 with AP topic url', async () => { + const { postData } = await topics.post({ + uid: 1, + cid, + title: 'Topic backlink testing - topic 2', + content: `testing ${nconf.get('url')}/topic/1aef954c-d0dc-45cf-acf2-e3a59f6cc134/foo`, + }); + const backlinks = await db.getSortedSetMembers(`pid:${postData.pid}:backlinks`); + assert.strictEqual(backlinks.length, 0); + }); }); describe('integration tests', () => {