]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/tests/api/notifications/moderation-notifications.ts
Introduce blacklist command
[github/Chocobozzz/PeerTube.git] / server / tests / api / notifications / moderation-notifications.ts
1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3 import 'mocha'
4 import { buildUUID } from '@server/helpers/uuid'
5 import {
6 addVideoCommentThread,
7 checkAbuseStateChange,
8 checkAutoInstanceFollowing,
9 CheckerBaseParams,
10 checkNewAbuseMessage,
11 checkNewAccountAbuseForModerators,
12 checkNewBlacklistOnMyVideo,
13 checkNewCommentAbuseForModerators,
14 checkNewInstanceFollower,
15 checkNewVideoAbuseForModerators,
16 checkNewVideoFromSubscription,
17 checkUserRegistered,
18 checkVideoAutoBlacklistForModerators,
19 checkVideoIsPublished,
20 cleanupTests,
21 createUser,
22 generateUserAccessToken,
23 getVideoCommentThreads,
24 getVideoIdFromUUID,
25 immutableAssign,
26 MockInstancesIndex,
27 MockSmtpServer,
28 prepareNotificationsTest,
29 registerUser,
30 ServerInfo,
31 uploadVideo,
32 wait,
33 waitJobs
34 } from '@shared/extra-utils'
35 import { AbuseState, CustomConfig, UserNotification, VideoPrivacy } from '@shared/models'
36
37 describe('Test moderation notifications', function () {
38 let servers: ServerInfo[] = []
39 let userAccessToken: string
40 let userNotifications: UserNotification[] = []
41 let adminNotifications: UserNotification[] = []
42 let adminNotificationsServer2: UserNotification[] = []
43 let emails: object[] = []
44
45 before(async function () {
46 this.timeout(120000)
47
48 const res = await prepareNotificationsTest(3)
49 emails = res.emails
50 userAccessToken = res.userAccessToken
51 servers = res.servers
52 userNotifications = res.userNotifications
53 adminNotifications = res.adminNotifications
54 adminNotificationsServer2 = res.adminNotificationsServer2
55 })
56
57 describe('Abuse for moderators notification', function () {
58 let baseParams: CheckerBaseParams
59
60 before(() => {
61 baseParams = {
62 server: servers[0],
63 emails,
64 socketNotifications: adminNotifications,
65 token: servers[0].accessToken
66 }
67 })
68
69 it('Should send a notification to moderators on local video abuse', async function () {
70 this.timeout(20000)
71
72 const name = 'video for abuse ' + buildUUID()
73 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
74 const video = resVideo.body.video
75
76 await servers[0].abusesCommand.report({ videoId: video.id, reason: 'super reason' })
77
78 await waitJobs(servers)
79 await checkNewVideoAbuseForModerators(baseParams, video.uuid, name, 'presence')
80 })
81
82 it('Should send a notification to moderators on remote video abuse', async function () {
83 this.timeout(20000)
84
85 const name = 'video for abuse ' + buildUUID()
86 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
87 const video = resVideo.body.video
88
89 await waitJobs(servers)
90
91 const videoId = await getVideoIdFromUUID(servers[1].url, video.uuid)
92 await servers[1].abusesCommand.report({ videoId, reason: 'super reason' })
93
94 await waitJobs(servers)
95 await checkNewVideoAbuseForModerators(baseParams, video.uuid, name, 'presence')
96 })
97
98 it('Should send a notification to moderators on local comment abuse', async function () {
99 this.timeout(20000)
100
101 const name = 'video for abuse ' + buildUUID()
102 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
103 const video = resVideo.body.video
104 const resComment = await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + buildUUID())
105 const comment = resComment.body.comment
106
107 await waitJobs(servers)
108
109 await servers[0].abusesCommand.report({ commentId: comment.id, reason: 'super reason' })
110
111 await waitJobs(servers)
112 await checkNewCommentAbuseForModerators(baseParams, video.uuid, name, 'presence')
113 })
114
115 it('Should send a notification to moderators on remote comment abuse', async function () {
116 this.timeout(20000)
117
118 const name = 'video for abuse ' + buildUUID()
119 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
120 const video = resVideo.body.video
121 await addVideoCommentThread(servers[0].url, userAccessToken, video.id, 'comment abuse ' + buildUUID())
122
123 await waitJobs(servers)
124
125 const resComments = await getVideoCommentThreads(servers[1].url, video.uuid, 0, 5)
126 const commentId = resComments.body.data[0].id
127 await servers[1].abusesCommand.report({ commentId, reason: 'super reason' })
128
129 await waitJobs(servers)
130 await checkNewCommentAbuseForModerators(baseParams, video.uuid, name, 'presence')
131 })
132
133 it('Should send a notification to moderators on local account abuse', async function () {
134 this.timeout(20000)
135
136 const username = 'user' + new Date().getTime()
137 const resUser = await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username, password: 'donald' })
138 const accountId = resUser.body.user.account.id
139
140 await servers[0].abusesCommand.report({ accountId, reason: 'super reason' })
141
142 await waitJobs(servers)
143 await checkNewAccountAbuseForModerators(baseParams, username, 'presence')
144 })
145
146 it('Should send a notification to moderators on remote account abuse', async function () {
147 this.timeout(20000)
148
149 const username = 'user' + new Date().getTime()
150 const tmpToken = await generateUserAccessToken(servers[0], username)
151 await uploadVideo(servers[0].url, tmpToken, { name: 'super video' })
152
153 await waitJobs(servers)
154
155 const account = await servers[1].accountsCommand.get({ accountName: username + '@' + servers[0].host })
156 await servers[1].abusesCommand.report({ accountId: account.id, reason: 'super reason' })
157
158 await waitJobs(servers)
159 await checkNewAccountAbuseForModerators(baseParams, username, 'presence')
160 })
161 })
162
163 describe('Abuse state change notification', function () {
164 let baseParams: CheckerBaseParams
165 let abuseId: number
166
167 before(async function () {
168 baseParams = {
169 server: servers[0],
170 emails,
171 socketNotifications: userNotifications,
172 token: userAccessToken
173 }
174
175 const name = 'abuse ' + buildUUID()
176 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
177 const video = resVideo.body.video
178
179 const body = await servers[0].abusesCommand.report({ token: userAccessToken, videoId: video.id, reason: 'super reason' })
180 abuseId = body.abuse.id
181 })
182
183 it('Should send a notification to reporter if the abuse has been accepted', async function () {
184 this.timeout(10000)
185
186 await servers[0].abusesCommand.update({ abuseId, body: { state: AbuseState.ACCEPTED } })
187 await waitJobs(servers)
188
189 await checkAbuseStateChange(baseParams, abuseId, AbuseState.ACCEPTED, 'presence')
190 })
191
192 it('Should send a notification to reporter if the abuse has been rejected', async function () {
193 this.timeout(10000)
194
195 await servers[0].abusesCommand.update({ abuseId, body: { state: AbuseState.REJECTED } })
196 await waitJobs(servers)
197
198 await checkAbuseStateChange(baseParams, abuseId, AbuseState.REJECTED, 'presence')
199 })
200 })
201
202 describe('New abuse message notification', function () {
203 let baseParamsUser: CheckerBaseParams
204 let baseParamsAdmin: CheckerBaseParams
205 let abuseId: number
206 let abuseId2: number
207
208 before(async function () {
209 baseParamsUser = {
210 server: servers[0],
211 emails,
212 socketNotifications: userNotifications,
213 token: userAccessToken
214 }
215
216 baseParamsAdmin = {
217 server: servers[0],
218 emails,
219 socketNotifications: adminNotifications,
220 token: servers[0].accessToken
221 }
222
223 const name = 'abuse ' + buildUUID()
224 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
225 const video = resVideo.body.video
226
227 {
228 const body = await servers[0].abusesCommand.report({ token: userAccessToken, videoId: video.id, reason: 'super reason' })
229 abuseId = body.abuse.id
230 }
231
232 {
233 const body = await servers[0].abusesCommand.report({ token: userAccessToken, videoId: video.id, reason: 'super reason 2' })
234 abuseId2 = body.abuse.id
235 }
236 })
237
238 it('Should send a notification to reporter on new message', async function () {
239 this.timeout(10000)
240
241 const message = 'my super message to users'
242 await servers[0].abusesCommand.addMessage({ abuseId, message })
243 await waitJobs(servers)
244
245 await checkNewAbuseMessage(baseParamsUser, abuseId, message, 'user_1@example.com', 'presence')
246 })
247
248 it('Should not send a notification to the admin if sent by the admin', async function () {
249 this.timeout(10000)
250
251 const message = 'my super message that should not be sent to the admin'
252 await servers[0].abusesCommand.addMessage({ abuseId, message })
253 await waitJobs(servers)
254
255 await checkNewAbuseMessage(baseParamsAdmin, abuseId, message, 'admin' + servers[0].internalServerNumber + '@example.com', 'absence')
256 })
257
258 it('Should send a notification to moderators', async function () {
259 this.timeout(10000)
260
261 const message = 'my super message to moderators'
262 await servers[0].abusesCommand.addMessage({ token: userAccessToken, abuseId: abuseId2, message })
263 await waitJobs(servers)
264
265 await checkNewAbuseMessage(baseParamsAdmin, abuseId2, message, 'admin' + servers[0].internalServerNumber + '@example.com', 'presence')
266 })
267
268 it('Should not send a notification to reporter if sent by the reporter', async function () {
269 this.timeout(10000)
270
271 const message = 'my super message that should not be sent to reporter'
272 await servers[0].abusesCommand.addMessage({ token: userAccessToken, abuseId: abuseId2, message })
273 await waitJobs(servers)
274
275 await checkNewAbuseMessage(baseParamsUser, abuseId2, message, 'user_1@example.com', 'absence')
276 })
277 })
278
279 describe('Video blacklist on my video', function () {
280 let baseParams: CheckerBaseParams
281
282 before(() => {
283 baseParams = {
284 server: servers[0],
285 emails,
286 socketNotifications: userNotifications,
287 token: userAccessToken
288 }
289 })
290
291 it('Should send a notification to video owner on blacklist', async function () {
292 this.timeout(10000)
293
294 const name = 'video for abuse ' + buildUUID()
295 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
296 const uuid = resVideo.body.video.uuid
297
298 await servers[0].blacklistCommand.add({ videoId: uuid })
299
300 await waitJobs(servers)
301 await checkNewBlacklistOnMyVideo(baseParams, uuid, name, 'blacklist')
302 })
303
304 it('Should send a notification to video owner on unblacklist', async function () {
305 this.timeout(10000)
306
307 const name = 'video for abuse ' + buildUUID()
308 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name })
309 const uuid = resVideo.body.video.uuid
310
311 await servers[0].blacklistCommand.add({ videoId: uuid })
312
313 await waitJobs(servers)
314 await servers[0].blacklistCommand.remove({ videoId: uuid })
315 await waitJobs(servers)
316
317 await wait(500)
318 await checkNewBlacklistOnMyVideo(baseParams, uuid, name, 'unblacklist')
319 })
320 })
321
322 describe('New registration', function () {
323 let baseParams: CheckerBaseParams
324
325 before(() => {
326 baseParams = {
327 server: servers[0],
328 emails,
329 socketNotifications: adminNotifications,
330 token: servers[0].accessToken
331 }
332 })
333
334 it('Should send a notification only to moderators when a user registers on the instance', async function () {
335 this.timeout(10000)
336
337 await registerUser(servers[0].url, 'user_45', 'password')
338
339 await waitJobs(servers)
340
341 await checkUserRegistered(baseParams, 'user_45', 'presence')
342
343 const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } }
344 await checkUserRegistered(immutableAssign(baseParams, userOverride), 'user_45', 'absence')
345 })
346 })
347
348 describe('New instance follows', function () {
349 const instanceIndexServer = new MockInstancesIndex()
350 let config: any
351 let baseParams: CheckerBaseParams
352
353 before(async () => {
354 baseParams = {
355 server: servers[0],
356 emails,
357 socketNotifications: adminNotifications,
358 token: servers[0].accessToken
359 }
360
361 const port = await instanceIndexServer.initialize()
362 instanceIndexServer.addInstance(servers[1].host)
363
364 config = {
365 followings: {
366 instance: {
367 autoFollowIndex: {
368 indexUrl: `http://localhost:${port}/api/v1/instances/hosts`,
369 enabled: true
370 }
371 }
372 }
373 }
374 })
375
376 it('Should send a notification only to admin when there is a new instance follower', async function () {
377 this.timeout(20000)
378
379 await servers[2].followsCommand.follow({ targets: [ servers[0].url ] })
380
381 await waitJobs(servers)
382
383 await checkNewInstanceFollower(baseParams, 'localhost:' + servers[2].port, 'presence')
384
385 const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } }
386 await checkNewInstanceFollower(immutableAssign(baseParams, userOverride), 'localhost:' + servers[2].port, 'absence')
387 })
388
389 it('Should send a notification on auto follow back', async function () {
390 this.timeout(40000)
391
392 await servers[2].followsCommand.unfollow({ target: servers[0] })
393 await waitJobs(servers)
394
395 const config = {
396 followings: {
397 instance: {
398 autoFollowBack: { enabled: true }
399 }
400 }
401 }
402 await servers[0].configCommand.updateCustomSubConfig({ newConfig: config })
403
404 await servers[2].followsCommand.follow({ targets: [ servers[0].url ] })
405
406 await waitJobs(servers)
407
408 const followerHost = servers[0].host
409 const followingHost = servers[2].host
410 await checkAutoInstanceFollowing(baseParams, followerHost, followingHost, 'presence')
411
412 const userOverride = { socketNotifications: userNotifications, token: userAccessToken, check: { web: true, mail: false } }
413 await checkAutoInstanceFollowing(immutableAssign(baseParams, userOverride), followerHost, followingHost, 'absence')
414
415 config.followings.instance.autoFollowBack.enabled = false
416 await servers[0].configCommand.updateCustomSubConfig({ newConfig: config })
417 await servers[0].followsCommand.unfollow({ target: servers[2] })
418 await servers[2].followsCommand.unfollow({ target: servers[0] })
419 })
420
421 it('Should send a notification on auto instances index follow', async function () {
422 this.timeout(30000)
423 await servers[0].followsCommand.unfollow({ target: servers[1] })
424
425 await servers[0].configCommand.updateCustomSubConfig({ newConfig: config })
426
427 await wait(5000)
428 await waitJobs(servers)
429
430 const followerHost = servers[0].host
431 const followingHost = servers[1].host
432 await checkAutoInstanceFollowing(baseParams, followerHost, followingHost, 'presence')
433
434 config.followings.instance.autoFollowIndex.enabled = false
435 await servers[0].configCommand.updateCustomSubConfig({ newConfig: config })
436 await servers[0].followsCommand.unfollow({ target: servers[1] })
437 })
438 })
439
440 describe('Video-related notifications when video auto-blacklist is enabled', function () {
441 let userBaseParams: CheckerBaseParams
442 let adminBaseParamsServer1: CheckerBaseParams
443 let adminBaseParamsServer2: CheckerBaseParams
444 let videoUUID: string
445 let videoName: string
446 let currentCustomConfig: CustomConfig
447
448 before(async () => {
449
450 adminBaseParamsServer1 = {
451 server: servers[0],
452 emails,
453 socketNotifications: adminNotifications,
454 token: servers[0].accessToken
455 }
456
457 adminBaseParamsServer2 = {
458 server: servers[1],
459 emails,
460 socketNotifications: adminNotificationsServer2,
461 token: servers[1].accessToken
462 }
463
464 userBaseParams = {
465 server: servers[0],
466 emails,
467 socketNotifications: userNotifications,
468 token: userAccessToken
469 }
470
471 currentCustomConfig = await servers[0].configCommand.getCustomConfig()
472
473 const autoBlacklistTestsCustomConfig = immutableAssign(currentCustomConfig, {
474 autoBlacklist: {
475 videos: {
476 ofUsers: {
477 enabled: true
478 }
479 }
480 }
481 })
482
483 // enable transcoding otherwise own publish notification after transcoding not expected
484 autoBlacklistTestsCustomConfig.transcoding.enabled = true
485 await servers[0].configCommand.updateCustomConfig({ newCustomConfig: autoBlacklistTestsCustomConfig })
486
487 await servers[0].subscriptionsCommand.add({ targetUri: 'user_1_channel@localhost:' + servers[0].port })
488 await servers[1].subscriptionsCommand.add({ targetUri: 'user_1_channel@localhost:' + servers[0].port })
489
490 })
491
492 it('Should send notification to moderators on new video with auto-blacklist', async function () {
493 this.timeout(40000)
494
495 videoName = 'video with auto-blacklist ' + buildUUID()
496 const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: videoName })
497 videoUUID = resVideo.body.video.uuid
498
499 await waitJobs(servers)
500 await checkVideoAutoBlacklistForModerators(adminBaseParamsServer1, videoUUID, videoName, 'presence')
501 })
502
503 it('Should not send video publish notification if auto-blacklisted', async function () {
504 await checkVideoIsPublished(userBaseParams, videoName, videoUUID, 'absence')
505 })
506
507 it('Should not send a local user subscription notification if auto-blacklisted', async function () {
508 await checkNewVideoFromSubscription(adminBaseParamsServer1, videoName, videoUUID, 'absence')
509 })
510
511 it('Should not send a remote user subscription notification if auto-blacklisted', async function () {
512 await checkNewVideoFromSubscription(adminBaseParamsServer2, videoName, videoUUID, 'absence')
513 })
514
515 it('Should send video published and unblacklist after video unblacklisted', async function () {
516 this.timeout(40000)
517
518 await servers[0].blacklistCommand.remove({ videoId: videoUUID })
519
520 await waitJobs(servers)
521
522 // FIXME: Can't test as two notifications sent to same user and util only checks last one
523 // One notification might be better anyways
524 // await checkNewBlacklistOnMyVideo(userBaseParams, videoUUID, videoName, 'unblacklist')
525 // await checkVideoIsPublished(userBaseParams, videoName, videoUUID, 'presence')
526 })
527
528 it('Should send a local user subscription notification after removed from blacklist', async function () {
529 await checkNewVideoFromSubscription(adminBaseParamsServer1, videoName, videoUUID, 'presence')
530 })
531
532 it('Should send a remote user subscription notification after removed from blacklist', async function () {
533 await checkNewVideoFromSubscription(adminBaseParamsServer2, videoName, videoUUID, 'presence')
534 })
535
536 it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () {
537 this.timeout(40000)
538
539 const updateAt = new Date(new Date().getTime() + 1000000)
540
541 const name = 'video with auto-blacklist and future schedule ' + buildUUID()
542
543 const data = {
544 name,
545 privacy: VideoPrivacy.PRIVATE,
546 scheduleUpdate: {
547 updateAt: updateAt.toISOString(),
548 privacy: VideoPrivacy.PUBLIC
549 }
550 }
551
552 const resVideo = await uploadVideo(servers[0].url, userAccessToken, data)
553 const uuid = resVideo.body.video.uuid
554
555 await servers[0].blacklistCommand.remove({ videoId: uuid })
556
557 await waitJobs(servers)
558 await checkNewBlacklistOnMyVideo(userBaseParams, uuid, name, 'unblacklist')
559
560 // FIXME: Can't test absence as two notifications sent to same user and util only checks last one
561 // One notification might be better anyways
562 // await checkVideoIsPublished(userBaseParams, name, uuid, 'absence')
563
564 await checkNewVideoFromSubscription(adminBaseParamsServer1, name, uuid, 'absence')
565 await checkNewVideoFromSubscription(adminBaseParamsServer2, name, uuid, 'absence')
566 })
567
568 it('Should not send publish/subscription notifications after scheduled update if video still auto-blacklisted', async function () {
569 this.timeout(40000)
570
571 // In 2 seconds
572 const updateAt = new Date(new Date().getTime() + 2000)
573
574 const name = 'video with schedule done and still auto-blacklisted ' + buildUUID()
575
576 const data = {
577 name,
578 privacy: VideoPrivacy.PRIVATE,
579 scheduleUpdate: {
580 updateAt: updateAt.toISOString(),
581 privacy: VideoPrivacy.PUBLIC
582 }
583 }
584
585 const resVideo = await uploadVideo(servers[0].url, userAccessToken, data)
586 const uuid = resVideo.body.video.uuid
587
588 await wait(6000)
589 await checkVideoIsPublished(userBaseParams, name, uuid, 'absence')
590 await checkNewVideoFromSubscription(adminBaseParamsServer1, name, uuid, 'absence')
591 await checkNewVideoFromSubscription(adminBaseParamsServer2, name, uuid, 'absence')
592 })
593
594 it('Should not send a notification to moderators on new video without auto-blacklist', async function () {
595 this.timeout(60000)
596
597 const name = 'video without auto-blacklist ' + buildUUID()
598
599 // admin with blacklist right will not be auto-blacklisted
600 const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name })
601 const uuid = resVideo.body.video.uuid
602
603 await waitJobs(servers)
604 await checkVideoAutoBlacklistForModerators(adminBaseParamsServer1, uuid, name, 'absence')
605 })
606
607 after(async () => {
608 await servers[0].configCommand.updateCustomConfig({ newCustomConfig: currentCustomConfig })
609
610 await servers[0].subscriptionsCommand.remove({ uri: 'user_1_channel@localhost:' + servers[0].port })
611 await servers[1].subscriptionsCommand.remove({ uri: 'user_1_channel@localhost:' + servers[0].port })
612 })
613 })
614
615 after(async function () {
616 MockSmtpServer.Instance.kill()
617
618 await cleanupTests(servers)
619 })
620 })