diff options
-rw-r--r-- | CHANGELOG.md | 12 | ||||
-rw-r--r-- | client/package.json | 2 | ||||
-rw-r--r-- | client/src/app/+admin/moderation/moderation.routes.ts | 2 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.html | 4 | ||||
-rw-r--r-- | client/src/app/menu/menu.component.scss | 7 | ||||
-rw-r--r-- | client/src/app/shared/users/user-notification.model.ts | 140 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rwxr-xr-x | scripts/reset-password.ts | 6 | ||||
-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 | ||||
-rw-r--r-- | support/doc/api/openapi.yaml | 2 |
17 files changed, 170 insertions, 99 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 13bec7535..911ec0fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md | |||
@@ -1,5 +1,17 @@ | |||
1 | # Changelog | 1 | # Changelog |
2 | 2 | ||
3 | ## v1.2.1 | ||
4 | |||
5 | ## Bug fixes | ||
6 | |||
7 | * **Important** Fix invalid `From` email header in contact form that could lead to the blacklisting of your SMTP server | ||
8 | * Fix too long display name overflow in menu | ||
9 | * Fix mention notification when a remote account mention a local account that has the same username than yours | ||
10 | * Fix access to muted servers table for moderators | ||
11 | * Don't crash notification popup on bug | ||
12 | * Fix reset password script that leaks password on invalid value | ||
13 | |||
14 | |||
3 | ## v1.2.0 | 15 | ## v1.2.0 |
4 | 16 | ||
5 | ### BREAKING CHANGES | 17 | ### BREAKING CHANGES |
diff --git a/client/package.json b/client/package.json index 31fc77887..bc06fbd1c 100644 --- a/client/package.json +++ b/client/package.json | |||
@@ -1,6 +1,6 @@ | |||
1 | { | 1 | { |
2 | "name": "peertube-client", | 2 | "name": "peertube-client", |
3 | "version": "1.2.0", | 3 | "version": "1.2.1", |
4 | "private": true, | 4 | "private": true, |
5 | "licence": "GPLv3", | 5 | "licence": "GPLv3", |
6 | "author": { | 6 | "author": { |
diff --git a/client/src/app/+admin/moderation/moderation.routes.ts b/client/src/app/+admin/moderation/moderation.routes.ts index bc6dd49d5..6f6dde290 100644 --- a/client/src/app/+admin/moderation/moderation.routes.ts +++ b/client/src/app/+admin/moderation/moderation.routes.ts | |||
@@ -64,7 +64,7 @@ export const ModerationRoutes: Routes = [ | |||
64 | component: InstanceServerBlocklistComponent, | 64 | component: InstanceServerBlocklistComponent, |
65 | canActivate: [ UserRightGuard ], | 65 | canActivate: [ UserRightGuard ], |
66 | data: { | 66 | data: { |
67 | userRight: UserRight.MANAGE_SERVER_REDUNDANCY, | 67 | userRight: UserRight.MANAGE_SERVERS_BLOCKLIST, |
68 | meta: { | 68 | meta: { |
69 | title: 'Muted instances' | 69 | title: 'Muted instances' |
70 | } | 70 | } |
diff --git a/client/src/app/menu/menu.component.html b/client/src/app/menu/menu.component.html index aa5bfa9c9..1e532ec13 100644 --- a/client/src/app/menu/menu.component.html +++ b/client/src/app/menu/menu.component.html | |||
@@ -5,8 +5,8 @@ | |||
5 | <my-avatar-notification [user]="user"></my-avatar-notification> | 5 | <my-avatar-notification [user]="user"></my-avatar-notification> |
6 | 6 | ||
7 | <div class="logged-in-info"> | 7 | <div class="logged-in-info"> |
8 | <a routerLink="/my-account/settings" class="logged-in-username">{{ user.account?.displayName }}</a> | 8 | <a routerLink="/my-account/settings" class="logged-in-display-name">{{ user.account?.displayName }}</a> |
9 | <div class="logged-in-email">{{ user.username }}</div> | 9 | <div class="logged-in-username">{{ user.username }}</div> |
10 | </div> | 10 | </div> |
11 | 11 | ||
12 | <div class="logged-in-more" ngbDropdown placement="bottom-right"> | 12 | <div class="logged-in-more" ngbDropdown placement="bottom-right"> |
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss index f30b89413..69704674a 100644 --- a/client/src/app/menu/menu.component.scss +++ b/client/src/app/menu/menu.component.scss | |||
@@ -41,8 +41,11 @@ menu { | |||
41 | 41 | ||
42 | .logged-in-info { | 42 | .logged-in-info { |
43 | flex-grow: 1; | 43 | flex-grow: 1; |
44 | white-space: nowrap; | ||
45 | overflow: hidden; | ||
46 | text-overflow: ellipsis; | ||
44 | 47 | ||
45 | .logged-in-username { | 48 | .logged-in-display-name { |
46 | font-size: 16px; | 49 | font-size: 16px; |
47 | font-weight: $font-semibold; | 50 | font-weight: $font-semibold; |
48 | color: var(--menuForegroundColor); | 51 | color: var(--menuForegroundColor); |
@@ -51,7 +54,7 @@ menu { | |||
51 | @include disable-default-a-behaviour; | 54 | @include disable-default-a-behaviour; |
52 | } | 55 | } |
53 | 56 | ||
54 | .logged-in-email { | 57 | .logged-in-username { |
55 | font-size: 13px; | 58 | font-size: 13px; |
56 | color: #C6C6C6; | 59 | color: #C6C6C6; |
57 | white-space: nowrap; | 60 | white-space: nowrap; |
diff --git a/client/src/app/shared/users/user-notification.model.ts b/client/src/app/shared/users/user-notification.model.ts index 125d2120c..5d0dc19ae 100644 --- a/client/src/app/shared/users/user-notification.model.ts +++ b/client/src/app/shared/users/user-notification.model.ts | |||
@@ -63,73 +63,79 @@ export class UserNotification implements UserNotificationServer { | |||
63 | this.type = hash.type | 63 | this.type = hash.type |
64 | this.read = hash.read | 64 | this.read = hash.read |
65 | 65 | ||
66 | this.video = hash.video | 66 | // We assume that some fields exist |
67 | if (this.video) this.setAvatarUrl(this.video.channel) | 67 | // To prevent a notification popup crash in case of bug, wrap it inside a try/catch |
68 | 68 | try { | |
69 | this.videoImport = hash.videoImport | 69 | this.video = hash.video |
70 | 70 | if (this.video) this.setAvatarUrl(this.video.channel) | |
71 | this.comment = hash.comment | 71 | |
72 | if (this.comment) this.setAvatarUrl(this.comment.account) | 72 | this.videoImport = hash.videoImport |
73 | 73 | ||
74 | this.videoAbuse = hash.videoAbuse | 74 | this.comment = hash.comment |
75 | 75 | if (this.comment) this.setAvatarUrl(this.comment.account) | |
76 | this.videoBlacklist = hash.videoBlacklist | 76 | |
77 | 77 | this.videoAbuse = hash.videoAbuse | |
78 | this.account = hash.account | 78 | |
79 | if (this.account) this.setAvatarUrl(this.account) | 79 | this.videoBlacklist = hash.videoBlacklist |
80 | 80 | ||
81 | this.actorFollow = hash.actorFollow | 81 | this.account = hash.account |
82 | if (this.actorFollow) this.setAvatarUrl(this.actorFollow.follower) | 82 | if (this.account) this.setAvatarUrl(this.account) |
83 | 83 | ||
84 | this.createdAt = hash.createdAt | 84 | this.actorFollow = hash.actorFollow |
85 | this.updatedAt = hash.updatedAt | 85 | if (this.actorFollow) this.setAvatarUrl(this.actorFollow.follower) |
86 | 86 | ||
87 | switch (this.type) { | 87 | this.createdAt = hash.createdAt |
88 | case UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION: | 88 | this.updatedAt = hash.updatedAt |
89 | this.videoUrl = this.buildVideoUrl(this.video) | 89 | |
90 | break | 90 | switch (this.type) { |
91 | 91 | case UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION: | |
92 | case UserNotificationType.UNBLACKLIST_ON_MY_VIDEO: | 92 | this.videoUrl = this.buildVideoUrl(this.video) |
93 | this.videoUrl = this.buildVideoUrl(this.video) | 93 | break |
94 | break | 94 | |
95 | 95 | case UserNotificationType.UNBLACKLIST_ON_MY_VIDEO: | |
96 | case UserNotificationType.NEW_COMMENT_ON_MY_VIDEO: | 96 | this.videoUrl = this.buildVideoUrl(this.video) |
97 | case UserNotificationType.COMMENT_MENTION: | 97 | break |
98 | this.accountUrl = this.buildAccountUrl(this.comment.account) | 98 | |
99 | this.commentUrl = [ this.buildVideoUrl(this.comment.video), { threadId: this.comment.threadId } ] | 99 | case UserNotificationType.NEW_COMMENT_ON_MY_VIDEO: |
100 | break | 100 | case UserNotificationType.COMMENT_MENTION: |
101 | 101 | this.accountUrl = this.buildAccountUrl(this.comment.account) | |
102 | case UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS: | 102 | this.commentUrl = [ this.buildVideoUrl(this.comment.video), { threadId: this.comment.threadId } ] |
103 | this.videoAbuseUrl = '/admin/moderation/video-abuses/list' | 103 | break |
104 | this.videoUrl = this.buildVideoUrl(this.videoAbuse.video) | 104 | |
105 | break | 105 | case UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS: |
106 | 106 | this.videoAbuseUrl = '/admin/moderation/video-abuses/list' | |
107 | case UserNotificationType.BLACKLIST_ON_MY_VIDEO: | 107 | this.videoUrl = this.buildVideoUrl(this.videoAbuse.video) |
108 | this.videoUrl = this.buildVideoUrl(this.videoBlacklist.video) | 108 | break |
109 | break | 109 | |
110 | 110 | case UserNotificationType.BLACKLIST_ON_MY_VIDEO: | |
111 | case UserNotificationType.MY_VIDEO_PUBLISHED: | 111 | this.videoUrl = this.buildVideoUrl(this.videoBlacklist.video) |
112 | this.videoUrl = this.buildVideoUrl(this.video) | 112 | break |
113 | break | 113 | |
114 | 114 | case UserNotificationType.MY_VIDEO_PUBLISHED: | |
115 | case UserNotificationType.MY_VIDEO_IMPORT_SUCCESS: | 115 | this.videoUrl = this.buildVideoUrl(this.video) |
116 | this.videoImportUrl = this.buildVideoImportUrl() | 116 | break |
117 | this.videoImportIdentifier = this.buildVideoImportIdentifier(this.videoImport) | 117 | |
118 | this.videoUrl = this.buildVideoUrl(this.videoImport.video) | 118 | case UserNotificationType.MY_VIDEO_IMPORT_SUCCESS: |
119 | break | 119 | this.videoImportUrl = this.buildVideoImportUrl() |
120 | 120 | this.videoImportIdentifier = this.buildVideoImportIdentifier(this.videoImport) | |
121 | case UserNotificationType.MY_VIDEO_IMPORT_ERROR: | 121 | this.videoUrl = this.buildVideoUrl(this.videoImport.video) |
122 | this.videoImportUrl = this.buildVideoImportUrl() | 122 | break |
123 | this.videoImportIdentifier = this.buildVideoImportIdentifier(this.videoImport) | 123 | |
124 | break | 124 | case UserNotificationType.MY_VIDEO_IMPORT_ERROR: |
125 | 125 | this.videoImportUrl = this.buildVideoImportUrl() | |
126 | case UserNotificationType.NEW_USER_REGISTRATION: | 126 | this.videoImportIdentifier = this.buildVideoImportIdentifier(this.videoImport) |
127 | this.accountUrl = this.buildAccountUrl(this.account) | 127 | break |
128 | break | 128 | |
129 | 129 | case UserNotificationType.NEW_USER_REGISTRATION: | |
130 | case UserNotificationType.NEW_FOLLOW: | 130 | this.accountUrl = this.buildAccountUrl(this.account) |
131 | this.accountUrl = this.buildAccountUrl(this.actorFollow.follower) | 131 | break |
132 | break | 132 | |
133 | case UserNotificationType.NEW_FOLLOW: | ||
134 | this.accountUrl = this.buildAccountUrl(this.actorFollow.follower) | ||
135 | break | ||
136 | } | ||
137 | } catch (err) { | ||
138 | console.error(err) | ||
133 | } | 139 | } |
134 | } | 140 | } |
135 | 141 | ||
diff --git a/package.json b/package.json index 0cf39c7ee..ed99157c4 100644 --- a/package.json +++ b/package.json | |||
@@ -1,7 +1,7 @@ | |||
1 | { | 1 | { |
2 | "name": "peertube", | 2 | "name": "peertube", |
3 | "description": "Federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.", | 3 | "description": "Federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.", |
4 | "version": "1.2.0", | 4 | "version": "1.2.1", |
5 | "private": true, | 5 | "private": true, |
6 | "licence": "AGPLv3", | 6 | "licence": "AGPLv3", |
7 | "engines": { | 7 | "engines": { |
diff --git a/scripts/reset-password.ts b/scripts/reset-password.ts index 6516edc28..4a9037280 100755 --- a/scripts/reset-password.ts +++ b/scripts/reset-password.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import * as program from 'commander' | 1 | import * as program from 'commander' |
2 | import { initDatabaseModels } from '../server/initializers' | 2 | import { initDatabaseModels } from '../server/initializers' |
3 | import { UserModel } from '../server/models/account/user' | 3 | import { UserModel } from '../server/models/account/user' |
4 | import { isUserPasswordValid } from '../server/helpers/custom-validators/users' | ||
4 | 5 | ||
5 | program | 6 | program |
6 | .option('-u, --user [user]', 'User') | 7 | .option('-u, --user [user]', 'User') |
@@ -36,6 +37,11 @@ initDatabaseModels(true) | |||
36 | 37 | ||
37 | console.log('New password?') | 38 | console.log('New password?') |
38 | rl.on('line', function (password) { | 39 | rl.on('line', function (password) { |
40 | if (!isUserPasswordValid(password)) { | ||
41 | console.error('New password is invalid.') | ||
42 | process.exit(-1) | ||
43 | } | ||
44 | |||
39 | user.password = password | 45 | user.password = password |
40 | 46 | ||
41 | user.save() | 47 | user.save() |
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 () { |
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml index f2bb945f9..ea419029c 100644 --- a/support/doc/api/openapi.yaml +++ b/support/doc/api/openapi.yaml | |||
@@ -1,7 +1,7 @@ | |||
1 | openapi: 3.0.0 | 1 | openapi: 3.0.0 |
2 | info: | 2 | info: |
3 | title: PeerTube | 3 | title: PeerTube |
4 | version: 1.2.0 | 4 | version: 1.2.1 |
5 | contact: | 5 | contact: |
6 | name: PeerTube Community | 6 | name: PeerTube Community |
7 | url: 'https://joinpeertube.org' | 7 | url: 'https://joinpeertube.org' |