diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/lib/emailer.ts | 18 | ||||
-rw-r--r-- | server/lib/job-queue/handlers/email.ts | 6 | ||||
-rw-r--r-- | server/lib/notifier.ts | 2 | ||||
-rw-r--r-- | server/models/video/video-comment.ts | 40 | ||||
-rw-r--r-- | server/tests/api/server/contact-form.ts | 3 | ||||
-rw-r--r-- | server/tests/api/server/email.ts | 7 | ||||
-rw-r--r-- | server/tests/api/users/user-notifications.ts | 14 | ||||
-rw-r--r-- | server/tests/helpers/comment-model.ts | 2 |
8 files changed, 68 insertions, 24 deletions
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index f384a254e..99010f473 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts | |||
@@ -361,7 +361,8 @@ class Emailer { | |||
361 | 'PeerTube.' | 361 | 'PeerTube.' |
362 | 362 | ||
363 | const emailPayload: EmailPayload = { | 363 | const emailPayload: EmailPayload = { |
364 | from: fromEmail, | 364 | fromDisplayName: fromEmail, |
365 | replyTo: fromEmail, | ||
365 | to: [ CONFIG.ADMIN.EMAIL ], | 366 | to: [ CONFIG.ADMIN.EMAIL ], |
366 | subject: '[PeerTube] Contact form submitted', | 367 | subject: '[PeerTube] Contact form submitted', |
367 | text | 368 | text |
@@ -370,16 +371,21 @@ class Emailer { | |||
370 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | 371 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) |
371 | } | 372 | } |
372 | 373 | ||
373 | sendMail (to: string[], subject: string, text: string, from?: string) { | 374 | sendMail (options: EmailPayload) { |
374 | if (!Emailer.isEnabled()) { | 375 | if (!Emailer.isEnabled()) { |
375 | throw new Error('Cannot send mail because SMTP is not configured.') | 376 | throw new Error('Cannot send mail because SMTP is not configured.') |
376 | } | 377 | } |
377 | 378 | ||
379 | const fromDisplayName = options.fromDisplayName | ||
380 | ? options.fromDisplayName | ||
381 | : CONFIG.WEBSERVER.HOST | ||
382 | |||
378 | return this.transporter.sendMail({ | 383 | return this.transporter.sendMail({ |
379 | from: from || CONFIG.SMTP.FROM_ADDRESS, | 384 | from: `"${fromDisplayName}" <${CONFIG.SMTP.FROM_ADDRESS}>`, |
380 | to: to.join(','), | 385 | replyTo: options.replyTo, |
381 | subject, | 386 | to: options.to.join(','), |
382 | text | 387 | subject: options.subject, |
388 | text: options.text | ||
383 | }) | 389 | }) |
384 | } | 390 | } |
385 | 391 | ||
diff --git a/server/lib/job-queue/handlers/email.ts b/server/lib/job-queue/handlers/email.ts index 220d0af32..2ba39a156 100644 --- a/server/lib/job-queue/handlers/email.ts +++ b/server/lib/job-queue/handlers/email.ts | |||
@@ -6,14 +6,16 @@ export type EmailPayload = { | |||
6 | to: string[] | 6 | to: string[] |
7 | subject: string | 7 | subject: string |
8 | text: string | 8 | text: string |
9 | from?: string | 9 | |
10 | fromDisplayName?: string | ||
11 | replyTo?: string | ||
10 | } | 12 | } |
11 | 13 | ||
12 | async function processEmail (job: Bull.Job) { | 14 | async function processEmail (job: Bull.Job) { |
13 | const payload = job.data as EmailPayload | 15 | const payload = job.data as EmailPayload |
14 | logger.info('Processing email in job %d.', job.id) | 16 | logger.info('Processing email in job %d.', job.id) |
15 | 17 | ||
16 | return Emailer.Instance.sendMail(payload.to, payload.subject, payload.text, payload.from) | 18 | return Emailer.Instance.sendMail(payload) |
17 | } | 19 | } |
18 | 20 | ||
19 | // --------------------------------------------------------------------------- | 21 | // --------------------------------------------------------------------------- |
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 { | |||
148 | 148 | ||
149 | private async notifyOfCommentMention (comment: VideoCommentModel) { | 149 | private async notifyOfCommentMention (comment: VideoCommentModel) { |
150 | const usernames = comment.extractMentions() | 150 | const usernames = comment.extractMentions() |
151 | logger.debug('Extracted %d username from comment %s.', usernames.length, comment.url, { usernames, text: comment.text }) | ||
152 | |||
151 | let users = await UserModel.listByUsernames(usernames) | 153 | let users = await UserModel.listByUsernames(usernames) |
152 | 154 | ||
153 | if (comment.Video.isOwned()) { | 155 | 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<VideoCommentModel> { | |||
466 | } | 466 | } |
467 | 467 | ||
468 | extractMentions () { | 468 | extractMentions () { |
469 | if (!this.text) return [] | 469 | let result: string[] = [] |
470 | 470 | ||
471 | const localMention = `@(${actorNameAlphabet}+)` | 471 | const localMention = `@(${actorNameAlphabet}+)` |
472 | const remoteMention = `${localMention}@${CONFIG.WEBSERVER.HOST}` | 472 | const remoteMention = `${localMention}@${CONFIG.WEBSERVER.HOST}` |
473 | 473 | ||
474 | const mentionRegex = this.isOwned() | ||
475 | ? '(?:(?:' + remoteMention + ')|(?:' + localMention + '))' // Include local mentions? | ||
476 | : '(?:' + remoteMention + ')' | ||
477 | |||
478 | const firstMentionRegex = new RegExp(`^${mentionRegex} `, 'g') | ||
479 | const endMentionRegex = new RegExp(` ${mentionRegex}$`, 'g') | ||
474 | const remoteMentionsRegex = new RegExp(' ' + remoteMention + ' ', 'g') | 480 | const remoteMentionsRegex = new RegExp(' ' + remoteMention + ' ', 'g') |
475 | const localMentionsRegex = new RegExp(' ' + localMention + ' ', 'g') | ||
476 | const firstMentionRegex = new RegExp('^(?:(?:' + remoteMention + ')|(?:' + localMention + ')) ', 'g') | ||
477 | const endMentionRegex = new RegExp(' (?:(?:' + remoteMention + ')|(?:' + localMention + '))$', 'g') | ||
478 | 481 | ||
479 | return uniq( | 482 | result = result.concat( |
480 | [].concat( | 483 | regexpCapture(this.text, firstMentionRegex) |
481 | regexpCapture(this.text, remoteMentionsRegex) | 484 | .map(([ , username1, username2 ]) => username1 || username2), |
482 | .map(([ , username ]) => username), | ||
483 | 485 | ||
484 | regexpCapture(this.text, localMentionsRegex) | 486 | regexpCapture(this.text, endMentionRegex) |
485 | .map(([ , username ]) => username), | 487 | .map(([ , username1, username2 ]) => username1 || username2), |
488 | |||
489 | regexpCapture(this.text, remoteMentionsRegex) | ||
490 | .map(([ , username ]) => username) | ||
491 | ) | ||
486 | 492 | ||
487 | regexpCapture(this.text, firstMentionRegex) | 493 | // Include local mentions |
488 | .map(([ , username1, username2 ]) => username1 || username2), | 494 | if (this.isOwned()) { |
495 | const localMentionsRegex = new RegExp(' ' + localMention + ' ', 'g') | ||
489 | 496 | ||
490 | regexpCapture(this.text, endMentionRegex) | 497 | result = result.concat( |
491 | .map(([ , username1, username2 ]) => username1 || username2) | 498 | regexpCapture(this.text, localMentionsRegex) |
499 | .map(([ , username ]) => username) | ||
492 | ) | 500 | ) |
493 | ) | 501 | } |
502 | |||
503 | return uniq(result) | ||
494 | } | 504 | } |
495 | 505 | ||
496 | toFormattedJSON () { | 506 | toFormattedJSON () { |
diff --git a/server/tests/api/server/contact-form.ts b/server/tests/api/server/contact-form.ts index 93221d0a3..06a2f89b0 100644 --- a/server/tests/api/server/contact-form.ts +++ b/server/tests/api/server/contact-form.ts | |||
@@ -45,7 +45,8 @@ describe('Test contact form', function () { | |||
45 | 45 | ||
46 | const email = emails[0] | 46 | const email = emails[0] |
47 | 47 | ||
48 | expect(email['from'][0]['address']).equal('toto@example.com') | 48 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
49 | expect(email['from'][0]['name']).equal('toto@example.com') | ||
49 | expect(email['to'][0]['address']).equal('admin1@example.com') | 50 | expect(email['to'][0]['address']).equal('admin1@example.com') |
50 | expect(email['subject']).contains('Contact form') | 51 | expect(email['subject']).contains('Contact form') |
51 | expect(email['text']).contains('my super message') | 52 | expect(email['text']).contains('my super message') |
diff --git a/server/tests/api/server/email.ts b/server/tests/api/server/email.ts index f96c57b66..f8f16f54f 100644 --- a/server/tests/api/server/email.ts +++ b/server/tests/api/server/email.ts | |||
@@ -89,6 +89,7 @@ describe('Test emails', function () { | |||
89 | 89 | ||
90 | const email = emails[0] | 90 | const email = emails[0] |
91 | 91 | ||
92 | expect(email['from'][0]['name']).equal('localhost:9001') | ||
92 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 93 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
93 | expect(email['to'][0]['address']).equal('user_1@example.com') | 94 | expect(email['to'][0]['address']).equal('user_1@example.com') |
94 | expect(email['subject']).contains('password') | 95 | expect(email['subject']).contains('password') |
@@ -133,6 +134,7 @@ describe('Test emails', function () { | |||
133 | 134 | ||
134 | const email = emails[1] | 135 | const email = emails[1] |
135 | 136 | ||
137 | expect(email['from'][0]['name']).equal('localhost:9001') | ||
136 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 138 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
137 | expect(email['to'][0]['address']).equal('admin1@example.com') | 139 | expect(email['to'][0]['address']).equal('admin1@example.com') |
138 | expect(email['subject']).contains('abuse') | 140 | expect(email['subject']).contains('abuse') |
@@ -152,6 +154,7 @@ describe('Test emails', function () { | |||
152 | 154 | ||
153 | const email = emails[2] | 155 | const email = emails[2] |
154 | 156 | ||
157 | expect(email['from'][0]['name']).equal('localhost:9001') | ||
155 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 158 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
156 | expect(email['to'][0]['address']).equal('user_1@example.com') | 159 | expect(email['to'][0]['address']).equal('user_1@example.com') |
157 | expect(email['subject']).contains(' blocked') | 160 | expect(email['subject']).contains(' blocked') |
@@ -169,6 +172,7 @@ describe('Test emails', function () { | |||
169 | 172 | ||
170 | const email = emails[3] | 173 | const email = emails[3] |
171 | 174 | ||
175 | expect(email['from'][0]['name']).equal('localhost:9001') | ||
172 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 176 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
173 | expect(email['to'][0]['address']).equal('user_1@example.com') | 177 | expect(email['to'][0]['address']).equal('user_1@example.com') |
174 | expect(email['subject']).contains(' unblocked') | 178 | expect(email['subject']).contains(' unblocked') |
@@ -188,6 +192,7 @@ describe('Test emails', function () { | |||
188 | 192 | ||
189 | const email = emails[4] | 193 | const email = emails[4] |
190 | 194 | ||
195 | expect(email['from'][0]['name']).equal('localhost:9001') | ||
191 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 196 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
192 | expect(email['to'][0]['address']).equal('user_1@example.com') | 197 | expect(email['to'][0]['address']).equal('user_1@example.com') |
193 | expect(email['subject']).contains(' blacklisted') | 198 | expect(email['subject']).contains(' blacklisted') |
@@ -205,6 +210,7 @@ describe('Test emails', function () { | |||
205 | 210 | ||
206 | const email = emails[5] | 211 | const email = emails[5] |
207 | 212 | ||
213 | expect(email['from'][0]['name']).equal('localhost:9001') | ||
208 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 214 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
209 | expect(email['to'][0]['address']).equal('user_1@example.com') | 215 | expect(email['to'][0]['address']).equal('user_1@example.com') |
210 | expect(email['subject']).contains(' unblacklisted') | 216 | expect(email['subject']).contains(' unblacklisted') |
@@ -224,6 +230,7 @@ describe('Test emails', function () { | |||
224 | 230 | ||
225 | const email = emails[6] | 231 | const email = emails[6] |
226 | 232 | ||
233 | expect(email['from'][0]['name']).equal('localhost:9001') | ||
227 | expect(email['from'][0]['address']).equal('test-admin@localhost') | 234 | expect(email['from'][0]['address']).equal('test-admin@localhost') |
228 | expect(email['to'][0]['address']).equal('user_1@example.com') | 235 | expect(email['to'][0]['address']).equal('user_1@example.com') |
229 | expect(email['subject']).contains('Verify') | 236 | expect(email['subject']).contains('Verify') |
diff --git a/server/tests/api/users/user-notifications.ts b/server/tests/api/users/user-notifications.ts index 5260d64cc..72b6a0aa2 100644 --- a/server/tests/api/users/user-notifications.ts +++ b/server/tests/api/users/user-notifications.ts | |||
@@ -506,6 +506,20 @@ describe('Test users notifications', function () { | |||
506 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') | 506 | await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root') |
507 | }) | 507 | }) |
508 | 508 | ||
509 | it('Should not send a new mention notification if the remote account mention a local account', async function () { | ||
510 | this.timeout(20000) | ||
511 | |||
512 | const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'super video' }) | ||
513 | const uuid = resVideo.body.video.uuid | ||
514 | |||
515 | await waitJobs(servers) | ||
516 | const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, '@user_1 hello') | ||
517 | const threadId = resThread.body.comment.id | ||
518 | |||
519 | await waitJobs(servers) | ||
520 | await checkCommentMention(baseParams, uuid, threadId, threadId, 'super root 2 name', 'absence') | ||
521 | }) | ||
522 | |||
509 | it('Should send a new mention notification after local comments', async function () { | 523 | it('Should send a new mention notification after local comments', async function () { |
510 | this.timeout(10000) | 524 | this.timeout(10000) |
511 | 525 | ||
diff --git a/server/tests/helpers/comment-model.ts b/server/tests/helpers/comment-model.ts index 76bb0f212..ebfd779e1 100644 --- a/server/tests/helpers/comment-model.ts +++ b/server/tests/helpers/comment-model.ts | |||
@@ -10,6 +10,8 @@ class CommentMock { | |||
10 | text: string | 10 | text: string |
11 | 11 | ||
12 | extractMentions = VideoCommentModel.prototype.extractMentions | 12 | extractMentions = VideoCommentModel.prototype.extractMentions |
13 | |||
14 | isOwned = () => true | ||
13 | } | 15 | } |
14 | 16 | ||
15 | describe('Comment model', function () { | 17 | describe('Comment model', function () { |