diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts index d1b331346..2fa320cd7 100644 --- a/server/lib/notifier.ts +++ b/server/lib/notifier.ts @@ -148,6 +148,8 @@ class Notifier { private async notifyOfCommentMention (comment: VideoCommentModel) { const usernames = comment.extractMentions() + logger.debug('Extracted %d username from comment %s.', usernames.length, comment.url, { usernames, text: comment.text }) + let users = await UserModel.listByUsernames(usernames) if (comment.Video.isOwned()) { diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index cf6278da7..1163f9a0e 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts @@ -466,31 +466,41 @@ export class VideoCommentModel extends Model { } extractMentions () { - if (!this.text) return [] + let result: string[] = [] const localMention = `@(${actorNameAlphabet}+)` const remoteMention = `${localMention}@${CONFIG.WEBSERVER.HOST}` + const mentionRegex = this.isOwned() + ? '(?:(?:' + remoteMention + ')|(?:' + localMention + '))' // Include local mentions? + : '(?:' + remoteMention + ')' + + const firstMentionRegex = new RegExp(`^${mentionRegex} `, 'g') + const endMentionRegex = new RegExp(` ${mentionRegex}$`, 'g') const remoteMentionsRegex = new RegExp(' ' + remoteMention + ' ', 'g') - const localMentionsRegex = new RegExp(' ' + localMention + ' ', 'g') - const firstMentionRegex = new RegExp('^(?:(?:' + remoteMention + ')|(?:' + localMention + ')) ', 'g') - const endMentionRegex = new RegExp(' (?:(?:' + remoteMention + ')|(?:' + localMention + '))$', 'g') - return uniq( - [].concat( - regexpCapture(this.text, remoteMentionsRegex) - .map(([ , username ]) => username), + result = result.concat( + regexpCapture(this.text, firstMentionRegex) + .map(([ , username1, username2 ]) => username1 || username2), - regexpCapture(this.text, localMentionsRegex) - .map(([ , username ]) => username), + regexpCapture(this.text, endMentionRegex) + .map(([ , username1, username2 ]) => username1 || username2), - regexpCapture(this.text, firstMentionRegex) - .map(([ , username1, username2 ]) => username1 || username2), - - regexpCapture(this.text, endMentionRegex) - .map(([ , username1, username2 ]) => username1 || username2) - ) + regexpCapture(this.text, remoteMentionsRegex) + .map(([ , username ]) => username) ) + + // Include local mentions + if (this.isOwned()) { + const localMentionsRegex = new RegExp(' ' + localMention + ' ', 'g') + + result = result.concat( + regexpCapture(this.text, localMentionsRegex) + .map(([ , username ]) => username) + ) + } + + return uniq(result) } toFormattedJSON () { diff --git a/server/tests/api/users/user-notifications.ts b/server/tests/api/users/user-notifications.ts index 69e51677e..6c6d208f5 100644 --- a/server/tests/api/users/user-notifications.ts +++ b/server/tests/api/users/user-notifications.ts @@ -508,6 +508,20 @@ describe('Test users notifications', function () { await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') }) + it('Should not send a new mention notification if the remote account mention a local account', async function () { + this.timeout(20000) + + const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'super video' }) + const uuid = resVideo.body.video.uuid + + await waitJobs(servers) + const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, '@user_1 hello') + const threadId = resThread.body.comment.id + + await waitJobs(servers) + await checkCommentMention(baseParams, uuid, threadId, threadId, 'super root 2 name', 'absence') + }) + it('Should send a new mention notification after local comments', async function () { this.timeout(10000)