aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/users/blocklist.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-05-22 17:06:26 +0200
committerChocobozzz <chocobozzz@cpy.re>2020-05-29 09:32:20 +0200
commit696d83fd1377486dd03cc1bd02a21d9b6ddd9fcd (patch)
treee1b88451c4357add80721f530993e2b48d197feb /server/tests/api/users/blocklist.ts
parent72c33e716fecd1826dcf645957f8669821f91ff3 (diff)
downloadPeerTube-696d83fd1377486dd03cc1bd02a21d9b6ddd9fcd.tar.gz
PeerTube-696d83fd1377486dd03cc1bd02a21d9b6ddd9fcd.tar.zst
PeerTube-696d83fd1377486dd03cc1bd02a21d9b6ddd9fcd.zip
Block comments from muted accounts/servers
Add better control for users of comments displayed on their videos: * Do not forward comments from muted remote accounts/servers (muted by the current server or by the video owner) * Do not list threads and hide replies (with their children) of accounts/servers muted by the video owner * Hide from RSS comments of muted accounts/servers by video owners Use case: * Try to limit spam propagation in the federation * Add ability for users to automatically hide comments on their videos from undesirable accounts/servers (the comment section belongs to videomakers, so they choose what's posted there)
Diffstat (limited to 'server/tests/api/users/blocklist.ts')
-rw-r--r--server/tests/api/users/blocklist.ts170
1 files changed, 147 insertions, 23 deletions
diff --git a/server/tests/api/users/blocklist.ts b/server/tests/api/users/blocklist.ts
index e37dbb5a4..8c9107a50 100644
--- a/server/tests/api/users/blocklist.ts
+++ b/server/tests/api/users/blocklist.ts
@@ -2,7 +2,7 @@
2 2
3import * as chai from 'chai' 3import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { AccountBlock, ServerBlock, Video } from '../../../../shared/index' 5import { AccountBlock, ServerBlock, Video, UserNotification, UserNotificationType } from '../../../../shared/index'
6import { 6import {
7 cleanupTests, 7 cleanupTests,
8 createUser, 8 createUser,
@@ -11,7 +11,9 @@ import {
11 flushAndRunMultipleServers, 11 flushAndRunMultipleServers,
12 ServerInfo, 12 ServerInfo,
13 uploadVideo, 13 uploadVideo,
14 userLogin 14 userLogin,
15 follow,
16 unfollow
15} from '../../../../shared/extra-utils/index' 17} from '../../../../shared/extra-utils/index'
16import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login' 18import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
17import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos' 19import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos'
@@ -19,7 +21,8 @@ import {
19 addVideoCommentReply, 21 addVideoCommentReply,
20 addVideoCommentThread, 22 addVideoCommentThread,
21 getVideoCommentThreads, 23 getVideoCommentThreads,
22 getVideoThreadComments 24 getVideoThreadComments,
25 findCommentId
23} from '../../../../shared/extra-utils/videos/video-comments' 26} from '../../../../shared/extra-utils/videos/video-comments'
24import { waitJobs } from '../../../../shared/extra-utils/server/jobs' 27import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
25import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' 28import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
@@ -45,13 +48,13 @@ async function checkAllVideos (url: string, token: string) {
45 { 48 {
46 const res = await getVideosListWithToken(url, token) 49 const res = await getVideosListWithToken(url, token)
47 50
48 expect(res.body.data).to.have.lengthOf(4) 51 expect(res.body.data).to.have.lengthOf(5)
49 } 52 }
50 53
51 { 54 {
52 const res = await getVideosList(url) 55 const res = await getVideosList(url)
53 56
54 expect(res.body.data).to.have.lengthOf(4) 57 expect(res.body.data).to.have.lengthOf(5)
55 } 58 }
56} 59}
57 60
@@ -76,13 +79,15 @@ async function checkCommentNotification (
76 check: 'presence' | 'absence' 79 check: 'presence' | 'absence'
77) { 80) {
78 const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text) 81 const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text)
79 const threadId = resComment.body.comment.id 82 const created = resComment.body.comment as VideoComment
83 const threadId = created.id
84 const createdAt = created.createdAt
80 85
81 await waitJobs([ mainServer, comment.server ]) 86 await waitJobs([ mainServer, comment.server ])
82 87
83 const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30) 88 const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30)
84 const commentNotifications = res.body.data 89 const commentNotifications = (res.body.data as UserNotification[])
85 .filter(n => n.comment && n.comment.id === threadId) 90 .filter(n => n.comment && n.comment.video.uuid === comment.videoUUID && n.createdAt >= createdAt)
86 91
87 if (check === 'presence') expect(commentNotifications).to.have.lengthOf(1) 92 if (check === 'presence') expect(commentNotifications).to.have.lengthOf(1)
88 else expect(commentNotifications).to.have.lengthOf(0) 93 else expect(commentNotifications).to.have.lengthOf(0)
@@ -96,6 +101,7 @@ describe('Test blocklist', function () {
96 let servers: ServerInfo[] 101 let servers: ServerInfo[]
97 let videoUUID1: string 102 let videoUUID1: string
98 let videoUUID2: string 103 let videoUUID2: string
104 let videoUUID3: string
99 let userToken1: string 105 let userToken1: string
100 let userModeratorToken: string 106 let userModeratorToken: string
101 let userToken2: string 107 let userToken2: string
@@ -103,7 +109,7 @@ describe('Test blocklist', function () {
103 before(async function () { 109 before(async function () {
104 this.timeout(60000) 110 this.timeout(60000)
105 111
106 servers = await flushAndRunMultipleServers(2) 112 servers = await flushAndRunMultipleServers(3)
107 await setAccessTokensToServers(servers) 113 await setAccessTokensToServers(servers)
108 114
109 { 115 {
@@ -139,7 +145,13 @@ describe('Test blocklist', function () {
139 videoUUID2 = res.body.video.uuid 145 videoUUID2 = res.body.video.uuid
140 } 146 }
141 147
148 {
149 const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 2 server 1' })
150 videoUUID3 = res.body.video.uuid
151 }
152
142 await doubleFollow(servers[0], servers[1]) 153 await doubleFollow(servers[0], servers[1])
154 await doubleFollow(servers[0], servers[2])
143 155
144 { 156 {
145 const resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID1, 'comment root 1') 157 const resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID1, 'comment root 1')
@@ -174,7 +186,7 @@ describe('Test blocklist', function () {
174 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) 186 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
175 187
176 const videos: Video[] = res.body.data 188 const videos: Video[] = res.body.data
177 expect(videos).to.have.lengthOf(3) 189 expect(videos).to.have.lengthOf(4)
178 190
179 const v = videos.find(v => v.name === 'video user 2') 191 const v = videos.find(v => v.name === 'video user 2')
180 expect(v).to.be.undefined 192 expect(v).to.be.undefined
@@ -188,7 +200,7 @@ describe('Test blocklist', function () {
188 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) 200 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
189 201
190 const videos: Video[] = res.body.data 202 const videos: Video[] = res.body.data
191 expect(videos).to.have.lengthOf(2) 203 expect(videos).to.have.lengthOf(3)
192 204
193 const v = videos.find(v => v.name === 'video user 1') 205 const v = videos.find(v => v.name === 'video user 1')
194 expect(v).to.be.undefined 206 expect(v).to.be.undefined
@@ -235,10 +247,6 @@ describe('Test blocklist', function () {
235 return checkAllVideos(servers[0].url, userToken1) 247 return checkAllVideos(servers[0].url, userToken1)
236 }) 248 })
237 249
238 it('Should list all the comments with another user', async function () {
239 return checkAllComments(servers[0].url, userToken1, videoUUID1)
240 })
241
242 it('Should list blocked accounts', async function () { 250 it('Should list blocked accounts', async function () {
243 { 251 {
244 const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt') 252 const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
@@ -269,6 +277,61 @@ describe('Test blocklist', function () {
269 } 277 }
270 }) 278 })
271 279
280 it('Should not allow a remote blocked user to comment my videos', async function () {
281 this.timeout(60000)
282
283 {
284 await addVideoCommentThread(servers[1].url, userToken2, videoUUID3, 'comment user 2')
285 await waitJobs(servers)
286
287 await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID3, 'uploader')
288 await waitJobs(servers)
289
290 const commentId = await findCommentId(servers[1].url, videoUUID3, 'uploader')
291 const message = 'reply by user 2'
292 const resReply = await addVideoCommentReply(servers[1].url, userToken2, videoUUID3, commentId, message)
293 await addVideoCommentReply(servers[1].url, servers[1].accessToken, videoUUID3, resReply.body.comment.id, 'another reply')
294
295 await waitJobs(servers)
296 }
297
298 // Server 2 has all the comments
299 {
300 const resThreads = await getVideoCommentThreads(servers[1].url, videoUUID3, 0, 25, '-createdAt')
301 const threads: VideoComment[] = resThreads.body.data
302
303 expect(threads).to.have.lengthOf(2)
304 expect(threads[0].text).to.equal('uploader')
305 expect(threads[1].text).to.equal('comment user 2')
306
307 const resReplies = await getVideoThreadComments(servers[1].url, videoUUID3, threads[0].id)
308
309 const tree: VideoCommentThreadTree = resReplies.body
310 expect(tree.children).to.have.lengthOf(1)
311 expect(tree.children[0].comment.text).to.equal('reply by user 2')
312 expect(tree.children[0].children).to.have.lengthOf(1)
313 expect(tree.children[0].children[0].comment.text).to.equal('another reply')
314 }
315
316 // Server 1 and 3 should only have uploader comments
317 for (const server of [ servers[0], servers[2] ]) {
318 const resThreads = await getVideoCommentThreads(server.url, videoUUID3, 0, 25, '-createdAt')
319 const threads: VideoComment[] = resThreads.body.data
320
321 expect(threads).to.have.lengthOf(1)
322 expect(threads[0].text).to.equal('uploader')
323
324 const resReplies = await getVideoThreadComments(server.url, videoUUID3, threads[0].id)
325
326 const tree: VideoCommentThreadTree = resReplies.body
327 if (server.serverNumber === 1) {
328 expect(tree.children).to.have.lengthOf(0)
329 } else {
330 expect(tree.children).to.have.lengthOf(1)
331 }
332 }
333 })
334
272 it('Should unblock the remote account', async function () { 335 it('Should unblock the remote account', async function () {
273 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port) 336 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
274 }) 337 })
@@ -277,12 +340,37 @@ describe('Test blocklist', function () {
277 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) 340 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
278 341
279 const videos: Video[] = res.body.data 342 const videos: Video[] = res.body.data
280 expect(videos).to.have.lengthOf(3) 343 expect(videos).to.have.lengthOf(4)
281 344
282 const v = videos.find(v => v.name === 'video user 2') 345 const v = videos.find(v => v.name === 'video user 2')
283 expect(v).not.to.be.undefined 346 expect(v).not.to.be.undefined
284 }) 347 })
285 348
349 it('Should display its comments on my video', async function () {
350 for (const server of servers) {
351 const resThreads = await getVideoCommentThreads(server.url, videoUUID3, 0, 25, '-createdAt')
352 const threads: VideoComment[] = resThreads.body.data
353
354 // Server 3 should not have 2 comment threads, because server 1 did not forward the server 2 comment
355 if (server.serverNumber === 3) {
356 expect(threads).to.have.lengthOf(1)
357 continue
358 }
359
360 expect(threads).to.have.lengthOf(2)
361 expect(threads[0].text).to.equal('uploader')
362 expect(threads[1].text).to.equal('comment user 2')
363
364 const resReplies = await getVideoThreadComments(server.url, videoUUID3, threads[0].id)
365
366 const tree: VideoCommentThreadTree = resReplies.body
367 expect(tree.children).to.have.lengthOf(1)
368 expect(tree.children[0].comment.text).to.equal('reply by user 2')
369 expect(tree.children[0].children).to.have.lengthOf(1)
370 expect(tree.children[0].children[0].comment.text).to.equal('another reply')
371 }
372 })
373
286 it('Should unblock the local account', async function () { 374 it('Should unblock the local account', async function () {
287 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1') 375 await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1')
288 }) 376 })
@@ -328,7 +416,7 @@ describe('Test blocklist', function () {
328 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken) 416 const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
329 417
330 const videos: Video[] = res.body.data 418 const videos: Video[] = res.body.data
331 expect(videos).to.have.lengthOf(2) 419 expect(videos).to.have.lengthOf(3)
332 420
333 const v1 = videos.find(v => v.name === 'video user 2') 421 const v1 = videos.find(v => v.name === 'video user 2')
334 const v2 = videos.find(v => v.name === 'video server 2') 422 const v2 = videos.find(v => v.name === 'video server 2')
@@ -442,7 +530,7 @@ describe('Test blocklist', function () {
442 const res = await getVideosListWithToken(servers[0].url, token) 530 const res = await getVideosListWithToken(servers[0].url, token)
443 531
444 const videos: Video[] = res.body.data 532 const videos: Video[] = res.body.data
445 expect(videos).to.have.lengthOf(3) 533 expect(videos).to.have.lengthOf(4)
446 534
447 const v = videos.find(v => v.name === 'video user 2') 535 const v = videos.find(v => v.name === 'video user 2')
448 expect(v).to.be.undefined 536 expect(v).to.be.undefined
@@ -458,7 +546,7 @@ describe('Test blocklist', function () {
458 const res = await getVideosListWithToken(servers[0].url, token) 546 const res = await getVideosListWithToken(servers[0].url, token)
459 547
460 const videos: Video[] = res.body.data 548 const videos: Video[] = res.body.data
461 expect(videos).to.have.lengthOf(2) 549 expect(videos).to.have.lengthOf(3)
462 550
463 const v = videos.find(v => v.name === 'video user 1') 551 const v = videos.find(v => v.name === 'video user 1')
464 expect(v).to.be.undefined 552 expect(v).to.be.undefined
@@ -545,7 +633,7 @@ describe('Test blocklist', function () {
545 const res = await getVideosListWithToken(servers[0].url, token) 633 const res = await getVideosListWithToken(servers[0].url, token)
546 634
547 const videos: Video[] = res.body.data 635 const videos: Video[] = res.body.data
548 expect(videos).to.have.lengthOf(3) 636 expect(videos).to.have.lengthOf(4)
549 637
550 const v = videos.find(v => v.name === 'video user 2') 638 const v = videos.find(v => v.name === 'video user 2')
551 expect(v).not.to.be.undefined 639 expect(v).not.to.be.undefined
@@ -606,7 +694,7 @@ describe('Test blocklist', function () {
606 694
607 for (const res of [ res1, res2 ]) { 695 for (const res of [ res1, res2 ]) {
608 const videos: Video[] = res.body.data 696 const videos: Video[] = res.body.data
609 expect(videos).to.have.lengthOf(2) 697 expect(videos).to.have.lengthOf(3)
610 698
611 const v1 = videos.find(v => v.name === 'video user 2') 699 const v1 = videos.find(v => v.name === 'video user 2')
612 const v2 = videos.find(v => v.name === 'video server 2') 700 const v2 = videos.find(v => v.name === 'video server 2')
@@ -631,7 +719,7 @@ describe('Test blocklist', function () {
631 }) 719 })
632 720
633 it('Should not have notification from blocked instances by instance', async function () { 721 it('Should not have notification from blocked instances by instance', async function () {
634 this.timeout(20000) 722 this.timeout(50000)
635 723
636 { 724 {
637 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' } 725 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' }
@@ -647,6 +735,24 @@ describe('Test blocklist', function () {
647 } 735 }
648 await checkCommentNotification(servers[0], comment, 'absence') 736 await checkCommentNotification(servers[0], comment, 'absence')
649 } 737 }
738
739 {
740 const now = new Date()
741 await unfollow(servers[1].url, servers[1].accessToken, servers[0])
742 await waitJobs(servers)
743 await follow(servers[1].url, [ servers[0].host ], servers[1].accessToken)
744
745 await waitJobs(servers)
746
747 const res = await getUserNotifications(servers[0].url, servers[0].accessToken, 0, 30)
748 const commentNotifications = (res.body.data as UserNotification[])
749 .filter(n => {
750 return n.type === UserNotificationType.NEW_INSTANCE_FOLLOWER &&
751 n.createdAt >= now.toISOString()
752 })
753
754 expect(commentNotifications).to.have.lengthOf(0)
755 }
650 }) 756 })
651 757
652 it('Should list blocked servers', async function () { 758 it('Should list blocked servers', async function () {
@@ -678,7 +784,7 @@ describe('Test blocklist', function () {
678 }) 784 })
679 785
680 it('Should have notification from unblocked instances', async function () { 786 it('Should have notification from unblocked instances', async function () {
681 this.timeout(20000) 787 this.timeout(50000)
682 788
683 { 789 {
684 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' } 790 const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
@@ -694,6 +800,24 @@ describe('Test blocklist', function () {
694 } 800 }
695 await checkCommentNotification(servers[0], comment, 'presence') 801 await checkCommentNotification(servers[0], comment, 'presence')
696 } 802 }
803
804 {
805 const now = new Date()
806 await unfollow(servers[1].url, servers[1].accessToken, servers[0])
807 await waitJobs(servers)
808 await follow(servers[1].url, [ servers[0].host ], servers[1].accessToken)
809
810 await waitJobs(servers)
811
812 const res = await getUserNotifications(servers[0].url, servers[0].accessToken, 0, 30)
813 const commentNotifications = (res.body.data as UserNotification[])
814 .filter(n => {
815 return n.type === UserNotificationType.NEW_INSTANCE_FOLLOWER &&
816 n.createdAt >= now.toISOString()
817 })
818
819 expect(commentNotifications).to.have.lengthOf(1)
820 }
697 }) 821 })
698 }) 822 })
699 }) 823 })