aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-11-10 14:41:20 +0100
committerChocobozzz <me@florianbigard.com>2020-11-10 14:50:16 +0100
commit7a4ea932461f228ae44a173ddcd48ffb088aa023 (patch)
tree429b6fa7dae496d339a9f22e4076e39ffda97461 /server
parent403c69c5a34e6db621f30c7b2bfb2b80dc8e74c1 (diff)
downloadPeerTube-7a4ea932461f228ae44a173ddcd48ffb088aa023.tar.gz
PeerTube-7a4ea932461f228ae44a173ddcd48ffb088aa023.tar.zst
PeerTube-7a4ea932461f228ae44a173ddcd48ffb088aa023.zip
Remove deprecated abuse api
Diffstat (limited to 'server')
-rw-r--r--server/controllers/api/abuse.ts8
-rw-r--r--server/controllers/api/videos/abuse.ts114
-rw-r--r--server/controllers/api/videos/index.ts4
-rw-r--r--server/helpers/middlewares/abuses.ts27
-rw-r--r--server/middlewares/validators/abuse.ts119
-rw-r--r--server/models/abuse/abuse.ts36
-rw-r--r--server/tests/api/check-params/index.ts1
-rw-r--r--server/tests/api/check-params/video-abuses.ts216
-rw-r--r--server/tests/api/moderation/index.ts1
-rw-r--r--server/tests/api/moderation/video-abuse.ts386
10 files changed, 8 insertions, 904 deletions
diff --git a/server/controllers/api/abuse.ts b/server/controllers/api/abuse.ts
index b97b99f16..25d6e2ab0 100644
--- a/server/controllers/api/abuse.ts
+++ b/server/controllers/api/abuse.ts
@@ -85,13 +85,7 @@ abuseRouter.delete('/:id/messages/:messageId',
85// --------------------------------------------------------------------------- 85// ---------------------------------------------------------------------------
86 86
87export { 87export {
88 abuseRouter, 88 abuseRouter
89
90 // FIXME: deprecated in 2.3. Remove these exports
91 listAbusesForAdmins,
92 updateAbuse,
93 deleteAbuse,
94 reportAbuse
95} 89}
96 90
97// --------------------------------------------------------------------------- 91// ---------------------------------------------------------------------------
diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts
deleted file mode 100644
index 9c4d00849..000000000
--- a/server/controllers/api/videos/abuse.ts
+++ /dev/null
@@ -1,114 +0,0 @@
1import * as express from 'express'
2import { AbuseModel } from '@server/models/abuse/abuse'
3import { getServerActor } from '@server/models/application/application'
4import { AbuseCreate, UserRight, VideoAbuseCreate } from '../../../../shared'
5import {
6 abusesSortValidator,
7 asyncMiddleware,
8 asyncRetryTransactionMiddleware,
9 authenticate,
10 ensureUserHasRight,
11 paginationValidator,
12 setDefaultPagination,
13 setDefaultSort,
14 videoAbuseGetValidator,
15 videoAbuseListValidator,
16 videoAbuseReportValidator,
17 videoAbuseUpdateValidator
18} from '../../../middlewares'
19import { deleteAbuse, reportAbuse, updateAbuse } from '../abuse'
20
21// FIXME: deprecated in 2.3. Remove this controller
22
23const abuseVideoRouter = express.Router()
24
25abuseVideoRouter.get('/abuse',
26 authenticate,
27 ensureUserHasRight(UserRight.MANAGE_ABUSES),
28 paginationValidator,
29 abusesSortValidator,
30 setDefaultSort,
31 setDefaultPagination,
32 videoAbuseListValidator,
33 asyncMiddleware(listVideoAbuses)
34)
35abuseVideoRouter.put('/:videoId/abuse/:id',
36 authenticate,
37 ensureUserHasRight(UserRight.MANAGE_ABUSES),
38 asyncMiddleware(videoAbuseUpdateValidator),
39 asyncRetryTransactionMiddleware(updateVideoAbuse)
40)
41abuseVideoRouter.post('/:videoId/abuse',
42 authenticate,
43 asyncMiddleware(videoAbuseReportValidator),
44 asyncRetryTransactionMiddleware(reportVideoAbuse)
45)
46abuseVideoRouter.delete('/:videoId/abuse/:id',
47 authenticate,
48 ensureUserHasRight(UserRight.MANAGE_ABUSES),
49 asyncMiddleware(videoAbuseGetValidator),
50 asyncRetryTransactionMiddleware(deleteVideoAbuse)
51)
52
53// ---------------------------------------------------------------------------
54
55export {
56 abuseVideoRouter
57}
58
59// ---------------------------------------------------------------------------
60
61async function listVideoAbuses (req: express.Request, res: express.Response) {
62 const user = res.locals.oauth.token.user
63 const serverActor = await getServerActor()
64
65 const resultList = await AbuseModel.listForAdminApi({
66 start: req.query.start,
67 count: req.query.count,
68 sort: req.query.sort,
69 id: req.query.id,
70 filter: 'video',
71 predefinedReason: req.query.predefinedReason,
72 search: req.query.search,
73 state: req.query.state,
74 videoIs: req.query.videoIs,
75 searchReporter: req.query.searchReporter,
76 searchReportee: req.query.searchReportee,
77 searchVideo: req.query.searchVideo,
78 searchVideoChannel: req.query.searchVideoChannel,
79 serverAccountId: serverActor.Account.id,
80 user
81 })
82
83 return res.json({
84 total: resultList.total,
85 data: resultList.data.map(d => d.toFormattedAdminJSON())
86 })
87}
88
89async function updateVideoAbuse (req: express.Request, res: express.Response) {
90 return updateAbuse(req, res)
91}
92
93async function deleteVideoAbuse (req: express.Request, res: express.Response) {
94 return deleteAbuse(req, res)
95}
96
97async function reportVideoAbuse (req: express.Request, res: express.Response) {
98 const oldBody = req.body as VideoAbuseCreate
99
100 req.body = {
101 accountId: res.locals.videoAll.VideoChannel.accountId,
102
103 reason: oldBody.reason,
104 predefinedReasons: oldBody.predefinedReasons,
105
106 video: {
107 id: res.locals.videoAll.id,
108 startAt: oldBody.startAt,
109 endAt: oldBody.endAt
110 }
111 } as AbuseCreate
112
113 return reportAbuse(req, res)
114}
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts
index 3f96f142c..bfebc54ed 100644
--- a/server/controllers/api/videos/index.ts
+++ b/server/controllers/api/videos/index.ts
@@ -6,6 +6,7 @@ import { addOptimizeOrMergeAudioJob } from '@server/helpers/video'
6import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' 6import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent'
7import { changeVideoChannelShare } from '@server/lib/activitypub/share' 7import { changeVideoChannelShare } from '@server/lib/activitypub/share'
8import { getVideoActivityPubUrl } from '@server/lib/activitypub/url' 8import { getVideoActivityPubUrl } from '@server/lib/activitypub/url'
9import { LiveManager } from '@server/lib/live-manager'
9import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' 10import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video'
10import { getVideoFilePath } from '@server/lib/video-paths' 11import { getVideoFilePath } from '@server/lib/video-paths'
11import { getServerActor } from '@server/models/application/application' 12import { getServerActor } from '@server/models/application/application'
@@ -57,7 +58,6 @@ import {
57import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update' 58import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update'
58import { VideoModel } from '../../../models/video/video' 59import { VideoModel } from '../../../models/video/video'
59import { VideoFileModel } from '../../../models/video/video-file' 60import { VideoFileModel } from '../../../models/video/video-file'
60import { abuseVideoRouter } from './abuse'
61import { blacklistRouter } from './blacklist' 61import { blacklistRouter } from './blacklist'
62import { videoCaptionsRouter } from './captions' 62import { videoCaptionsRouter } from './captions'
63import { videoCommentRouter } from './comment' 63import { videoCommentRouter } from './comment'
@@ -66,7 +66,6 @@ import { liveRouter } from './live'
66import { ownershipVideoRouter } from './ownership' 66import { ownershipVideoRouter } from './ownership'
67import { rateVideoRouter } from './rate' 67import { rateVideoRouter } from './rate'
68import { watchingRouter } from './watching' 68import { watchingRouter } from './watching'
69import { LiveManager } from '@server/lib/live-manager'
70 69
71const auditLogger = auditLoggerFactory('videos') 70const auditLogger = auditLoggerFactory('videos')
72const videosRouter = express.Router() 71const videosRouter = express.Router()
@@ -89,7 +88,6 @@ const reqVideoFileUpdate = createReqFiles(
89 } 88 }
90) 89)
91 90
92videosRouter.use('/', abuseVideoRouter)
93videosRouter.use('/', blacklistRouter) 91videosRouter.use('/', blacklistRouter)
94videosRouter.use('/', rateVideoRouter) 92videosRouter.use('/', rateVideoRouter)
95videosRouter.use('/', videoCommentRouter) 93videosRouter.use('/', videoCommentRouter)
diff --git a/server/helpers/middlewares/abuses.ts b/server/helpers/middlewares/abuses.ts
index 659ad8939..59ba0d3ed 100644
--- a/server/helpers/middlewares/abuses.ts
+++ b/server/helpers/middlewares/abuses.ts
@@ -1,29 +1,5 @@
1import { Response } from 'express' 1import { Response } from 'express'
2import { AbuseModel } from '../../models/abuse/abuse' 2import { AbuseModel } from '../../models/abuse/abuse'
3import { fetchVideo } from '../video'
4
5// FIXME: deprecated in 2.3. Remove this function
6async function doesVideoAbuseExist (abuseIdArg: number | string, videoUUID: string, res: Response) {
7 const abuseId = parseInt(abuseIdArg + '', 10)
8 let abuse = await AbuseModel.loadByIdAndVideoId(abuseId, null, videoUUID)
9
10 if (!abuse) {
11 const userId = res.locals.oauth?.token.User.id
12 const video = await fetchVideo(videoUUID, 'all', userId)
13
14 if (video) abuse = await AbuseModel.loadByIdAndVideoId(abuseId, video.id)
15 }
16
17 if (abuse === null) {
18 res.status(404)
19 .json({ error: 'Video abuse not found' })
20
21 return false
22 }
23
24 res.locals.abuse = abuse
25 return true
26}
27 3
28async function doesAbuseExist (abuseId: number | string, res: Response) { 4async function doesAbuseExist (abuseId: number | string, res: Response) {
29 const abuse = await AbuseModel.loadByIdWithReporter(parseInt(abuseId + '', 10)) 5 const abuse = await AbuseModel.loadByIdWithReporter(parseInt(abuseId + '', 10))
@@ -42,6 +18,5 @@ async function doesAbuseExist (abuseId: number | string, res: Response) {
42// --------------------------------------------------------------------------- 18// ---------------------------------------------------------------------------
43 19
44export { 20export {
45 doesAbuseExist, 21 doesAbuseExist
46 doesVideoAbuseExist
47} 22}
diff --git a/server/middlewares/validators/abuse.ts b/server/middlewares/validators/abuse.ts
index f99d850a5..99403ca40 100644
--- a/server/middlewares/validators/abuse.ts
+++ b/server/middlewares/validators/abuse.ts
@@ -1,10 +1,10 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param, query } from 'express-validator' 2import { body, param, query } from 'express-validator'
3import { 3import {
4 areAbusePredefinedReasonsValid,
4 isAbuseFilterValid, 5 isAbuseFilterValid,
5 isAbuseMessageValid, 6 isAbuseMessageValid,
6 isAbuseModerationCommentValid, 7 isAbuseModerationCommentValid,
7 areAbusePredefinedReasonsValid,
8 isAbusePredefinedReasonValid, 8 isAbusePredefinedReasonValid,
9 isAbuseReasonValid, 9 isAbuseReasonValid,
10 isAbuseStateValid, 10 isAbuseStateValid,
@@ -15,7 +15,7 @@ import {
15import { exists, isIdOrUUIDValid, isIdValid, toIntOrNull } from '@server/helpers/custom-validators/misc' 15import { exists, isIdOrUUIDValid, isIdValid, toIntOrNull } from '@server/helpers/custom-validators/misc'
16import { doesCommentIdExist } from '@server/helpers/custom-validators/video-comments' 16import { doesCommentIdExist } from '@server/helpers/custom-validators/video-comments'
17import { logger } from '@server/helpers/logger' 17import { logger } from '@server/helpers/logger'
18import { doesAbuseExist, doesAccountIdExist, doesVideoAbuseExist, doesVideoExist } from '@server/helpers/middlewares' 18import { doesAbuseExist, doesAccountIdExist, doesVideoExist } from '@server/helpers/middlewares'
19import { AbuseMessageModel } from '@server/models/abuse/abuse-message' 19import { AbuseMessageModel } from '@server/models/abuse/abuse-message'
20import { AbuseCreate, UserRight } from '@shared/models' 20import { AbuseCreate, UserRight } from '@shared/models'
21import { areValidationErrors } from './utils' 21import { areValidationErrors } from './utils'
@@ -256,115 +256,6 @@ const deleteAbuseMessageValidator = [
256 } 256 }
257] 257]
258 258
259// FIXME: deprecated in 2.3. Remove these validators
260
261const videoAbuseReportValidator = [
262 param('videoId')
263 .custom(isIdOrUUIDValid)
264 .not()
265 .isEmpty()
266 .withMessage('Should have a valid videoId'),
267 body('reason')
268 .custom(isAbuseReasonValid)
269 .withMessage('Should have a valid reason'),
270 body('predefinedReasons')
271 .optional()
272 .custom(areAbusePredefinedReasonsValid)
273 .withMessage('Should have a valid list of predefined reasons'),
274 body('startAt')
275 .optional()
276 .customSanitizer(toIntOrNull)
277 .custom(isAbuseTimestampValid)
278 .withMessage('Should have valid starting time value'),
279 body('endAt')
280 .optional()
281 .customSanitizer(toIntOrNull)
282 .custom(isAbuseTimestampValid)
283 .withMessage('Should have valid ending time value'),
284
285 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
286 logger.debug('Checking videoAbuseReport parameters', { parameters: req.body })
287
288 if (areValidationErrors(req, res)) return
289 if (!await doesVideoExist(req.params.videoId, res)) return
290
291 return next()
292 }
293]
294
295const videoAbuseGetValidator = [
296 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
297 param('id').custom(isIdValid).not().isEmpty().withMessage('Should have a valid id'),
298
299 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
300 logger.debug('Checking videoAbuseGetValidator parameters', { parameters: req.body })
301
302 if (areValidationErrors(req, res)) return
303 if (!await doesVideoAbuseExist(req.params.id, req.params.videoId, res)) return
304
305 return next()
306 }
307]
308
309const videoAbuseUpdateValidator = [
310 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
311 param('id').custom(isIdValid).not().isEmpty().withMessage('Should have a valid id'),
312 body('state')
313 .optional()
314 .custom(isAbuseStateValid).withMessage('Should have a valid video abuse state'),
315 body('moderationComment')
316 .optional()
317 .custom(isAbuseModerationCommentValid).withMessage('Should have a valid video moderation comment'),
318
319 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
320 logger.debug('Checking videoAbuseUpdateValidator parameters', { parameters: req.body })
321
322 if (areValidationErrors(req, res)) return
323 if (!await doesVideoAbuseExist(req.params.id, req.params.videoId, res)) return
324
325 return next()
326 }
327]
328
329const videoAbuseListValidator = [
330 query('id')
331 .optional()
332 .custom(isIdValid).withMessage('Should have a valid id'),
333 query('predefinedReason')
334 .optional()
335 .custom(isAbusePredefinedReasonValid)
336 .withMessage('Should have a valid predefinedReason'),
337 query('search')
338 .optional()
339 .custom(exists).withMessage('Should have a valid search'),
340 query('state')
341 .optional()
342 .custom(isAbuseStateValid).withMessage('Should have a valid video abuse state'),
343 query('videoIs')
344 .optional()
345 .custom(isAbuseVideoIsValid).withMessage('Should have a valid "video is" attribute'),
346 query('searchReporter')
347 .optional()
348 .custom(exists).withMessage('Should have a valid reporter search'),
349 query('searchReportee')
350 .optional()
351 .custom(exists).withMessage('Should have a valid reportee search'),
352 query('searchVideo')
353 .optional()
354 .custom(exists).withMessage('Should have a valid video search'),
355 query('searchVideoChannel')
356 .optional()
357 .custom(exists).withMessage('Should have a valid video channel search'),
358
359 (req: express.Request, res: express.Response, next: express.NextFunction) => {
360 logger.debug('Checking videoAbuseListValidator parameters', { parameters: req.body })
361
362 if (areValidationErrors(req, res)) return
363
364 return next()
365 }
366]
367
368// --------------------------------------------------------------------------- 259// ---------------------------------------------------------------------------
369 260
370export { 261export {
@@ -376,9 +267,5 @@ export {
376 abuseUpdateValidator, 267 abuseUpdateValidator,
377 deleteAbuseMessageValidator, 268 deleteAbuseMessageValidator,
378 abuseListForUserValidator, 269 abuseListForUserValidator,
379 getAbuseValidator, 270 getAbuseValidator
380 videoAbuseReportValidator,
381 videoAbuseGetValidator,
382 videoAbuseUpdateValidator,
383 videoAbuseListValidator
384} 271}
diff --git a/server/models/abuse/abuse.ts b/server/models/abuse/abuse.ts
index 2a407c3d2..290270fe2 100644
--- a/server/models/abuse/abuse.ts
+++ b/server/models/abuse/abuse.ts
@@ -1,6 +1,6 @@
1import * as Bluebird from 'bluebird' 1import * as Bluebird from 'bluebird'
2import { invert } from 'lodash' 2import { invert } from 'lodash'
3import { literal, Op, QueryTypes, WhereOptions } from 'sequelize' 3import { literal, Op, QueryTypes } from 'sequelize'
4import { 4import {
5 AllowNull, 5 AllowNull,
6 BelongsTo, 6 BelongsTo,
@@ -265,32 +265,6 @@ export class AbuseModel extends Model<AbuseModel> {
265 }) 265 })
266 VideoAbuse: VideoAbuseModel 266 VideoAbuse: VideoAbuseModel
267 267
268 // FIXME: deprecated in 2.3. Remove these validators
269 static loadByIdAndVideoId (id: number, videoId?: number, uuid?: string): Bluebird<MAbuseReporter> {
270 const videoWhere: WhereOptions = {}
271
272 if (videoId) videoWhere.videoId = videoId
273 if (uuid) videoWhere.deletedVideo = { uuid }
274
275 const query = {
276 include: [
277 {
278 model: VideoAbuseModel,
279 required: true,
280 where: videoWhere
281 },
282 {
283 model: AccountModel,
284 as: 'ReporterAccount'
285 }
286 ],
287 where: {
288 id
289 }
290 }
291 return AbuseModel.findOne(query)
292 }
293
294 static loadByIdWithReporter (id: number): Bluebird<MAbuseReporter> { 268 static loadByIdWithReporter (id: number): Bluebird<MAbuseReporter> {
295 const query = { 269 const query = {
296 where: { 270 where: {
@@ -561,13 +535,7 @@ export class AbuseModel extends Model<AbuseModel> {
561 : null, 535 : null,
562 536
563 countReportsForReporter: (countReportsForReporter || 0), 537 countReportsForReporter: (countReportsForReporter || 0),
564 countReportsForReportee: (countReportsForReportee || 0), 538 countReportsForReportee: (countReportsForReportee || 0)
565
566 // FIXME: deprecated in 2.3, remove this
567 startAt: null,
568 endAt: null,
569 count: countReportsForVideo || 0,
570 nth: nthReportForVideo || 0
571 }) 539 })
572 } 540 }
573 541
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts
index b5f0d07be..d0b0b9c21 100644
--- a/server/tests/api/check-params/index.ts
+++ b/server/tests/api/check-params/index.ts
@@ -16,7 +16,6 @@ import './services'
16import './user-notifications' 16import './user-notifications'
17import './user-subscriptions' 17import './user-subscriptions'
18import './users' 18import './users'
19import './video-abuses'
20import './video-blacklist' 19import './video-blacklist'
21import './video-captions' 20import './video-captions'
22import './video-channels' 21import './video-channels'
diff --git a/server/tests/api/check-params/video-abuses.ts b/server/tests/api/check-params/video-abuses.ts
deleted file mode 100644
index 3b361ca79..000000000
--- a/server/tests/api/check-params/video-abuses.ts
+++ /dev/null
@@ -1,216 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import { AbuseState, VideoAbuseCreate } from '@shared/models'
5import {
6 cleanupTests,
7 createUser,
8 deleteVideoAbuse,
9 flushAndRunServer,
10 makeGetRequest,
11 makePostBodyRequest,
12 ServerInfo,
13 setAccessTokensToServers,
14 updateVideoAbuse,
15 uploadVideo,
16 userLogin
17} from '../../../../shared/extra-utils'
18import {
19 checkBadCountPagination,
20 checkBadSortPagination,
21 checkBadStartPagination
22} from '../../../../shared/extra-utils/requests/check-api-params'
23
24// FIXME: deprecated in 2.3. Remove this controller
25
26describe('Test video abuses API validators', function () {
27 let server: ServerInfo
28 let userAccessToken = ''
29 let videoAbuseId: number
30
31 // ---------------------------------------------------------------
32
33 before(async function () {
34 this.timeout(30000)
35
36 server = await flushAndRunServer(1)
37
38 await setAccessTokensToServers([ server ])
39
40 const username = 'user1'
41 const password = 'my super password'
42 await createUser({ url: server.url, accessToken: server.accessToken, username: username, password: password })
43 userAccessToken = await userLogin(server, { username, password })
44
45 const res = await uploadVideo(server.url, server.accessToken, {})
46 server.video = res.body.video
47 })
48
49 describe('When listing video abuses', function () {
50 const path = '/api/v1/videos/abuse'
51
52 it('Should fail with a bad start pagination', async function () {
53 await checkBadStartPagination(server.url, path, server.accessToken)
54 })
55
56 it('Should fail with a bad count pagination', async function () {
57 await checkBadCountPagination(server.url, path, server.accessToken)
58 })
59
60 it('Should fail with an incorrect sort', async function () {
61 await checkBadSortPagination(server.url, path, server.accessToken)
62 })
63
64 it('Should fail with a non authenticated user', async function () {
65 await makeGetRequest({
66 url: server.url,
67 path,
68 statusCodeExpected: 401
69 })
70 })
71
72 it('Should fail with a non admin user', async function () {
73 await makeGetRequest({
74 url: server.url,
75 path,
76 token: userAccessToken,
77 statusCodeExpected: 403
78 })
79 })
80
81 it('Should fail with a bad id filter', async function () {
82 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { id: 'toto' } })
83 })
84
85 it('Should fail with a bad state filter', async function () {
86 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { state: 'toto' } })
87 })
88
89 it('Should fail with a bad videoIs filter', async function () {
90 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { videoIs: 'toto' } })
91 })
92
93 it('Should succeed with the correct params', async function () {
94 await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { id: 13 }, statusCodeExpected: 200 })
95 })
96 })
97
98 describe('When reporting a video abuse', function () {
99 const basePath = '/api/v1/videos/'
100 let path: string
101
102 before(() => {
103 path = basePath + server.video.id + '/abuse'
104 })
105
106 it('Should fail with nothing', async function () {
107 const fields = {}
108 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
109 })
110
111 it('Should fail with a wrong video', async function () {
112 const wrongPath = '/api/v1/videos/blabla/abuse'
113 const fields = { reason: 'my super reason' }
114
115 await makePostBodyRequest({ url: server.url, path: wrongPath, token: server.accessToken, fields })
116 })
117
118 it('Should fail with a non authenticated user', async function () {
119 const fields = { reason: 'my super reason' }
120
121 await makePostBodyRequest({ url: server.url, path, token: 'hello', fields, statusCodeExpected: 401 })
122 })
123
124 it('Should fail with a reason too short', async function () {
125 const fields = { reason: 'h' }
126
127 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
128 })
129
130 it('Should fail with a too big reason', async function () {
131 const fields = { reason: 'super'.repeat(605) }
132
133 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
134 })
135
136 it('Should succeed with the correct parameters (basic)', async function () {
137 const fields = { reason: 'my super reason' }
138
139 const res = await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 200 })
140 videoAbuseId = res.body.abuse.id
141 })
142
143 it('Should fail with a wrong predefined reason', async function () {
144 const fields = { reason: 'my super reason', predefinedReasons: [ 'wrongPredefinedReason' ] }
145
146 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
147 })
148
149 it('Should fail with negative timestamps', async function () {
150 const fields = { reason: 'my super reason', startAt: -1 }
151
152 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
153 })
154
155 it('Should succeed with the corret parameters (advanced)', async function () {
156 const fields: VideoAbuseCreate = { reason: 'my super reason', predefinedReasons: [ 'serverRules' ], startAt: 1, endAt: 5 }
157
158 await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 200 })
159 })
160 })
161
162 describe('When updating a video abuse', function () {
163
164 it('Should fail with a non authenticated user', async function () {
165 await updateVideoAbuse(server.url, 'blabla', server.video.uuid, videoAbuseId, {}, 401)
166 })
167
168 it('Should fail with a non admin user', async function () {
169 await updateVideoAbuse(server.url, userAccessToken, server.video.uuid, videoAbuseId, {}, 403)
170 })
171
172 it('Should fail with a bad video id or bad video abuse id', async function () {
173 await updateVideoAbuse(server.url, server.accessToken, server.video.uuid, 45, {}, 404)
174 await updateVideoAbuse(server.url, server.accessToken, 52, videoAbuseId, {}, 404)
175 })
176
177 it('Should fail with a bad state', async function () {
178 const body = { state: 5 }
179 await updateVideoAbuse(server.url, server.accessToken, server.video.uuid, videoAbuseId, body, 400)
180 })
181
182 it('Should fail with a bad moderation comment', async function () {
183 const body = { moderationComment: 'b'.repeat(3001) }
184 await updateVideoAbuse(server.url, server.accessToken, server.video.uuid, videoAbuseId, body, 400)
185 })
186
187 it('Should succeed with the correct params', async function () {
188 const body = { state: AbuseState.ACCEPTED }
189 await updateVideoAbuse(server.url, server.accessToken, server.video.uuid, videoAbuseId, body)
190 })
191 })
192
193 describe('When deleting a video abuse', function () {
194
195 it('Should fail with a non authenticated user', async function () {
196 await deleteVideoAbuse(server.url, 'blabla', server.video.uuid, videoAbuseId, 401)
197 })
198
199 it('Should fail with a non admin user', async function () {
200 await deleteVideoAbuse(server.url, userAccessToken, server.video.uuid, videoAbuseId, 403)
201 })
202
203 it('Should fail with a bad video id or bad video abuse id', async function () {
204 await deleteVideoAbuse(server.url, server.accessToken, server.video.uuid, 45, 404)
205 await deleteVideoAbuse(server.url, server.accessToken, 52, videoAbuseId, 404)
206 })
207
208 it('Should succeed with the correct params', async function () {
209 await deleteVideoAbuse(server.url, server.accessToken, server.video.uuid, videoAbuseId)
210 })
211 })
212
213 after(async function () {
214 await cleanupTests([ server ])
215 })
216})
diff --git a/server/tests/api/moderation/index.ts b/server/tests/api/moderation/index.ts
index ceb223003..6593c001f 100644
--- a/server/tests/api/moderation/index.ts
+++ b/server/tests/api/moderation/index.ts
@@ -1,4 +1,3 @@
1export * from './abuses' 1export * from './abuses'
2export * from './blocklist' 2export * from './blocklist'
3export * from './video-abuse'
4export * from './video-blacklist' 3export * from './video-blacklist'
diff --git a/server/tests/api/moderation/video-abuse.ts b/server/tests/api/moderation/video-abuse.ts
deleted file mode 100644
index 0b6a0e8ae..000000000
--- a/server/tests/api/moderation/video-abuse.ts
+++ /dev/null
@@ -1,386 +0,0 @@
1/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3import 'mocha'
4import * as chai from 'chai'
5import { AbusePredefinedReasonsString, AbuseState, AdminAbuse } 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
32// FIXME: deprecated in 2.3. Remove this controller
33
34describe('Test video abuses', function () {
35 let servers: ServerInfo[] = []
36 let abuseServer2: AdminAbuse
37
38 before(async function () {
39 this.timeout(50000)
40
41 // Run servers
42 servers = await flushAndRunMultipleServers(2)
43
44 // Get the access tokens
45 await setAccessTokensToServers(servers)
46
47 // Server 1 and server 2 follow each other
48 await doubleFollow(servers[0], servers[1])
49
50 // Upload some videos on each servers
51 const video1Attributes = {
52 name: 'my super name for server 1',
53 description: 'my super description for server 1'
54 }
55 await uploadVideo(servers[0].url, servers[0].accessToken, video1Attributes)
56
57 const video2Attributes = {
58 name: 'my super name for server 2',
59 description: 'my super description for server 2'
60 }
61 await uploadVideo(servers[1].url, servers[1].accessToken, video2Attributes)
62
63 // Wait videos propagation, server 2 has transcoding enabled
64 await waitJobs(servers)
65
66 const res = await getVideosList(servers[0].url)
67 const videos = res.body.data
68
69 expect(videos.length).to.equal(2)
70
71 servers[0].video = videos.find(video => video.name === 'my super name for server 1')
72 servers[1].video = videos.find(video => video.name === 'my super name for server 2')
73 })
74
75 it('Should not have video abuses', async function () {
76 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
77
78 expect(res.body.total).to.equal(0)
79 expect(res.body.data).to.be.an('array')
80 expect(res.body.data.length).to.equal(0)
81 })
82
83 it('Should report abuse on a local video', async function () {
84 this.timeout(15000)
85
86 const reason = 'my super bad reason'
87 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[0].video.id, reason)
88
89 // We wait requests propagation, even if the server 1 is not supposed to make a request to server 2
90 await waitJobs(servers)
91 })
92
93 it('Should have 1 video abuses on server 1 and 0 on server 2', async function () {
94 const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
95
96 expect(res1.body.total).to.equal(1)
97 expect(res1.body.data).to.be.an('array')
98 expect(res1.body.data.length).to.equal(1)
99
100 const abuse: AdminAbuse = res1.body.data[0]
101 expect(abuse.reason).to.equal('my super bad reason')
102 expect(abuse.reporterAccount.name).to.equal('root')
103 expect(abuse.reporterAccount.host).to.equal('localhost:' + servers[0].port)
104 expect(abuse.video.id).to.equal(servers[0].video.id)
105 expect(abuse.video.channel).to.exist
106 expect(abuse.video.countReports).to.equal(1)
107 expect(abuse.video.nthReport).to.equal(1)
108 expect(abuse.countReportsForReporter).to.equal(1)
109 expect(abuse.countReportsForReportee).to.equal(1)
110
111 const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
112 expect(res2.body.total).to.equal(0)
113 expect(res2.body.data).to.be.an('array')
114 expect(res2.body.data.length).to.equal(0)
115 })
116
117 it('Should report abuse on a remote video', async function () {
118 this.timeout(10000)
119
120 const reason = 'my super bad reason 2'
121 await reportVideoAbuse(servers[0].url, servers[0].accessToken, servers[1].video.id, reason)
122
123 // We wait requests propagation
124 await waitJobs(servers)
125 })
126
127 it('Should have 2 video abuses on server 1 and 1 on server 2', async function () {
128 const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
129 expect(res1.body.total).to.equal(2)
130 expect(res1.body.data).to.be.an('array')
131 expect(res1.body.data.length).to.equal(2)
132
133 const abuse1: AdminAbuse = res1.body.data[0]
134 expect(abuse1.reason).to.equal('my super bad reason')
135 expect(abuse1.reporterAccount.name).to.equal('root')
136 expect(abuse1.reporterAccount.host).to.equal('localhost:' + servers[0].port)
137 expect(abuse1.video.id).to.equal(servers[0].video.id)
138 expect(abuse1.state.id).to.equal(AbuseState.PENDING)
139 expect(abuse1.state.label).to.equal('Pending')
140 expect(abuse1.moderationComment).to.be.null
141 expect(abuse1.video.countReports).to.equal(1)
142 expect(abuse1.video.nthReport).to.equal(1)
143
144 const abuse2: AdminAbuse = res1.body.data[1]
145 expect(abuse2.reason).to.equal('my super bad reason 2')
146 expect(abuse2.reporterAccount.name).to.equal('root')
147 expect(abuse2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
148 expect(abuse2.video.id).to.equal(servers[1].video.id)
149 expect(abuse2.state.id).to.equal(AbuseState.PENDING)
150 expect(abuse2.state.label).to.equal('Pending')
151 expect(abuse2.moderationComment).to.be.null
152
153 const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
154 expect(res2.body.total).to.equal(1)
155 expect(res2.body.data).to.be.an('array')
156 expect(res2.body.data.length).to.equal(1)
157
158 abuseServer2 = res2.body.data[0]
159 expect(abuseServer2.reason).to.equal('my super bad reason 2')
160 expect(abuseServer2.reporterAccount.name).to.equal('root')
161 expect(abuseServer2.reporterAccount.host).to.equal('localhost:' + servers[0].port)
162 expect(abuseServer2.state.id).to.equal(AbuseState.PENDING)
163 expect(abuseServer2.state.label).to.equal('Pending')
164 expect(abuseServer2.moderationComment).to.be.null
165 })
166
167 it('Should update the state of a video abuse', async function () {
168 const body = { state: AbuseState.REJECTED }
169 await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body)
170
171 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
172 expect(res.body.data[0].state.id).to.equal(AbuseState.REJECTED)
173 })
174
175 it('Should add a moderation comment', async function () {
176 const body = { state: AbuseState.ACCEPTED, moderationComment: 'It is valid' }
177 await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body)
178
179 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
180 expect(res.body.data[0].state.id).to.equal(AbuseState.ACCEPTED)
181 expect(res.body.data[0].moderationComment).to.equal('It is valid')
182 })
183
184 it('Should hide video abuses from blocked accounts', async function () {
185 this.timeout(10000)
186
187 {
188 await reportVideoAbuse(servers[1].url, servers[1].accessToken, servers[0].video.uuid, 'will mute this')
189 await waitJobs(servers)
190
191 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
192 expect(res.body.total).to.equal(3)
193 }
194
195 const accountToBlock = 'root@localhost:' + servers[1].port
196
197 {
198 await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
199
200 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
201 expect(res.body.total).to.equal(2)
202
203 const abuse = res.body.data.find(a => a.reason === 'will mute this')
204 expect(abuse).to.be.undefined
205 }
206
207 {
208 await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
209
210 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
211 expect(res.body.total).to.equal(3)
212 }
213 })
214
215 it('Should hide video abuses from blocked servers', async function () {
216 const serverToBlock = servers[1].host
217
218 {
219 await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host)
220
221 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
222 expect(res.body.total).to.equal(2)
223
224 const abuse = res.body.data.find(a => a.reason === 'will mute this')
225 expect(abuse).to.be.undefined
226 }
227
228 {
229 await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock)
230
231 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
232 expect(res.body.total).to.equal(3)
233 }
234 })
235
236 it('Should keep the video abuse when deleting the video', async function () {
237 this.timeout(10000)
238
239 await removeVideo(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid)
240
241 await waitJobs(servers)
242
243 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
244 expect(res.body.total).to.equal(2, "wrong number of videos returned")
245 expect(res.body.data.length).to.equal(2, "wrong number of videos returned")
246 expect(res.body.data[0].id).to.equal(abuseServer2.id, "wrong origin server id for first video")
247
248 const abuse: AdminAbuse = res.body.data[0]
249 expect(abuse.video.id).to.equal(abuseServer2.video.id, "wrong video id")
250 expect(abuse.video.channel).to.exist
251 expect(abuse.video.deleted).to.be.true
252 })
253
254 it('Should include counts of reports from reporter and reportee', async function () {
255 this.timeout(10000)
256
257 // register a second user to have two reporters/reportees
258 const user = { username: 'user2', password: 'password' }
259 await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, ...user })
260 const userAccessToken = await userLogin(servers[0], user)
261
262 // upload a third video via this user
263 const video3Attributes = {
264 name: 'my second super name for server 1',
265 description: 'my second super description for server 1'
266 }
267 await uploadVideo(servers[0].url, userAccessToken, video3Attributes)
268
269 const res1 = await getVideosList(servers[0].url)
270 const videos = res1.body.data
271 const video3 = videos.find(video => video.name === 'my second super name for server 1')
272
273 // resume with the test
274 const reason3 = 'my super bad reason 3'
275 await reportVideoAbuse(servers[0].url, servers[0].accessToken, video3.id, reason3)
276 const reason4 = 'my super bad reason 4'
277 await reportVideoAbuse(servers[0].url, userAccessToken, servers[0].video.id, reason4)
278
279 const res2 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
280
281 {
282 for (const abuse of res2.body.data as AdminAbuse[]) {
283 if (abuse.video.id === video3.id) {
284 expect(abuse.video.countReports).to.equal(1, "wrong reports count for video 3")
285 expect(abuse.video.nthReport).to.equal(1, "wrong report position in report list for video 3")
286 expect(abuse.countReportsForReportee).to.equal(1, "wrong reports count for reporter on video 3 abuse")
287 expect(abuse.countReportsForReporter).to.equal(3, "wrong reports count for reportee on video 3 abuse")
288 }
289 if (abuse.video.id === servers[0].video.id) {
290 expect(abuse.countReportsForReportee).to.equal(3, "wrong reports count for reporter on video 1 abuse")
291 }
292 }
293 }
294 })
295
296 it('Should list predefined reasons as well as timestamps for the reported video', async function () {
297 this.timeout(10000)
298
299 const reason5 = 'my super bad reason 5'
300 const predefinedReasons5: AbusePredefinedReasonsString[] = [ 'violentOrRepulsive', 'captions' ]
301 const createdAbuse = (await reportVideoAbuse(
302 servers[0].url,
303 servers[0].accessToken,
304 servers[0].video.id,
305 reason5,
306 predefinedReasons5,
307 1,
308 5
309 )).body.abuse
310
311 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
312
313 {
314 const abuse = (res.body.data as AdminAbuse[]).find(a => a.id === createdAbuse.id)
315 expect(abuse.reason).to.equals(reason5)
316 expect(abuse.predefinedReasons).to.deep.equals(predefinedReasons5, "predefined reasons do not match the one reported")
317 expect(abuse.video.startAt).to.equal(1, "starting timestamp doesn't match the one reported")
318 expect(abuse.video.endAt).to.equal(5, "ending timestamp doesn't match the one reported")
319 }
320 })
321
322 it('Should delete the video abuse', async function () {
323 this.timeout(10000)
324
325 await deleteVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id)
326
327 await waitJobs(servers)
328
329 {
330 const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken })
331 expect(res.body.total).to.equal(1)
332 expect(res.body.data.length).to.equal(1)
333 expect(res.body.data[0].id).to.not.equal(abuseServer2.id)
334 }
335
336 {
337 const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken })
338 expect(res.body.total).to.equal(6)
339 }
340 })
341
342 it('Should list and filter video abuses', async function () {
343 async function list (query: Omit<Parameters<typeof getVideoAbusesList>[0], 'url' | 'token'>) {
344 const options = {
345 url: servers[0].url,
346 token: servers[0].accessToken
347 }
348
349 Object.assign(options, query)
350
351 const res = await getVideoAbusesList(options)
352
353 return res.body.data as AdminAbuse[]
354 }
355
356 expect(await list({ id: 56 })).to.have.lengthOf(0)
357 expect(await list({ id: 1 })).to.have.lengthOf(1)
358
359 expect(await list({ search: 'my super name for server 1' })).to.have.lengthOf(4)
360 expect(await list({ search: 'aaaaaaaaaaaaaaaaaaaaaaaaaa' })).to.have.lengthOf(0)
361
362 expect(await list({ searchVideo: 'my second super name for server 1' })).to.have.lengthOf(1)
363
364 expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(4)
365 expect(await list({ searchVideoChannel: 'aaaa' })).to.have.lengthOf(0)
366
367 expect(await list({ searchReporter: 'user2' })).to.have.lengthOf(1)
368 expect(await list({ searchReporter: 'root' })).to.have.lengthOf(5)
369
370 expect(await list({ searchReportee: 'root' })).to.have.lengthOf(5)
371 expect(await list({ searchReportee: 'aaaa' })).to.have.lengthOf(0)
372
373 expect(await list({ videoIs: 'deleted' })).to.have.lengthOf(1)
374 expect(await list({ videoIs: 'blacklisted' })).to.have.lengthOf(0)
375
376 expect(await list({ state: AbuseState.ACCEPTED })).to.have.lengthOf(0)
377 expect(await list({ state: AbuseState.PENDING })).to.have.lengthOf(6)
378
379 expect(await list({ predefinedReason: 'violentOrRepulsive' })).to.have.lengthOf(1)
380 expect(await list({ predefinedReason: 'serverRules' })).to.have.lengthOf(0)
381 })
382
383 after(async function () {
384 await cleanupTests(servers)
385 })
386})