]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/tests/api/videos/video-abuse.ts
predefined report reasons & improved reporter UI (#2842)
[github/Chocobozzz/PeerTube.git] / server / tests / api / videos / video-abuse.ts
CommitLineData
a1587156 1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
0e1dc3e7 2
0e1dc3e7 3import * as chai from 'chai'
afffe988 4import 'mocha'
1ebddadd 5import { VideoAbuse, VideoAbuseState, VideoAbusePredefinedReasonsString } from '../../../../shared/models/videos'
0e1dc3e7 6import {
7c3b7976 7 cleanupTests,
268eebed 8 deleteVideoAbuse,
0e1dc3e7 9 flushAndRunMultipleServers,
0e1dc3e7 10 getVideoAbusesList,
afffe988 11 getVideosList,
afffe988
C
12 reportVideoAbuse,
13 ServerInfo,
14 setAccessTokensToServers,
268eebed 15 updateVideoAbuse,
197876ea 16 uploadVideo,
d1261d9a
RK
17 removeVideo,
18 createUser,
19 userLogin
94565d52
C
20} from '../../../../shared/extra-utils/index'
21import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
22import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
f0a47bc9
C
23import {
24 addAccountToServerBlocklist,
25 addServerToServerBlocklist,
26 removeAccountFromServerBlocklist,
27 removeServerFromServerBlocklist
28} from '../../../../shared/extra-utils/users/blocklist'
afffe988
C
29
30const expect = chai.expect
0e1dc3e7
C
31
32describe('Test video abuses', function () {
33 let servers: ServerInfo[] = []
268eebed 34 let abuseServer2: VideoAbuse
0e1dc3e7
C
35
36 before(async function () {
572f8d3d 37 this.timeout(50000)
0e1dc3e7
C
38
39 // Run servers
40 servers = await flushAndRunMultipleServers(2)
41
42 // Get the access tokens
43 await setAccessTokensToServers(servers)
44
afffe988
C
45 // Server 1 and server 2 follow each other
46 await doubleFollow(servers[0], servers[1])
0e1dc3e7 47
afffe988 48 // Upload some videos on each servers
0e1dc3e7 49 const video1Attributes = {
afffe988
C
50 name: 'my super name for server 1',
51 description: 'my super description for server 1'
0e1dc3e7
C
52 }
53 await uploadVideo(servers[0].url, servers[0].accessToken, video1Attributes)
54
55 const video2Attributes = {
afffe988
C
56 name: 'my super name for server 2',
57 description: 'my super description for server 2'
0e1dc3e7
C
58 }
59 await uploadVideo(servers[1].url, servers[1].accessToken, video2Attributes)
60
572f8d3d 61 // Wait videos propagation, server 2 has transcoding enabled
3cd0734f 62 await waitJobs(servers)
0e1dc3e7
C
63
64 const res = await getVideosList(servers[0].url)
65 const videos = res.body.data
66
67 expect(videos.length).to.equal(2)
68
afffe988
C
69 servers[0].video = videos.find(video => video.name === 'my super name for server 1')
70 servers[1].video = videos.find(video => video.name === 'my super name for server 2')
0e1dc3e7
C
71 })
72
73 it('Should not have video abuses', async function () {
feb34f6b 74 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
0e1dc3e7
C
75
76 expect(res.body.total).to.equal(0)
77 expect(res.body.data).to.be.an('array')
78 expect(res.body.data.length).to.equal(0)
79 })
80
81 it('Should report abuse on a local video', async function () {
3cd0734f 82 this.timeout(15000)
0e1dc3e7
C
83
84 const reason = 'my super bad reason'
85 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[0].video.id, reason)
86
afffe988 87 // We wait requests propagation, even if the server 1 is not supposed to make a request to server 2
3cd0734f 88 await waitJobs(servers)
0e1dc3e7
C
89 })
90
afffe988 91 it('Should have 1 video abuses on server 1 and 0 on server 2', async function () {
feb34f6b 92 const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
0e1dc3e7
C
93
94 expect(res1.body.total).to.equal(1)
95 expect(res1.body.data).to.be.an('array')
96 expect(res1.body.data.length).to.equal(1)
97
19a3b914 98 const abuse: VideoAbuse = res1.body.data[0]
0e1dc3e7 99 expect(abuse.reason).to.equal('my super bad reason')
19a3b914 100 expect(abuse.reporterAccount.name).to.equal('root')
7243f84d 101 expect(abuse.reporterAccount.host).to.equal('localhost:' + servers[0].port)
19a3b914 102 expect(abuse.video.id).to.equal(servers[0].video.id)
197876ea
RK
103 expect(abuse.video.channel).to.exist
104 expect(abuse.count).to.equal(1)
105 expect(abuse.nth).to.equal(1)
106 expect(abuse.countReportsForReporter).to.equal(1)
107 expect(abuse.countReportsForReportee).to.equal(1)
0e1dc3e7 108
feb34f6b 109 const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
0e1dc3e7
C
110 expect(res2.body.total).to.equal(0)
111 expect(res2.body.data).to.be.an('array')
112 expect(res2.body.data.length).to.equal(0)
113 })
114
115 it('Should report abuse on a remote video', async function () {
572f8d3d 116 this.timeout(10000)
0e1dc3e7
C
117
118 const reason = 'my super bad reason 2'
119 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[1].video.id, reason)
120
121 // We wait requests propagation
3cd0734f 122 await waitJobs(servers)
0e1dc3e7
C
123 })
124
268eebed 125 it('Should have 2 video abuses on server 1 and 1 on server 2', async function () {
feb34f6b 126 const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
0e1dc3e7
C
127 expect(res1.body.total).to.equal(2)
128 expect(res1.body.data).to.be.an('array')
129 expect(res1.body.data.length).to.equal(2)
130
19a3b914 131 const abuse1: VideoAbuse = res1.body.data[0]
0e1dc3e7 132 expect(abuse1.reason).to.equal('my super bad reason')
19a3b914 133 expect(abuse1.reporterAccount.name).to.equal('root')
7243f84d 134 expect(abuse1.reporterAccount.host).to.equal('localhost:' + servers[0].port)
19a3b914 135 expect(abuse1.video.id).to.equal(servers[0].video.id)
268eebed
C
136 expect(abuse1.state.id).to.equal(VideoAbuseState.PENDING)
137 expect(abuse1.state.label).to.equal('Pending')
138 expect(abuse1.moderationComment).to.be.null
197876ea
RK
139 expect(abuse1.count).to.equal(1)
140 expect(abuse1.nth).to.equal(1)
0e1dc3e7 141
19a3b914 142 const abuse2: VideoAbuse = res1.body.data[1]
0e1dc3e7 143 expect(abuse2.reason).to.equal('my super bad reason 2')
19a3b914 144 expect(abuse2.reporterAccount.name).to.equal('root')
7243f84d 145 expect(abuse2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
19a3b914 146 expect(abuse2.video.id).to.equal(servers[1].video.id)
268eebed
C
147 expect(abuse2.state.id).to.equal(VideoAbuseState.PENDING)
148 expect(abuse2.state.label).to.equal('Pending')
149 expect(abuse2.moderationComment).to.be.null
0e1dc3e7 150
feb34f6b 151 const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
0e1dc3e7
C
152 expect(res2.body.total).to.equal(1)
153 expect(res2.body.data).to.be.an('array')
154 expect(res2.body.data.length).to.equal(1)
155
268eebed
C
156 abuseServer2 = res2.body.data[0]
157 expect(abuseServer2.reason).to.equal('my super bad reason 2')
158 expect(abuseServer2.reporterAccount.name).to.equal('root')
7243f84d 159 expect(abuseServer2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
268eebed
C
160 expect(abuseServer2.state.id).to.equal(VideoAbuseState.PENDING)
161 expect(abuseServer2.state.label).to.equal('Pending')
162 expect(abuseServer2.moderationComment).to.be.null
163 })
164
165 it('Should update the state of a video abuse', async function () {
166 const body = { state: VideoAbuseState.REJECTED }
167 await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body)
168
feb34f6b 169 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
268eebed
C
170 expect(res.body.data[0].state.id).to.equal(VideoAbuseState.REJECTED)
171 })
172
173 it('Should add a moderation comment', async function () {
174 const body = { state: VideoAbuseState.ACCEPTED, moderationComment: 'It is valid' }
175 await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body)
176
feb34f6b 177 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
268eebed
C
178 expect(res.body.data[0].state.id).to.equal(VideoAbuseState.ACCEPTED)
179 expect(res.body.data[0].moderationComment).to.equal('It is valid')
180 })
181
f0a47bc9
C
182 it('Should hide video abuses from blocked accounts', async function () {
183 this.timeout(10000)
184
185 {
186 await reportVideoAbuse(servers[1].url, servers[1].accessToken, servers[0].video.uuid, 'will mute this')
187 await waitJobs(servers)
188
feb34f6b 189 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
f0a47bc9
C
190 expect(res.body.total).to.equal(3)
191 }
192
193 const accountToBlock = 'root@localhost:' + servers[1].port
194
195 {
a1587156 196 await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
f0a47bc9 197
feb34f6b 198 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
f0a47bc9
C
199 expect(res.body.total).to.equal(2)
200
201 const abuse = res.body.data.find(a => a.reason === 'will mute this')
202 expect(abuse).to.be.undefined
203 }
204
205 {
a1587156 206 await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
f0a47bc9 207
feb34f6b 208 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
f0a47bc9
C
209 expect(res.body.total).to.equal(3)
210 }
211 })
212
213 it('Should hide video abuses from blocked servers', async function () {
214 const serverToBlock = servers[1].host
215
216 {
a1587156 217 await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host)
f0a47bc9 218
feb34f6b 219 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
f0a47bc9
C
220 expect(res.body.total).to.equal(2)
221
222 const abuse = res.body.data.find(a => a.reason === 'will mute this')
223 expect(abuse).to.be.undefined
224 }
225
226 {
a1587156 227 await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock)
f0a47bc9 228
feb34f6b 229 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
f0a47bc9
C
230 expect(res.body.total).to.equal(3)
231 }
232 })
233
197876ea
RK
234 it('Should keep the video abuse when deleting the video', async function () {
235 this.timeout(10000)
236
237 await removeVideo(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid)
238
239 await waitJobs(servers)
240
feb34f6b 241 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
d1261d9a
RK
242 expect(res.body.total).to.equal(2, "wrong number of videos returned")
243 expect(res.body.data.length).to.equal(2, "wrong number of videos returned")
244 expect(res.body.data[0].id).to.equal(abuseServer2.id, "wrong origin server id for first video")
245
246 const abuse: VideoAbuse = res.body.data[0]
247 expect(abuse.video.id).to.equal(abuseServer2.video.id, "wrong video id")
248 expect(abuse.video.channel).to.exist
249 expect(abuse.video.deleted).to.be.true
250 })
251
252 it('Should include counts of reports from reporter and reportee', async function () {
253 this.timeout(10000)
197876ea 254
d1261d9a
RK
255 // register a second user to have two reporters/reportees
256 const user = { username: 'user2', password: 'password' }
257 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, ...user })
258 const userAccessToken = await userLogin(servers[0], user)
259
260 // upload a third video via this user
261 const video3Attributes = {
262 name: 'my second super name for server 1',
263 description: 'my second super description for server 1'
264 }
265 await uploadVideo(servers[0].url, userAccessToken, video3Attributes)
266
267 const res1 = await getVideosList(servers[0].url)
268 const videos = res1.body.data
269 const video3 = videos.find(video => video.name === 'my second super name for server 1')
270
271 // resume with the test
272 const reason3 = 'my super bad reason 3'
273 await reportVideoAbuse(servers[0].url, servers[0].accessToken, video3.id, reason3)
274 const reason4 = 'my super bad reason 4'
275 await reportVideoAbuse(servers[0].url, userAccessToken, servers[0].video.id, reason4)
276
feb34f6b 277 const res2 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
d1261d9a
RK
278
279 {
280 for (const abuse of res2.body.data as VideoAbuse[]) {
281 if (abuse.video.id === video3.id) {
282 expect(abuse.count).to.equal(1, "wrong reports count for video 3")
283 expect(abuse.nth).to.equal(1, "wrong report position in report list for video 3")
284 expect(abuse.countReportsForReportee).to.equal(1, "wrong reports count for reporter on video 3 abuse")
285 expect(abuse.countReportsForReporter).to.equal(3, "wrong reports count for reportee on video 3 abuse")
286 }
287 if (abuse.video.id === servers[0].video.id) {
288 expect(abuse.countReportsForReportee).to.equal(3, "wrong reports count for reporter on video 1 abuse")
289 }
290 }
197876ea
RK
291 }
292 })
293
1ebddadd
RK
294 it('Should list predefined reasons as well as timestamps for the reported video', async function () {
295 this.timeout(10000)
296
297 const reason5 = 'my super bad reason 5'
298 const predefinedReasons5: VideoAbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ]
299 const createdAbuse = (await reportVideoAbuse(
300 servers[0].url,
301 servers[0].accessToken,
302 servers[0].video.id,
303 reason5,
304 predefinedReasons5,
305 1,
306 5
307 )).body.videoAbuse as VideoAbuse
308
309 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
310
311 {
312 const abuse = (res.body.data as VideoAbuse[]).find(a => a.id === createdAbuse.id)
313 expect(abuse.reason).to.equals(reason5)
314 expect(abuse.predefinedReasons).to.deep.equals(predefinedReasons5, "predefined reasons do not match the one reported")
315 expect(abuse.startAt).to.equal(1, "starting timestamp doesn't match the one reported")
316 expect(abuse.endAt).to.equal(5, "ending timestamp doesn't match the one reported")
317 }
318 })
319
268eebed 320 it('Should delete the video abuse', async function () {
f0a47bc9
C
321 this.timeout(10000)
322
268eebed
C
323 await deleteVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id)
324
f0a47bc9
C
325 await waitJobs(servers)
326
327 {
feb34f6b 328 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
f0a47bc9
C
329 expect(res.body.total).to.equal(1)
330 expect(res.body.data.length).to.equal(1)
331 expect(res.body.data[0].id).to.not.equal(abuseServer2.id)
332 }
333
334 {
feb34f6b 335 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
1ebddadd 336 expect(res.body.total).to.equal(6)
f0a47bc9 337 }
0e1dc3e7
C
338 })
339
feb34f6b
C
340 it('Should list and filter video abuses', async function () {
341 async function list (query: Omit<Parameters<typeof getVideoAbusesList>[0], 'url' | 'token'>) {
342 const options = {
343 url: servers[0].url,
344 token: servers[0].accessToken
345 }
346
347 Object.assign(options, query)
348
349 const res = await getVideoAbusesList(options)
350
351 return res.body.data as VideoAbuse[]
352 }
353
354 expect(await list({ id: 56 })).to.have.lengthOf(0)
355 expect(await list({ id: 1 })).to.have.lengthOf(1)
356
1ebddadd 357 expect(await list({ search: 'my super name for server 1' })).to.have.lengthOf(4)
feb34f6b
C
358 expect(await list({ search: 'aaaaaaaaaaaaaaaaaaaaaaaaaa' })).to.have.lengthOf(0)
359
360 expect(await list({ searchVideo: 'my second super name for server 1' })).to.have.lengthOf(1)
361
1ebddadd 362 expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(4)
feb34f6b
C
363 expect(await list({ searchVideoChannel: 'aaaa' })).to.have.lengthOf(0)
364
365 expect(await list({ searchReporter: 'user2' })).to.have.lengthOf(1)
1ebddadd 366 expect(await list({ searchReporter: 'root' })).to.have.lengthOf(5)
feb34f6b 367
1ebddadd 368 expect(await list({ searchReportee: 'root' })).to.have.lengthOf(4)
feb34f6b
C
369 expect(await list({ searchReportee: 'aaaa' })).to.have.lengthOf(0)
370
371 expect(await list({ videoIs: 'deleted' })).to.have.lengthOf(1)
372 expect(await list({ videoIs: 'blacklisted' })).to.have.lengthOf(0)
373
374 expect(await list({ state: VideoAbuseState.ACCEPTED })).to.have.lengthOf(0)
1ebddadd
RK
375 expect(await list({ state: VideoAbuseState.PENDING })).to.have.lengthOf(6)
376
377 expect(await list({ predefinedReason: 'violentOrRepulsive' })).to.have.lengthOf(1)
378 expect(await list({ predefinedReason: 'serverRules' })).to.have.lengthOf(0)
feb34f6b
C
379 })
380
7c3b7976
C
381 after(async function () {
382 await cleanupTests(servers)
0e1dc3e7
C
383 })
384})