1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
3 import * as chai from 'chai'
5 import { VideoAbuse, VideoAbuseState, VideoAbusePredefinedReasonsString } from '../../../../shared/models/videos'
9 flushAndRunMultipleServers,
14 setAccessTokensToServers,
20 } from '../../../../shared/extra-utils/index'
21 import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
22 import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
24 addAccountToServerBlocklist,
25 addServerToServerBlocklist,
26 removeAccountFromServerBlocklist,
27 removeServerFromServerBlocklist
28 } from '../../../../shared/extra-utils/users/blocklist'
30 const expect = chai.expect
32 describe('Test video abuses', function () {
33 let servers: ServerInfo[] = []
34 let abuseServer2: VideoAbuse
36 before(async function () {
40 servers = await flushAndRunMultipleServers(2)
42 // Get the access tokens
43 await setAccessTokensToServers(servers)
45 // Server 1 and server 2 follow each other
46 await doubleFollow(servers[0], servers[1])
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'
53 await uploadVideo(servers[0].url, servers[0].accessToken, video1Attributes)
55 const video2Attributes = {
56 name: 'my super name for server 2',
57 description: 'my super description for server 2'
59 await uploadVideo(servers[1].url, servers[1].accessToken, video2Attributes)
61 // Wait videos propagation, server 2 has transcoding enabled
62 await waitJobs(servers)
64 const res = await getVideosList(servers[0].url)
65 const videos = res.body.data
67 expect(videos.length).to.equal(2)
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')
73 it('Should not have video abuses', async function () {
74 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
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)
81 it('Should report abuse on a local video', async function () {
84 const reason = 'my super bad reason'
85 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[0].video.id, reason)
87 // We wait requests propagation, even if the server 1 is not supposed to make a request to server 2
88 await waitJobs(servers)
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 })
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)
98 const abuse: VideoAbuse = 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)
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)
115 it('Should report abuse on a remote video', async function () {
118 const reason = 'my super bad reason 2'
119 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[1].video.id, reason)
121 // We wait requests propagation
122 await waitJobs(servers)
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)
131 const abuse1: VideoAbuse = 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(VideoAbuseState.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)
142 const abuse2: VideoAbuse = 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(VideoAbuseState.PENDING)
148 expect(abuse2.state.label).to.equal('Pending')
149 expect(abuse2.moderationComment).to.be.null
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)
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(VideoAbuseState.PENDING)
161 expect(abuseServer2.state.label).to.equal('Pending')
162 expect(abuseServer2.moderationComment).to.be.null
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)
169 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
170 expect(res.body.data[0].state.id).to.equal(VideoAbuseState.REJECTED)
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)
177 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
178 expect(res.body.data[0].state.id).to.equal(VideoAbuseState.ACCEPTED)
179 expect(res.body.data[0].moderationComment).to.equal('It is valid')
182 it('Should hide video abuses from blocked accounts', async function () {
186 await reportVideoAbuse(servers[1].url, servers[1].accessToken, servers[0].video.uuid, 'will mute this')
187 await waitJobs(servers)
189 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
190 expect(res.body.total).to.equal(3)
193 const accountToBlock = 'root@localhost:' + servers[1].port
196 await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
198 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
199 expect(res.body.total).to.equal(2)
201 const abuse = res.body.data.find(a => a.reason === 'will mute this')
202 expect(abuse).to.be.undefined
206 await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
208 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
209 expect(res.body.total).to.equal(3)
213 it('Should hide video abuses from blocked servers', async function () {
214 const serverToBlock = servers[1].host
217 await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host)
219 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
220 expect(res.body.total).to.equal(2)
222 const abuse = res.body.data.find(a => a.reason === 'will mute this')
223 expect(abuse).to.be.undefined
227 await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock)
229 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
230 expect(res.body.total).to.equal(3)
234 it('Should keep the video abuse when deleting the video', async function () {
237 await removeVideo(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid)
239 await waitJobs(servers)
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")
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
252 it('Should include counts of reports from reporter and reportee', async function () {
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)
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'
265 await uploadVideo(servers[0].url, userAccessToken, video3Attributes)
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')
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)
277 const res2 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
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")
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")
294 it('Should list predefined reasons as well as timestamps for the reported video', async function () {
297 const reason5 = 'my super bad reason 5'
298 const predefinedReasons5: VideoAbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ]
299 const createdAbuse = (await reportVideoAbuse(
301 servers[0].accessToken,
307 )).body.videoAbuse as VideoAbuse
309 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
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")
320 it('Should delete the video abuse', async function () {
323 await deleteVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id)
325 await waitJobs(servers)
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)
335 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
336 expect(res.body.total).to.equal(6)
340 it('Should list and filter video abuses', async function () {
341 async function list (query: Omit<Parameters<typeof getVideoAbusesList>[0], 'url' | 'token'>) {
344 token: servers[0].accessToken
347 Object.assign(options, query)
349 const res = await getVideoAbusesList(options)
351 return res.body.data as VideoAbuse[]
354 expect(await list({ id: 56 })).to.have.lengthOf(0)
355 expect(await list({ id: 1 })).to.have.lengthOf(1)
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)
360 expect(await list({ searchVideo: 'my second super name for server 1' })).to.have.lengthOf(1)
362 expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(4)
363 expect(await list({ searchVideoChannel: 'aaaa' })).to.have.lengthOf(0)
365 expect(await list({ searchReporter: 'user2' })).to.have.lengthOf(1)
366 expect(await list({ searchReporter: 'root' })).to.have.lengthOf(5)
368 expect(await list({ searchReportee: 'root' })).to.have.lengthOf(4)
369 expect(await list({ searchReportee: 'aaaa' })).to.have.lengthOf(0)
371 expect(await list({ videoIs: 'deleted' })).to.have.lengthOf(1)
372 expect(await list({ videoIs: 'blacklisted' })).to.have.lengthOf(0)
374 expect(await list({ state: VideoAbuseState.ACCEPTED })).to.have.lengthOf(0)
375 expect(await list({ state: VideoAbuseState.PENDING })).to.have.lengthOf(6)
377 expect(await list({ predefinedReason: 'violentOrRepulsive' })).to.have.lengthOf(1)
378 expect(await list({ predefinedReason: 'serverRules' })).to.have.lengthOf(0)
381 after(async function () {
382 await cleanupTests(servers)