aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/tests/api/moderation/abuses.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/tests/api/moderation/abuses.ts')
-rw-r--r--server/tests/api/moderation/abuses.ts384
1 files changed, 384 insertions, 0 deletions
diff --git a/server/tests/api/moderation/abuses.ts b/server/tests/api/moderation/abuses.ts
new file mode 100644
index 000000000..28c5a5531
--- /dev/null
+++ b/server/tests/api/moderation/abuses.ts
@@ -0,0 +1,384 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { Abuse, AbusePredefinedReasonsString, AbuseState } from '@shared/models'
6import {
7 cleanupTests,
8 createUser,
9 deleteVideoAbuse,
10 flushAndRunMultipleServers,
11 getVideoAbusesList,
12 getVideosList,
13 removeVideo,
14 reportVideoAbuse,
15 ServerInfo,
16 setAccessTokensToServers,
17 updateVideoAbuse,
18 uploadVideo,
19 userLogin
20} from '../../../../shared/extra-utils/index'
21import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
22import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
23import {
24 addAccountToServerBlocklist,
25 addServerToServerBlocklist,
26 removeAccountFromServerBlocklist,
27 removeServerFromServerBlocklist
28} from '../../../../shared/extra-utils/users/blocklist'
29
30const expect = chai.expect
31
32describe('Test abuses', function () {
33 let servers: ServerInfo[] = []
34 let abuseServer2: Abuse
35
36 before(async function () {
37 this.timeout(50000)
38
39 // Run servers
40 servers = await flushAndRunMultipleServers(2)
41
42 // Get the access tokens
43 await setAccessTokensToServers(servers)
44
45 // Server 1 and server 2 follow each other
46 await doubleFollow(servers[0], servers[1])
47
48 // Upload some videos on each servers
49 const video1Attributes = {
50 name: 'my super name for server 1',
51 description: 'my super description for server 1'
52 }
53 await uploadVideo(servers[0].url, servers[0].accessToken, video1Attributes)
54
55 const video2Attributes = {
56 name: 'my super name for server 2',
57 description: 'my super description for server 2'
58 }
59 await uploadVideo(servers[1].url, servers[1].accessToken, video2Attributes)
60
61 // Wait videos propagation, server 2 has transcoding enabled
62 await waitJobs(servers)
63
64 const res = await getVideosList(servers[0].url)
65 const videos = res.body.data
66
67 expect(videos.length).to.equal(2)
68
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')
71 })
72
73 it('Should not have video abuses', async function () {
74 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
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 () {
82 this.timeout(15000)
83
84 const reason = 'my super bad reason'
85 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[0].video.id, reason)
86
87 // We wait requests propagation, even if the server 1 is not supposed to make a request to server 2
88 await waitJobs(servers)
89 })
90
91 it('Should have 1 video abuses on server 1 and 0 on server 2', async function () {
92 const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
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
98 const abuse: Abuse = res1.body.data[0]
99 expect(abuse.reason).to.equal('my super bad reason')
100 expect(abuse.reporterAccount.name).to.equal('root')
101 expect(abuse.reporterAccount.host).to.equal('localhost:' + servers[0].port)
102 expect(abuse.video.id).to.equal(servers[0].video.id)
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)
108
109 const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
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 () {
116 this.timeout(10000)
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
122 await waitJobs(servers)
123 })
124
125 it('Should have 2 video abuses on server 1 and 1 on server 2', async function () {
126 const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
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
131 const abuse1: Abuse = res1.body.data[0]
132 expect(abuse1.reason).to.equal('my super bad reason')
133 expect(abuse1.reporterAccount.name).to.equal('root')
134 expect(abuse1.reporterAccount.host).to.equal('localhost:' + servers[0].port)
135 expect(abuse1.video.id).to.equal(servers[0].video.id)
136 expect(abuse1.state.id).to.equal(AbuseState.PENDING)
137 expect(abuse1.state.label).to.equal('Pending')
138 expect(abuse1.moderationComment).to.be.null
139 expect(abuse1.count).to.equal(1)
140 expect(abuse1.nth).to.equal(1)
141
142 const abuse2: Abuse = res1.body.data[1]
143 expect(abuse2.reason).to.equal('my super bad reason 2')
144 expect(abuse2.reporterAccount.name).to.equal('root')
145 expect(abuse2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
146 expect(abuse2.video.id).to.equal(servers[1].video.id)
147 expect(abuse2.state.id).to.equal(AbuseState.PENDING)
148 expect(abuse2.state.label).to.equal('Pending')
149 expect(abuse2.moderationComment).to.be.null
150
151 const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
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
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')
159 expect(abuseServer2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
160 expect(abuseServer2.state.id).to.equal(AbuseState.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: AbuseState.REJECTED }
167 await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body)
168
169 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
170 expect(res.body.data[0].state.id).to.equal(AbuseState.REJECTED)
171 })
172
173 it('Should add a moderation comment', async function () {
174 const body = { state: AbuseState.ACCEPTED, moderationComment: 'It is valid' }
175 await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body)
176
177 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
178 expect(res.body.data[0].state.id).to.equal(AbuseState.ACCEPTED)
179 expect(res.body.data[0].moderationComment).to.equal('It is valid')
180 })
181
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
189 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
190 expect(res.body.total).to.equal(3)
191 }
192
193 const accountToBlock = 'root@localhost:' + servers[1].port
194
195 {
196 await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
197
198 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
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 {
206 await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
207
208 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
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 {
217 await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host)
218
219 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
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 {
227 await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock)
228
229 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
230 expect(res.body.total).to.equal(3)
231 }
232 })
233
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
241 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
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: Abuse = 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)
254
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
277 const res2 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
278
279 {
280 for (const abuse of res2.body.data as Abuse[]) {
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 }
291 }
292 })
293
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: AbusePredefinedReasonsString[] = [ '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.abuse
308
309 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
310
311 {
312 const abuse = (res.body.data as Abuse[]).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.video.startAt).to.equal(1, "starting timestamp doesn't match the one reported")
316 expect(abuse.video.endAt).to.equal(5, "ending timestamp doesn't match the one reported")
317 }
318 })
319
320 it('Should delete the video abuse', async function () {
321 this.timeout(10000)
322
323 await deleteVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id)
324
325 await waitJobs(servers)
326
327 {
328 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
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 {
335 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
336 expect(res.body.total).to.equal(6)
337 }
338 })
339
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 Abuse[]
352 }
353
354 expect(await list({ id: 56 })).to.have.lengthOf(0)
355 expect(await list({ id: 1 })).to.have.lengthOf(1)
356
357 expect(await list({ search: 'my super name for server 1' })).to.have.lengthOf(4)
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
362 expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(4)
363 expect(await list({ searchVideoChannel: 'aaaa' })).to.have.lengthOf(0)
364
365 expect(await list({ searchReporter: 'user2' })).to.have.lengthOf(1)
366 expect(await list({ searchReporter: 'root' })).to.have.lengthOf(5)
367
368 expect(await list({ searchReportee: 'root' })).to.have.lengthOf(5)
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: AbuseState.ACCEPTED })).to.have.lengthOf(0)
375 expect(await list({ state: AbuseState.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)
379 })
380
381 after(async function () {
382 await cleanupTests(servers)
383 })
384})