aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared/server-commands/users
diff options
context:
space:
mode:
Diffstat (limited to 'shared/server-commands/users')
-rw-r--r--shared/server-commands/users/accounts-command.ts4
-rw-r--r--shared/server-commands/users/actors.ts73
-rw-r--r--shared/server-commands/users/index.ts2
-rw-r--r--shared/server-commands/users/notifications-command.ts3
-rw-r--r--shared/server-commands/users/notifications.ts795
-rw-r--r--shared/server-commands/users/users-command.ts2
6 files changed, 3 insertions, 876 deletions
diff --git a/shared/server-commands/users/accounts-command.ts b/shared/server-commands/users/accounts-command.ts
index 98d9d5927..5844b330b 100644
--- a/shared/server-commands/users/accounts-command.ts
+++ b/shared/server-commands/users/accounts-command.ts
@@ -1,6 +1,4 @@
1import { HttpStatusCode, ResultList } from '@shared/models' 1import { Account, AccountVideoRate, ActorFollow, HttpStatusCode, ResultList, VideoRateType } from '@shared/models'
2import { Account, ActorFollow } from '../../models/actors'
3import { AccountVideoRate, VideoRateType } from '../../models/videos'
4import { AbstractCommand, OverrideCommandOptions } from '../shared' 2import { AbstractCommand, OverrideCommandOptions } from '../shared'
5 3
6export class AccountsCommand extends AbstractCommand { 4export class AccountsCommand extends AbstractCommand {
diff --git a/shared/server-commands/users/actors.ts b/shared/server-commands/users/actors.ts
deleted file mode 100644
index 12c3e078a..000000000
--- a/shared/server-commands/users/actors.ts
+++ /dev/null
@@ -1,73 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { pathExists, readdir } from 'fs-extra'
5import { join } from 'path'
6import { root } from '@shared/core-utils'
7import { Account, VideoChannel } from '@shared/models'
8import { PeerTubeServer } from '../server'
9
10async function expectChannelsFollows (options: {
11 server: PeerTubeServer
12 handle: string
13 followers: number
14 following: number
15}) {
16 const { server } = options
17 const { data } = await server.channels.list()
18
19 return expectActorFollow({ ...options, data })
20}
21
22async function expectAccountFollows (options: {
23 server: PeerTubeServer
24 handle: string
25 followers: number
26 following: number
27}) {
28 const { server } = options
29 const { data } = await server.accounts.list()
30
31 return expectActorFollow({ ...options, data })
32}
33
34async function checkActorFilesWereRemoved (filename: string, serverNumber: number) {
35 const testDirectory = 'test' + serverNumber
36
37 for (const directory of [ 'avatars' ]) {
38 const directoryPath = join(root(), testDirectory, directory)
39
40 const directoryExists = await pathExists(directoryPath)
41 expect(directoryExists).to.be.true
42
43 const files = await readdir(directoryPath)
44 for (const file of files) {
45 expect(file).to.not.contain(filename)
46 }
47 }
48}
49
50export {
51 expectAccountFollows,
52 expectChannelsFollows,
53 checkActorFilesWereRemoved
54}
55
56// ---------------------------------------------------------------------------
57
58function expectActorFollow (options: {
59 server: PeerTubeServer
60 data: (Account | VideoChannel)[]
61 handle: string
62 followers: number
63 following: number
64}) {
65 const { server, data, handle, followers, following } = options
66
67 const actor = data.find(a => a.name + '@' + a.host === handle)
68 const message = `${handle} on ${server.url}`
69
70 expect(actor, message).to.exist
71 expect(actor.followersCount).to.equal(followers, message)
72 expect(actor.followingCount).to.equal(following, message)
73}
diff --git a/shared/server-commands/users/index.ts b/shared/server-commands/users/index.ts
index 460a06f70..c2bc5c44f 100644
--- a/shared/server-commands/users/index.ts
+++ b/shared/server-commands/users/index.ts
@@ -1,9 +1,7 @@
1export * from './accounts-command' 1export * from './accounts-command'
2export * from './actors'
3export * from './blocklist-command' 2export * from './blocklist-command'
4export * from './login' 3export * from './login'
5export * from './login-command' 4export * from './login-command'
6export * from './notifications'
7export * from './notifications-command' 5export * from './notifications-command'
8export * from './subscriptions-command' 6export * from './subscriptions-command'
9export * from './users-command' 7export * from './users-command'
diff --git a/shared/server-commands/users/notifications-command.ts b/shared/server-commands/users/notifications-command.ts
index 692420b8b..6bd815daa 100644
--- a/shared/server-commands/users/notifications-command.ts
+++ b/shared/server-commands/users/notifications-command.ts
@@ -1,5 +1,4 @@
1import { HttpStatusCode, ResultList } from '@shared/models' 1import { HttpStatusCode, ResultList, UserNotification, UserNotificationSetting } from '@shared/models'
2import { UserNotification, UserNotificationSetting } from '../../models/users'
3import { AbstractCommand, OverrideCommandOptions } from '../shared' 2import { AbstractCommand, OverrideCommandOptions } from '../shared'
4 3
5export class NotificationsCommand extends AbstractCommand { 4export class NotificationsCommand extends AbstractCommand {
diff --git a/shared/server-commands/users/notifications.ts b/shared/server-commands/users/notifications.ts
deleted file mode 100644
index 07ccb0f8d..000000000
--- a/shared/server-commands/users/notifications.ts
+++ /dev/null
@@ -1,795 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import { expect } from 'chai'
4import { inspect } from 'util'
5import { AbuseState, PluginType } from '@shared/models'
6import { UserNotification, UserNotificationSetting, UserNotificationSettingValue, UserNotificationType } from '../../models/users'
7import { MockSmtpServer } from '../mock-servers/mock-email'
8import { PeerTubeServer } from '../server'
9import { doubleFollow } from '../server/follows'
10import { createMultipleServers } from '../server/servers'
11import { setAccessTokensToServers } from './login'
12
13type CheckerBaseParams = {
14 server: PeerTubeServer
15 emails: any[]
16 socketNotifications: UserNotification[]
17 token: string
18 check?: { web: boolean, mail: boolean }
19}
20
21type CheckerType = 'presence' | 'absence'
22
23function getAllNotificationsSettings (): UserNotificationSetting {
24 return {
25 newVideoFromSubscription: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
26 newCommentOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
27 abuseAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
28 videoAutoBlacklistAsModerator: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
29 blacklistOnMyVideo: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
30 myVideoImportFinished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
31 myVideoPublished: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
32 commentMention: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
33 newFollow: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
34 newUserRegistration: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
35 newInstanceFollower: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
36 abuseNewMessage: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
37 abuseStateChange: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
38 autoInstanceFollowing: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
39 newPeerTubeVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL,
40 newPluginVersion: UserNotificationSettingValue.WEB | UserNotificationSettingValue.EMAIL
41 }
42}
43
44async function checkNewVideoFromSubscription (options: CheckerBaseParams & {
45 videoName: string
46 shortUUID: string
47 checkType: CheckerType
48}) {
49 const { videoName, shortUUID } = options
50 const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION
51
52 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
53 if (checkType === 'presence') {
54 expect(notification).to.not.be.undefined
55 expect(notification.type).to.equal(notificationType)
56
57 checkVideo(notification.video, videoName, shortUUID)
58 checkActor(notification.video.channel)
59 } else {
60 expect(notification).to.satisfy((n: UserNotification) => {
61 return n === undefined || n.type !== UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION || n.video.name !== videoName
62 })
63 }
64 }
65
66 function emailNotificationFinder (email: object) {
67 const text = email['text']
68 return text.indexOf(shortUUID) !== -1 && text.indexOf('Your subscription') !== -1
69 }
70
71 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
72}
73
74async function checkVideoIsPublished (options: CheckerBaseParams & {
75 videoName: string
76 shortUUID: string
77 checkType: CheckerType
78}) {
79 const { videoName, shortUUID } = options
80 const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED
81
82 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
83 if (checkType === 'presence') {
84 expect(notification).to.not.be.undefined
85 expect(notification.type).to.equal(notificationType)
86
87 checkVideo(notification.video, videoName, shortUUID)
88 checkActor(notification.video.channel)
89 } else {
90 expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
91 }
92 }
93
94 function emailNotificationFinder (email: object) {
95 const text: string = email['text']
96 return text.includes(shortUUID) && text.includes('Your video')
97 }
98
99 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
100}
101
102async function checkMyVideoImportIsFinished (options: CheckerBaseParams & {
103 videoName: string
104 shortUUID: string
105 url: string
106 success: boolean
107 checkType: CheckerType
108}) {
109 const { videoName, shortUUID, url, success } = options
110
111 const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR
112
113 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
114 if (checkType === 'presence') {
115 expect(notification).to.not.be.undefined
116 expect(notification.type).to.equal(notificationType)
117
118 expect(notification.videoImport.targetUrl).to.equal(url)
119
120 if (success) checkVideo(notification.videoImport.video, videoName, shortUUID)
121 } else {
122 expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url)
123 }
124 }
125
126 function emailNotificationFinder (email: object) {
127 const text: string = email['text']
128 const toFind = success ? ' finished' : ' error'
129
130 return text.includes(url) && text.includes(toFind)
131 }
132
133 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
134}
135
136async function checkUserRegistered (options: CheckerBaseParams & {
137 username: string
138 checkType: CheckerType
139}) {
140 const { username } = options
141 const notificationType = UserNotificationType.NEW_USER_REGISTRATION
142
143 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
144 if (checkType === 'presence') {
145 expect(notification).to.not.be.undefined
146 expect(notification.type).to.equal(notificationType)
147
148 checkActor(notification.account)
149 expect(notification.account.name).to.equal(username)
150 } else {
151 expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username)
152 }
153 }
154
155 function emailNotificationFinder (email: object) {
156 const text: string = email['text']
157
158 return text.includes(' registered.') && text.includes(username)
159 }
160
161 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
162}
163
164async function checkNewActorFollow (options: CheckerBaseParams & {
165 followType: 'channel' | 'account'
166 followerName: string
167 followerDisplayName: string
168 followingDisplayName: string
169 checkType: CheckerType
170}) {
171 const { followType, followerName, followerDisplayName, followingDisplayName } = options
172 const notificationType = UserNotificationType.NEW_FOLLOW
173
174 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
175 if (checkType === 'presence') {
176 expect(notification).to.not.be.undefined
177 expect(notification.type).to.equal(notificationType)
178
179 checkActor(notification.actorFollow.follower)
180 expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName)
181 expect(notification.actorFollow.follower.name).to.equal(followerName)
182 expect(notification.actorFollow.follower.host).to.not.be.undefined
183
184 const following = notification.actorFollow.following
185 expect(following.displayName).to.equal(followingDisplayName)
186 expect(following.type).to.equal(followType)
187 } else {
188 expect(notification).to.satisfy(n => {
189 return n.type !== notificationType ||
190 (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName)
191 })
192 }
193 }
194
195 function emailNotificationFinder (email: object) {
196 const text: string = email['text']
197
198 return text.includes(followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
199 }
200
201 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
202}
203
204async function checkNewInstanceFollower (options: CheckerBaseParams & {
205 followerHost: string
206 checkType: CheckerType
207}) {
208 const { followerHost } = options
209 const notificationType = UserNotificationType.NEW_INSTANCE_FOLLOWER
210
211 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
212 if (checkType === 'presence') {
213 expect(notification).to.not.be.undefined
214 expect(notification.type).to.equal(notificationType)
215
216 checkActor(notification.actorFollow.follower)
217 expect(notification.actorFollow.follower.name).to.equal('peertube')
218 expect(notification.actorFollow.follower.host).to.equal(followerHost)
219
220 expect(notification.actorFollow.following.name).to.equal('peertube')
221 } else {
222 expect(notification).to.satisfy(n => {
223 return n.type !== notificationType || n.actorFollow.follower.host !== followerHost
224 })
225 }
226 }
227
228 function emailNotificationFinder (email: object) {
229 const text: string = email['text']
230
231 return text.includes('instance has a new follower') && text.includes(followerHost)
232 }
233
234 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
235}
236
237async function checkAutoInstanceFollowing (options: CheckerBaseParams & {
238 followerHost: string
239 followingHost: string
240 checkType: CheckerType
241}) {
242 const { followerHost, followingHost } = options
243 const notificationType = UserNotificationType.AUTO_INSTANCE_FOLLOWING
244
245 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
246 if (checkType === 'presence') {
247 expect(notification).to.not.be.undefined
248 expect(notification.type).to.equal(notificationType)
249
250 const following = notification.actorFollow.following
251 checkActor(following)
252 expect(following.name).to.equal('peertube')
253 expect(following.host).to.equal(followingHost)
254
255 expect(notification.actorFollow.follower.name).to.equal('peertube')
256 expect(notification.actorFollow.follower.host).to.equal(followerHost)
257 } else {
258 expect(notification).to.satisfy(n => {
259 return n.type !== notificationType || n.actorFollow.following.host !== followingHost
260 })
261 }
262 }
263
264 function emailNotificationFinder (email: object) {
265 const text: string = email['text']
266
267 return text.includes(' automatically followed a new instance') && text.includes(followingHost)
268 }
269
270 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
271}
272
273async function checkCommentMention (options: CheckerBaseParams & {
274 shortUUID: string
275 commentId: number
276 threadId: number
277 byAccountDisplayName: string
278 checkType: CheckerType
279}) {
280 const { shortUUID, commentId, threadId, byAccountDisplayName } = options
281 const notificationType = UserNotificationType.COMMENT_MENTION
282
283 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
284 if (checkType === 'presence') {
285 expect(notification).to.not.be.undefined
286 expect(notification.type).to.equal(notificationType)
287
288 checkComment(notification.comment, commentId, threadId)
289 checkActor(notification.comment.account)
290 expect(notification.comment.account.displayName).to.equal(byAccountDisplayName)
291
292 checkVideo(notification.comment.video, undefined, shortUUID)
293 } else {
294 expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId)
295 }
296 }
297
298 function emailNotificationFinder (email: object) {
299 const text: string = email['text']
300
301 return text.includes(' mentioned ') && text.includes(shortUUID) && text.includes(byAccountDisplayName)
302 }
303
304 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
305}
306
307let lastEmailCount = 0
308
309async function checkNewCommentOnMyVideo (options: CheckerBaseParams & {
310 shortUUID: string
311 commentId: number
312 threadId: number
313 checkType: CheckerType
314}) {
315 const { server, shortUUID, commentId, threadId, checkType, emails } = options
316 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
317
318 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
319 if (checkType === 'presence') {
320 expect(notification).to.not.be.undefined
321 expect(notification.type).to.equal(notificationType)
322
323 checkComment(notification.comment, commentId, threadId)
324 checkActor(notification.comment.account)
325 checkVideo(notification.comment.video, undefined, shortUUID)
326 } else {
327 expect(notification).to.satisfy((n: UserNotification) => {
328 return n === undefined || n.comment === undefined || n.comment.id !== commentId
329 })
330 }
331 }
332
333 const commentUrl = `http://localhost:${server.port}/w/${shortUUID};threadId=${threadId}`
334
335 function emailNotificationFinder (email: object) {
336 return email['text'].indexOf(commentUrl) !== -1
337 }
338
339 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
340
341 if (checkType === 'presence') {
342 // We cannot detect email duplicates, so check we received another email
343 expect(emails).to.have.length.above(lastEmailCount)
344 lastEmailCount = emails.length
345 }
346}
347
348async function checkNewVideoAbuseForModerators (options: CheckerBaseParams & {
349 shortUUID: string
350 videoName: string
351 checkType: CheckerType
352}) {
353 const { shortUUID, videoName } = options
354 const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
355
356 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
357 if (checkType === 'presence') {
358 expect(notification).to.not.be.undefined
359 expect(notification.type).to.equal(notificationType)
360
361 expect(notification.abuse.id).to.be.a('number')
362 checkVideo(notification.abuse.video, videoName, shortUUID)
363 } else {
364 expect(notification).to.satisfy((n: UserNotification) => {
365 return n === undefined || n.abuse === undefined || n.abuse.video.shortUUID !== shortUUID
366 })
367 }
368 }
369
370 function emailNotificationFinder (email: object) {
371 const text = email['text']
372 return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1
373 }
374
375 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
376}
377
378async function checkNewAbuseMessage (options: CheckerBaseParams & {
379 abuseId: number
380 message: string
381 toEmail: string
382 checkType: CheckerType
383}) {
384 const { abuseId, message, toEmail } = options
385 const notificationType = UserNotificationType.ABUSE_NEW_MESSAGE
386
387 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
388 if (checkType === 'presence') {
389 expect(notification).to.not.be.undefined
390 expect(notification.type).to.equal(notificationType)
391
392 expect(notification.abuse.id).to.equal(abuseId)
393 } else {
394 expect(notification).to.satisfy((n: UserNotification) => {
395 return n === undefined || n.type !== notificationType || n.abuse === undefined || n.abuse.id !== abuseId
396 })
397 }
398 }
399
400 function emailNotificationFinder (email: object) {
401 const text = email['text']
402 const to = email['to'].filter(t => t.address === toEmail)
403
404 return text.indexOf(message) !== -1 && to.length !== 0
405 }
406
407 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
408}
409
410async function checkAbuseStateChange (options: CheckerBaseParams & {
411 abuseId: number
412 state: AbuseState
413 checkType: CheckerType
414}) {
415 const { abuseId, state } = options
416 const notificationType = UserNotificationType.ABUSE_STATE_CHANGE
417
418 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
419 if (checkType === 'presence') {
420 expect(notification).to.not.be.undefined
421 expect(notification.type).to.equal(notificationType)
422
423 expect(notification.abuse.id).to.equal(abuseId)
424 expect(notification.abuse.state).to.equal(state)
425 } else {
426 expect(notification).to.satisfy((n: UserNotification) => {
427 return n === undefined || n.abuse === undefined || n.abuse.id !== abuseId
428 })
429 }
430 }
431
432 function emailNotificationFinder (email: object) {
433 const text = email['text']
434
435 const contains = state === AbuseState.ACCEPTED
436 ? ' accepted'
437 : ' rejected'
438
439 return text.indexOf(contains) !== -1
440 }
441
442 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
443}
444
445async function checkNewCommentAbuseForModerators (options: CheckerBaseParams & {
446 shortUUID: string
447 videoName: string
448 checkType: CheckerType
449}) {
450 const { shortUUID, videoName } = options
451 const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
452
453 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
454 if (checkType === 'presence') {
455 expect(notification).to.not.be.undefined
456 expect(notification.type).to.equal(notificationType)
457
458 expect(notification.abuse.id).to.be.a('number')
459 checkVideo(notification.abuse.comment.video, videoName, shortUUID)
460 } else {
461 expect(notification).to.satisfy((n: UserNotification) => {
462 return n === undefined || n.abuse === undefined || n.abuse.comment.video.shortUUID !== shortUUID
463 })
464 }
465 }
466
467 function emailNotificationFinder (email: object) {
468 const text = email['text']
469 return text.indexOf(shortUUID) !== -1 && text.indexOf('abuse') !== -1
470 }
471
472 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
473}
474
475async function checkNewAccountAbuseForModerators (options: CheckerBaseParams & {
476 displayName: string
477 checkType: CheckerType
478}) {
479 const { displayName } = options
480 const notificationType = UserNotificationType.NEW_ABUSE_FOR_MODERATORS
481
482 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
483 if (checkType === 'presence') {
484 expect(notification).to.not.be.undefined
485 expect(notification.type).to.equal(notificationType)
486
487 expect(notification.abuse.id).to.be.a('number')
488 expect(notification.abuse.account.displayName).to.equal(displayName)
489 } else {
490 expect(notification).to.satisfy((n: UserNotification) => {
491 return n === undefined || n.abuse === undefined || n.abuse.account.displayName !== displayName
492 })
493 }
494 }
495
496 function emailNotificationFinder (email: object) {
497 const text = email['text']
498 return text.indexOf(displayName) !== -1 && text.indexOf('abuse') !== -1
499 }
500
501 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
502}
503
504async function checkVideoAutoBlacklistForModerators (options: CheckerBaseParams & {
505 shortUUID: string
506 videoName: string
507 checkType: CheckerType
508}) {
509 const { shortUUID, videoName } = options
510 const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS
511
512 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
513 if (checkType === 'presence') {
514 expect(notification).to.not.be.undefined
515 expect(notification.type).to.equal(notificationType)
516
517 expect(notification.videoBlacklist.video.id).to.be.a('number')
518 checkVideo(notification.videoBlacklist.video, videoName, shortUUID)
519 } else {
520 expect(notification).to.satisfy((n: UserNotification) => {
521 return n === undefined || n.video === undefined || n.video.shortUUID !== shortUUID
522 })
523 }
524 }
525
526 function emailNotificationFinder (email: object) {
527 const text = email['text']
528 return text.indexOf(shortUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1
529 }
530
531 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
532}
533
534async function checkNewBlacklistOnMyVideo (options: CheckerBaseParams & {
535 shortUUID: string
536 videoName: string
537 blacklistType: 'blacklist' | 'unblacklist'
538}) {
539 const { videoName, shortUUID, blacklistType } = options
540 const notificationType = blacklistType === 'blacklist'
541 ? UserNotificationType.BLACKLIST_ON_MY_VIDEO
542 : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO
543
544 function notificationChecker (notification: UserNotification) {
545 expect(notification).to.not.be.undefined
546 expect(notification.type).to.equal(notificationType)
547
548 const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video
549
550 checkVideo(video, videoName, shortUUID)
551 }
552
553 function emailNotificationFinder (email: object) {
554 const text = email['text']
555 const blacklistText = blacklistType === 'blacklist'
556 ? 'blacklisted'
557 : 'unblacklisted'
558
559 return text.includes(shortUUID) && text.includes(blacklistText)
560 }
561
562 await checkNotification({ ...options, notificationChecker, emailNotificationFinder, checkType: 'presence' })
563}
564
565async function checkNewPeerTubeVersion (options: CheckerBaseParams & {
566 latestVersion: string
567 checkType: CheckerType
568}) {
569 const { latestVersion } = options
570 const notificationType = UserNotificationType.NEW_PEERTUBE_VERSION
571
572 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
573 if (checkType === 'presence') {
574 expect(notification).to.not.be.undefined
575 expect(notification.type).to.equal(notificationType)
576
577 expect(notification.peertube).to.exist
578 expect(notification.peertube.latestVersion).to.equal(latestVersion)
579 } else {
580 expect(notification).to.satisfy((n: UserNotification) => {
581 return n === undefined || n.peertube === undefined || n.peertube.latestVersion !== latestVersion
582 })
583 }
584 }
585
586 function emailNotificationFinder (email: object) {
587 const text = email['text']
588
589 return text.includes(latestVersion)
590 }
591
592 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
593}
594
595async function checkNewPluginVersion (options: CheckerBaseParams & {
596 pluginType: PluginType
597 pluginName: string
598 checkType: CheckerType
599}) {
600 const { pluginName, pluginType } = options
601 const notificationType = UserNotificationType.NEW_PLUGIN_VERSION
602
603 function notificationChecker (notification: UserNotification, checkType: CheckerType) {
604 if (checkType === 'presence') {
605 expect(notification).to.not.be.undefined
606 expect(notification.type).to.equal(notificationType)
607
608 expect(notification.plugin.name).to.equal(pluginName)
609 expect(notification.plugin.type).to.equal(pluginType)
610 } else {
611 expect(notification).to.satisfy((n: UserNotification) => {
612 return n === undefined || n.plugin === undefined || n.plugin.name !== pluginName
613 })
614 }
615 }
616
617 function emailNotificationFinder (email: object) {
618 const text = email['text']
619
620 return text.includes(pluginName)
621 }
622
623 await checkNotification({ ...options, notificationChecker, emailNotificationFinder })
624}
625
626async function prepareNotificationsTest (serversCount = 3, overrideConfigArg: any = {}) {
627 const userNotifications: UserNotification[] = []
628 const adminNotifications: UserNotification[] = []
629 const adminNotificationsServer2: UserNotification[] = []
630 const emails: object[] = []
631
632 const port = await MockSmtpServer.Instance.collectEmails(emails)
633
634 const overrideConfig = {
635 smtp: {
636 hostname: 'localhost',
637 port
638 },
639 signup: {
640 limit: 20
641 }
642 }
643 const servers = await createMultipleServers(serversCount, Object.assign(overrideConfig, overrideConfigArg))
644
645 await setAccessTokensToServers(servers)
646
647 if (serversCount > 1) {
648 await doubleFollow(servers[0], servers[1])
649 }
650
651 const user = { username: 'user_1', password: 'super password' }
652 await servers[0].users.create({ ...user, videoQuota: 10 * 1000 * 1000 })
653 const userAccessToken = await servers[0].login.getAccessToken(user)
654
655 await servers[0].notifications.updateMySettings({ token: userAccessToken, settings: getAllNotificationsSettings() })
656 await servers[0].notifications.updateMySettings({ settings: getAllNotificationsSettings() })
657
658 if (serversCount > 1) {
659 await servers[1].notifications.updateMySettings({ settings: getAllNotificationsSettings() })
660 }
661
662 {
663 const socket = servers[0].socketIO.getUserNotificationSocket({ token: userAccessToken })
664 socket.on('new-notification', n => userNotifications.push(n))
665 }
666 {
667 const socket = servers[0].socketIO.getUserNotificationSocket()
668 socket.on('new-notification', n => adminNotifications.push(n))
669 }
670
671 if (serversCount > 1) {
672 const socket = servers[1].socketIO.getUserNotificationSocket()
673 socket.on('new-notification', n => adminNotificationsServer2.push(n))
674 }
675
676 const { videoChannels } = await servers[0].users.getMyInfo()
677 const channelId = videoChannels[0].id
678
679 return {
680 userNotifications,
681 adminNotifications,
682 adminNotificationsServer2,
683 userAccessToken,
684 emails,
685 servers,
686 channelId
687 }
688}
689
690// ---------------------------------------------------------------------------
691
692export {
693 getAllNotificationsSettings,
694
695 CheckerBaseParams,
696 CheckerType,
697 checkMyVideoImportIsFinished,
698 checkUserRegistered,
699 checkAutoInstanceFollowing,
700 checkVideoIsPublished,
701 checkNewVideoFromSubscription,
702 checkNewActorFollow,
703 checkNewCommentOnMyVideo,
704 checkNewBlacklistOnMyVideo,
705 checkCommentMention,
706 checkNewVideoAbuseForModerators,
707 checkVideoAutoBlacklistForModerators,
708 checkNewAbuseMessage,
709 checkAbuseStateChange,
710 checkNewInstanceFollower,
711 prepareNotificationsTest,
712 checkNewCommentAbuseForModerators,
713 checkNewAccountAbuseForModerators,
714 checkNewPeerTubeVersion,
715 checkNewPluginVersion
716}
717
718// ---------------------------------------------------------------------------
719
720async function checkNotification (options: CheckerBaseParams & {
721 notificationChecker: (notification: UserNotification, checkType: CheckerType) => void
722 emailNotificationFinder: (email: object) => boolean
723 checkType: CheckerType
724}) {
725 const { server, token, checkType, notificationChecker, emailNotificationFinder, socketNotifications, emails } = options
726
727 const check = options.check || { web: true, mail: true }
728
729 if (check.web) {
730 const notification = await server.notifications.getLatest({ token: token })
731
732 if (notification || checkType !== 'absence') {
733 notificationChecker(notification, checkType)
734 }
735
736 const socketNotification = socketNotifications.find(n => {
737 try {
738 notificationChecker(n, 'presence')
739 return true
740 } catch {
741 return false
742 }
743 })
744
745 if (checkType === 'presence') {
746 const obj = inspect(socketNotifications, { depth: 5 })
747 expect(socketNotification, 'The socket notification is absent when it should be present. ' + obj).to.not.be.undefined
748 } else {
749 const obj = inspect(socketNotification, { depth: 5 })
750 expect(socketNotification, 'The socket notification is present when it should not be present. ' + obj).to.be.undefined
751 }
752 }
753
754 if (check.mail) {
755 // Last email
756 const email = emails
757 .slice()
758 .reverse()
759 .find(e => emailNotificationFinder(e))
760
761 if (checkType === 'presence') {
762 const texts = emails.map(e => e.text)
763 expect(email, 'The email is absent when is should be present. ' + inspect(texts)).to.not.be.undefined
764 } else {
765 expect(email, 'The email is present when is should not be present. ' + inspect(email)).to.be.undefined
766 }
767 }
768}
769
770function checkVideo (video: any, videoName?: string, shortUUID?: string) {
771 if (videoName) {
772 expect(video.name).to.be.a('string')
773 expect(video.name).to.not.be.empty
774 expect(video.name).to.equal(videoName)
775 }
776
777 if (shortUUID) {
778 expect(video.shortUUID).to.be.a('string')
779 expect(video.shortUUID).to.not.be.empty
780 expect(video.shortUUID).to.equal(shortUUID)
781 }
782
783 expect(video.id).to.be.a('number')
784}
785
786function checkActor (actor: any) {
787 expect(actor.displayName).to.be.a('string')
788 expect(actor.displayName).to.not.be.empty
789 expect(actor.host).to.not.be.undefined
790}
791
792function checkComment (comment: any, commentId: number, threadId: number) {
793 expect(comment.id).to.equal(commentId)
794 expect(comment.threadId).to.equal(threadId)
795}
diff --git a/shared/server-commands/users/users-command.ts b/shared/server-commands/users/users-command.ts
index 90c5f2183..b5ae9008e 100644
--- a/shared/server-commands/users/users-command.ts
+++ b/shared/server-commands/users/users-command.ts
@@ -4,6 +4,7 @@ import {
4 HttpStatusCode, 4 HttpStatusCode,
5 MyUser, 5 MyUser,
6 ResultList, 6 ResultList,
7 ScopedToken,
7 User, 8 User,
8 UserAdminFlag, 9 UserAdminFlag,
9 UserCreateResult, 10 UserCreateResult,
@@ -13,7 +14,6 @@ import {
13 UserVideoQuota, 14 UserVideoQuota,
14 UserVideoRate 15 UserVideoRate
15} from '@shared/models' 16} from '@shared/models'
16import { ScopedToken } from '@shared/models/users/user-scoped-token'
17import { unwrapBody } from '../requests' 17import { unwrapBody } from '../requests'
18import { AbstractCommand, OverrideCommandOptions } from '../shared' 18import { AbstractCommand, OverrideCommandOptions } from '../shared'
19 19