diff options
author | Chocobozzz <me@florianbigard.com> | 2020-05-06 17:39:07 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2020-05-07 08:33:34 +0200 |
commit | feb34f6b6b991046aab6a10df747b48fa4da07a7 (patch) | |
tree | 02bb7277d45be166ba48caef2ee73bf89dbe1258 | |
parent | d170c5c580abf6f90d7bf144e2417e248ce2ecf4 (diff) | |
download | PeerTube-feb34f6b6b991046aab6a10df747b48fa4da07a7.tar.gz PeerTube-feb34f6b6b991046aab6a10df747b48fa4da07a7.tar.zst PeerTube-feb34f6b6b991046aab6a10df747b48fa4da07a7.zip |
Use video abuse filters on client side
-rw-r--r-- | client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html | 4 | ||||
-rw-r--r-- | client/src/app/shared/rest/rest.service.ts | 63 | ||||
-rw-r--r-- | client/src/app/shared/video-abuse/video-abuse.service.ts | 31 | ||||
-rw-r--r-- | server/controllers/api/videos/abuse.ts | 11 | ||||
-rw-r--r-- | server/helpers/custom-validators/video-abuses.ts | 10 | ||||
-rw-r--r-- | server/middlewares/validators/videos/video-abuses.ts | 45 | ||||
-rw-r--r-- | server/models/utils.ts | 60 | ||||
-rw-r--r-- | server/models/video/video-abuse.ts | 127 | ||||
-rw-r--r-- | server/tests/api/check-params/video-abuses.ts | 16 | ||||
-rw-r--r-- | server/tests/api/users/users.ts | 2 | ||||
-rw-r--r-- | server/tests/api/videos/video-abuse.ts | 70 | ||||
-rw-r--r-- | shared/extra-utils/videos/video-abuses.ts | 55 | ||||
-rw-r--r-- | shared/models/videos/abuse/video-abuse-video-is.type.ts | 1 |
13 files changed, 342 insertions, 153 deletions
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html index ba05073cf..cffa7a40e 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html | |||
@@ -19,8 +19,8 @@ | |||
19 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:pending' }" class="dropdown-item" i18n>Unsolved reports</a> | 19 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:pending' }" class="dropdown-item" i18n>Unsolved reports</a> |
20 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:accepted' }" class="dropdown-item" i18n>Accepted reports</a> | 20 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:accepted' }" class="dropdown-item" i18n>Accepted reports</a> |
21 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:rejected' }" class="dropdown-item" i18n>Refused reports</a> | 21 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:rejected' }" class="dropdown-item" i18n>Refused reports</a> |
22 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'is:blacklisted' }" class="dropdown-item" i18n>Reports with blacklisted videos</a> | 22 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'videoIs:blacklisted' }" class="dropdown-item" i18n>Reports with blacklisted videos</a> |
23 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'is:deleted' }" class="dropdown-item" i18n>Reports with deleted videos</a> | 23 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'videoIs:deleted' }" class="dropdown-item" i18n>Reports with deleted videos</a> |
24 | </div> | 24 | </div> |
25 | </div> | 25 | </div> |
26 | <input | 26 | <input |
diff --git a/client/src/app/shared/rest/rest.service.ts b/client/src/app/shared/rest/rest.service.ts index 5bd2b5e43..cd6db1f3c 100644 --- a/client/src/app/shared/rest/rest.service.ts +++ b/client/src/app/shared/rest/rest.service.ts | |||
@@ -1,10 +1,21 @@ | |||
1 | import { Injectable } from '@angular/core' | ||
2 | import { HttpParams } from '@angular/common/http' | ||
3 | import { SortMeta } from 'primeng/api' | 1 | import { SortMeta } from 'primeng/api' |
4 | import { ComponentPagination, ComponentPaginationLight } from './component-pagination.model' | 2 | import { HttpParams } from '@angular/common/http' |
5 | 3 | import { Injectable } from '@angular/core' | |
4 | import { ComponentPaginationLight } from './component-pagination.model' | ||
6 | import { RestPagination } from './rest-pagination' | 5 | import { RestPagination } from './rest-pagination' |
7 | 6 | ||
7 | interface QueryStringFilterPrefixes { | ||
8 | [key: string]: { | ||
9 | prefix: string | ||
10 | handler?: (v: string) => string | number | ||
11 | multiple?: boolean | ||
12 | } | ||
13 | } | ||
14 | |||
15 | type ParseQueryStringFilterResult = { | ||
16 | [key: string]: string | number | (string | number)[] | ||
17 | } | ||
18 | |||
8 | @Injectable() | 19 | @Injectable() |
9 | export class RestService { | 20 | export class RestService { |
10 | 21 | ||
@@ -53,4 +64,48 @@ export class RestService { | |||
53 | 64 | ||
54 | return { start, count } | 65 | return { start, count } |
55 | } | 66 | } |
67 | |||
68 | parseQueryStringFilter (q: string, prefixes: QueryStringFilterPrefixes): ParseQueryStringFilterResult { | ||
69 | if (!q) return {} | ||
70 | |||
71 | // Tokenize the strings using spaces | ||
72 | const tokens = q.split(' ').filter(token => !!token) | ||
73 | |||
74 | // Build prefix array | ||
75 | const prefixeStrings = Object.values(prefixes) | ||
76 | .map(p => p.prefix) | ||
77 | |||
78 | // Search is the querystring minus defined filters | ||
79 | const searchTokens = tokens.filter(t => { | ||
80 | return prefixeStrings.every(prefixString => t.startsWith(prefixString) === false) | ||
81 | }) | ||
82 | |||
83 | const additionalFilters: ParseQueryStringFilterResult = {} | ||
84 | |||
85 | for (const prefixKey of Object.keys(prefixes)) { | ||
86 | const prefixObj = prefixes[prefixKey] | ||
87 | const prefix = prefixObj.prefix | ||
88 | |||
89 | const matchedTokens = tokens.filter(t => t.startsWith(prefix)) | ||
90 | .map(t => t.slice(prefix.length)) // Keep the value filter | ||
91 | .map(t => { | ||
92 | if (prefixObj.handler) return prefixObj.handler(t) | ||
93 | |||
94 | return t | ||
95 | }) | ||
96 | .filter(t => !!t) | ||
97 | |||
98 | if (matchedTokens.length === 0) continue | ||
99 | |||
100 | additionalFilters[prefixKey] = prefixObj.multiple === true | ||
101 | ? matchedTokens | ||
102 | : matchedTokens[0] | ||
103 | } | ||
104 | |||
105 | return { | ||
106 | search: searchTokens.join(' '), | ||
107 | |||
108 | ...additionalFilters | ||
109 | } | ||
110 | } | ||
56 | } | 111 | } |
diff --git a/client/src/app/shared/video-abuse/video-abuse.service.ts b/client/src/app/shared/video-abuse/video-abuse.service.ts index 1ab6b5376..700a30239 100644 --- a/client/src/app/shared/video-abuse/video-abuse.service.ts +++ b/client/src/app/shared/video-abuse/video-abuse.service.ts | |||
@@ -3,7 +3,7 @@ import { HttpClient, HttpParams } from '@angular/common/http' | |||
3 | import { Injectable } from '@angular/core' | 3 | import { Injectable } from '@angular/core' |
4 | import { SortMeta } from 'primeng/api' | 4 | import { SortMeta } from 'primeng/api' |
5 | import { Observable } from 'rxjs' | 5 | import { Observable } from 'rxjs' |
6 | import { ResultList, VideoAbuse, VideoAbuseUpdate } from '../../../../../shared' | 6 | import { ResultList, VideoAbuse, VideoAbuseUpdate, VideoAbuseState } from '../../../../../shared' |
7 | import { environment } from '../../../environments/environment' | 7 | import { environment } from '../../../environments/environment' |
8 | import { RestExtractor, RestPagination, RestService } from '../rest' | 8 | import { RestExtractor, RestPagination, RestService } from '../rest' |
9 | 9 | ||
@@ -28,7 +28,34 @@ export class VideoAbuseService { | |||
28 | let params = new HttpParams() | 28 | let params = new HttpParams() |
29 | params = this.restService.addRestGetParams(params, pagination, sort) | 29 | params = this.restService.addRestGetParams(params, pagination, sort) |
30 | 30 | ||
31 | if (search) params = params.append('search', search) | 31 | if (search) { |
32 | const filters = this.restService.parseQueryStringFilter(search, { | ||
33 | id: { prefix: '#' }, | ||
34 | state: { | ||
35 | prefix: 'state:', | ||
36 | handler: v => { | ||
37 | if (v === 'accepted') return VideoAbuseState.ACCEPTED | ||
38 | if (v === 'pending') return VideoAbuseState.PENDING | ||
39 | if (v === 'rejected') return VideoAbuseState.REJECTED | ||
40 | |||
41 | return undefined | ||
42 | } | ||
43 | }, | ||
44 | videoIs: { | ||
45 | prefix: 'videoIs:', | ||
46 | handler: v => { | ||
47 | if (v === 'deleted') return v | ||
48 | if (v === 'blacklisted') return v | ||
49 | |||
50 | return undefined | ||
51 | } | ||
52 | }, | ||
53 | searchReporter: { prefix: 'reporter:' }, | ||
54 | searchReportee: { prefix: 'reportee:' } | ||
55 | }) | ||
56 | |||
57 | params = this.restService.addObjectParams(params, filters) | ||
58 | } | ||
32 | 59 | ||
33 | return this.authHttp.get<ResultList<VideoAbuse>>(url, { params }) | 60 | return this.authHttp.get<ResultList<VideoAbuse>>(url, { params }) |
34 | .pipe( | 61 | .pipe( |
diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts index bc7df48c8..3fe7f7e51 100644 --- a/server/controllers/api/videos/abuse.ts +++ b/server/controllers/api/videos/abuse.ts | |||
@@ -14,7 +14,8 @@ import { | |||
14 | videoAbuseGetValidator, | 14 | videoAbuseGetValidator, |
15 | videoAbuseReportValidator, | 15 | videoAbuseReportValidator, |
16 | videoAbusesSortValidator, | 16 | videoAbusesSortValidator, |
17 | videoAbuseUpdateValidator | 17 | videoAbuseUpdateValidator, |
18 | videoAbuseListValidator | ||
18 | } from '../../../middlewares' | 19 | } from '../../../middlewares' |
19 | import { AccountModel } from '../../../models/account/account' | 20 | import { AccountModel } from '../../../models/account/account' |
20 | import { VideoAbuseModel } from '../../../models/video/video-abuse' | 21 | import { VideoAbuseModel } from '../../../models/video/video-abuse' |
@@ -34,6 +35,7 @@ abuseVideoRouter.get('/abuse', | |||
34 | videoAbusesSortValidator, | 35 | videoAbusesSortValidator, |
35 | setDefaultSort, | 36 | setDefaultSort, |
36 | setDefaultPagination, | 37 | setDefaultPagination, |
38 | videoAbuseListValidator, | ||
37 | asyncMiddleware(listVideoAbuses) | 39 | asyncMiddleware(listVideoAbuses) |
38 | ) | 40 | ) |
39 | abuseVideoRouter.put('/:videoId/abuse/:id', | 41 | abuseVideoRouter.put('/:videoId/abuse/:id', |
@@ -70,7 +72,14 @@ async function listVideoAbuses (req: express.Request, res: express.Response) { | |||
70 | start: req.query.start, | 72 | start: req.query.start, |
71 | count: req.query.count, | 73 | count: req.query.count, |
72 | sort: req.query.sort, | 74 | sort: req.query.sort, |
75 | id: req.query.id, | ||
73 | search: req.query.search, | 76 | search: req.query.search, |
77 | state: req.query.state, | ||
78 | videoIs: req.query.videoIs, | ||
79 | searchReporter: req.query.searchReporter, | ||
80 | searchReportee: req.query.searchReportee, | ||
81 | searchVideo: req.query.searchVideo, | ||
82 | searchVideoChannel: req.query.searchVideoChannel, | ||
74 | serverAccountId: serverActor.Account.id, | 83 | serverAccountId: serverActor.Account.id, |
75 | user | 84 | user |
76 | }) | 85 | }) |
diff --git a/server/helpers/custom-validators/video-abuses.ts b/server/helpers/custom-validators/video-abuses.ts index 5c7bc6fd9..05e11b1c6 100644 --- a/server/helpers/custom-validators/video-abuses.ts +++ b/server/helpers/custom-validators/video-abuses.ts | |||
@@ -1,6 +1,8 @@ | |||
1 | import validator from 'validator' | 1 | import validator from 'validator' |
2 | |||
2 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' | 3 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' |
3 | import { exists } from './misc' | 4 | import { exists } from './misc' |
5 | import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type' | ||
4 | 6 | ||
5 | const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES | 7 | const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES |
6 | 8 | ||
@@ -16,10 +18,18 @@ function isVideoAbuseStateValid (value: string) { | |||
16 | return exists(value) && VIDEO_ABUSE_STATES[value] !== undefined | 18 | return exists(value) && VIDEO_ABUSE_STATES[value] !== undefined |
17 | } | 19 | } |
18 | 20 | ||
21 | function isAbuseVideoIsValid (value: VideoAbuseVideoIs) { | ||
22 | return exists(value) && ( | ||
23 | value === 'deleted' || | ||
24 | value === 'blacklisted' | ||
25 | ) | ||
26 | } | ||
27 | |||
19 | // --------------------------------------------------------------------------- | 28 | // --------------------------------------------------------------------------- |
20 | 29 | ||
21 | export { | 30 | export { |
22 | isVideoAbuseStateValid, | 31 | isVideoAbuseStateValid, |
23 | isVideoAbuseReasonValid, | 32 | isVideoAbuseReasonValid, |
33 | isAbuseVideoIsValid, | ||
24 | isVideoAbuseModerationCommentValid | 34 | isVideoAbuseModerationCommentValid |
25 | } | 35 | } |
diff --git a/server/middlewares/validators/videos/video-abuses.ts b/server/middlewares/validators/videos/video-abuses.ts index 7c316fe13..901997bcb 100644 --- a/server/middlewares/validators/videos/video-abuses.ts +++ b/server/middlewares/validators/videos/video-abuses.ts | |||
@@ -1,14 +1,15 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { body, param } from 'express-validator' | 2 | import { body, param, query } from 'express-validator' |
3 | import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' | 3 | import { exists, isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' |
4 | import { logger } from '../../../helpers/logger' | ||
5 | import { areValidationErrors } from '../utils' | ||
6 | import { | 4 | import { |
5 | isAbuseVideoIsValid, | ||
7 | isVideoAbuseModerationCommentValid, | 6 | isVideoAbuseModerationCommentValid, |
8 | isVideoAbuseReasonValid, | 7 | isVideoAbuseReasonValid, |
9 | isVideoAbuseStateValid | 8 | isVideoAbuseStateValid |
10 | } from '../../../helpers/custom-validators/video-abuses' | 9 | } from '../../../helpers/custom-validators/video-abuses' |
10 | import { logger } from '../../../helpers/logger' | ||
11 | import { doesVideoAbuseExist, doesVideoExist } from '../../../helpers/middlewares' | 11 | import { doesVideoAbuseExist, doesVideoExist } from '../../../helpers/middlewares' |
12 | import { areValidationErrors } from '../utils' | ||
12 | 13 | ||
13 | const videoAbuseReportValidator = [ | 14 | const videoAbuseReportValidator = [ |
14 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), | 15 | param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), |
@@ -58,9 +59,45 @@ const videoAbuseUpdateValidator = [ | |||
58 | } | 59 | } |
59 | ] | 60 | ] |
60 | 61 | ||
62 | const videoAbuseListValidator = [ | ||
63 | query('id') | ||
64 | .optional() | ||
65 | .custom(isIdValid).withMessage('Should have a valid id'), | ||
66 | query('search') | ||
67 | .optional() | ||
68 | .custom(exists).withMessage('Should have a valid search'), | ||
69 | query('state') | ||
70 | .optional() | ||
71 | .custom(isVideoAbuseStateValid).withMessage('Should have a valid video abuse state'), | ||
72 | query('videoIs') | ||
73 | .optional() | ||
74 | .custom(isAbuseVideoIsValid).withMessage('Should have a valid "video is" attribute'), | ||
75 | query('searchReporter') | ||
76 | .optional() | ||
77 | .custom(exists).withMessage('Should have a valid reporter search'), | ||
78 | query('searchReportee') | ||
79 | .optional() | ||
80 | .custom(exists).withMessage('Should have a valid reportee search'), | ||
81 | query('searchVideo') | ||
82 | .optional() | ||
83 | .custom(exists).withMessage('Should have a valid video search'), | ||
84 | query('searchVideoChannel') | ||
85 | .optional() | ||
86 | .custom(exists).withMessage('Should have a valid video channel search'), | ||
87 | |||
88 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
89 | logger.debug('Checking videoAbuseListValidator parameters', { parameters: req.body }) | ||
90 | |||
91 | if (areValidationErrors(req, res)) return | ||
92 | |||
93 | return next() | ||
94 | } | ||
95 | ] | ||
96 | |||
61 | // --------------------------------------------------------------------------- | 97 | // --------------------------------------------------------------------------- |
62 | 98 | ||
63 | export { | 99 | export { |
100 | videoAbuseListValidator, | ||
64 | videoAbuseReportValidator, | 101 | videoAbuseReportValidator, |
65 | videoAbuseGetValidator, | 102 | videoAbuseGetValidator, |
66 | videoAbuseUpdateValidator | 103 | videoAbuseUpdateValidator |
diff --git a/server/models/utils.ts b/server/models/utils.ts index fe4596d31..b2573cd35 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts | |||
@@ -207,60 +207,13 @@ function buildDirectionAndField (value: string) { | |||
207 | return { direction, field } | 207 | return { direction, field } |
208 | } | 208 | } |
209 | 209 | ||
210 | function searchAttribute (sourceField, targetField) { | 210 | function searchAttribute (sourceField?: string, targetField?: string) { |
211 | if (sourceField) { | 211 | if (!sourceField) return {} |
212 | return { | ||
213 | [targetField]: { | ||
214 | [Op.iLike]: `%${sourceField}%` | ||
215 | } | ||
216 | } | ||
217 | } else { | ||
218 | return {} | ||
219 | } | ||
220 | } | ||
221 | |||
222 | interface QueryStringFilterPrefixes { | ||
223 | [key: string]: string | { prefix: string, handler: Function, multiple?: boolean } | ||
224 | } | ||
225 | |||
226 | function parseQueryStringFilter (q: string, prefixes: QueryStringFilterPrefixes): { | ||
227 | search: string | ||
228 | [key: string]: string | number | string[] | number[] | ||
229 | } { | ||
230 | const tokens = q // tokenize only if we have a querystring | ||
231 | ? [].concat.apply([], q.split('"').map((v, i) => i % 2 ? v : v.split(' '))).filter(Boolean) // split by space unless using double quotes | ||
232 | : [] | ||
233 | |||
234 | const objectMap = (obj, fn) => Object.fromEntries( | ||
235 | Object.entries(obj).map( | ||
236 | ([ k, v ], i) => [ k, fn(v, k, i) ] | ||
237 | ) | ||
238 | ) | ||
239 | 212 | ||
240 | return { | 213 | return { |
241 | // search is the querystring minus defined filters | 214 | [targetField]: { |
242 | search: tokens.filter(e => !Object.values(prefixes).some(p => { | 215 | [Op.iLike]: `%${sourceField}%` |
243 | if (typeof p === 'string') { | 216 | } |
244 | return e.startsWith(p) | ||
245 | } else { | ||
246 | return e.startsWith(p.prefix) | ||
247 | } | ||
248 | })).join(' '), | ||
249 | // filters defined in prefixes are added under their own name | ||
250 | ...objectMap(prefixes, p => { | ||
251 | if (typeof p === 'string') { | ||
252 | return tokens.filter(e => e.startsWith(p)).map(e => e.slice(p.length)) // we keep the matched item, and remove its prefix | ||
253 | } else { | ||
254 | const _tokens = tokens.filter(e => e.startsWith(p.prefix)).map(e => e.slice(p.prefix.length)).map(p.handler) | ||
255 | // multiple is false by default, meaning we usually just keep the first occurence of a given prefix | ||
256 | if (!p.multiple && _tokens.length > 0) { | ||
257 | return _tokens[0] | ||
258 | } else if (!p.multiple) { | ||
259 | return '' | ||
260 | } | ||
261 | return _tokens | ||
262 | } | ||
263 | }) | ||
264 | } | 217 | } |
265 | } | 218 | } |
266 | 219 | ||
@@ -286,8 +239,7 @@ export { | |||
286 | getFollowsSort, | 239 | getFollowsSort, |
287 | buildDirectionAndField, | 240 | buildDirectionAndField, |
288 | createSafeIn, | 241 | createSafeIn, |
289 | searchAttribute, | 242 | searchAttribute |
290 | parseQueryStringFilter | ||
291 | } | 243 | } |
292 | 244 | ||
293 | // --------------------------------------------------------------------------- | 245 | // --------------------------------------------------------------------------- |
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts index 6cd2c0418..0844f702d 100644 --- a/server/models/video/video-abuse.ts +++ b/server/models/video/video-abuse.ts | |||
@@ -1,6 +1,21 @@ | |||
1 | import * as Bluebird from 'bluebird' | ||
2 | import { literal, Op } from 'sequelize' | ||
1 | import { | 3 | import { |
2 | AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt, Scopes | 4 | AllowNull, |
5 | BelongsTo, | ||
6 | Column, | ||
7 | CreatedAt, | ||
8 | DataType, | ||
9 | Default, | ||
10 | ForeignKey, | ||
11 | Is, | ||
12 | Model, | ||
13 | Scopes, | ||
14 | Table, | ||
15 | UpdatedAt | ||
3 | } from 'sequelize-typescript' | 16 | } from 'sequelize-typescript' |
17 | import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type' | ||
18 | import { VideoAbuseState, VideoDetails } from '../../../shared' | ||
4 | import { VideoAbuseObject } from '../../../shared/models/activitypub/objects' | 19 | import { VideoAbuseObject } from '../../../shared/models/activitypub/objects' |
5 | import { VideoAbuse } from '../../../shared/models/videos' | 20 | import { VideoAbuse } from '../../../shared/models/videos' |
6 | import { | 21 | import { |
@@ -8,15 +23,12 @@ import { | |||
8 | isVideoAbuseReasonValid, | 23 | isVideoAbuseReasonValid, |
9 | isVideoAbuseStateValid | 24 | isVideoAbuseStateValid |
10 | } from '../../helpers/custom-validators/video-abuses' | 25 | } from '../../helpers/custom-validators/video-abuses' |
11 | import { AccountModel } from '../account/account' | ||
12 | import { buildBlockedAccountSQL, getSort, throwIfNotValid, searchAttribute, parseQueryStringFilter } from '../utils' | ||
13 | import { VideoModel } from './video' | ||
14 | import { VideoAbuseState, VideoDetails } from '../../../shared' | ||
15 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' | 26 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' |
16 | import { MUserAccountId, MVideoAbuse, MVideoAbuseFormattable, MVideoAbuseVideo } from '../../typings/models' | 27 | import { MUserAccountId, MVideoAbuse, MVideoAbuseFormattable, MVideoAbuseVideo } from '../../typings/models' |
17 | import * as Bluebird from 'bluebird' | 28 | import { AccountModel } from '../account/account' |
18 | import { literal, Op } from 'sequelize' | 29 | import { buildBlockedAccountSQL, getSort, searchAttribute, throwIfNotValid } from '../utils' |
19 | import { ThumbnailModel } from './thumbnail' | 30 | import { ThumbnailModel } from './thumbnail' |
31 | import { VideoModel } from './video' | ||
20 | import { VideoBlacklistModel } from './video-blacklist' | 32 | import { VideoBlacklistModel } from './video-blacklist' |
21 | import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel' | 33 | import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel' |
22 | 34 | ||
@@ -35,21 +47,22 @@ export enum ScopeNames { | |||
35 | 47 | ||
36 | // filters | 48 | // filters |
37 | id?: number | 49 | id?: number |
50 | |||
38 | state?: VideoAbuseState | 51 | state?: VideoAbuseState |
39 | is?: 'deleted' | 'blacklisted' | 52 | videoIs?: VideoAbuseVideoIs |
40 | 53 | ||
41 | // accountIds | 54 | // accountIds |
42 | serverAccountId: number | 55 | serverAccountId: number |
43 | userAccountId: number | 56 | userAccountId: number |
44 | }) => { | 57 | }) => { |
45 | let where = { | 58 | const where = { |
46 | reporterAccountId: { | 59 | reporterAccountId: { |
47 | [Op.notIn]: literal('(' + buildBlockedAccountSQL(options.serverAccountId, options.userAccountId) + ')') | 60 | [Op.notIn]: literal('(' + buildBlockedAccountSQL(options.serverAccountId, options.userAccountId) + ')') |
48 | } | 61 | } |
49 | } | 62 | } |
50 | 63 | ||
51 | if (options.search) { | 64 | if (options.search) { |
52 | where = Object.assign(where, { | 65 | Object.assign(where, { |
53 | [Op.or]: [ | 66 | [Op.or]: [ |
54 | { | 67 | { |
55 | [Op.and]: [ | 68 | [Op.and]: [ |
@@ -80,26 +93,18 @@ export enum ScopeNames { | |||
80 | }) | 93 | }) |
81 | } | 94 | } |
82 | 95 | ||
83 | if (options.id) { | 96 | if (options.id) Object.assign(where, { id: options.id }) |
84 | where = Object.assign(where, { | 97 | if (options.state) Object.assign(where, { state: options.state }) |
85 | id: options.id | ||
86 | }) | ||
87 | } | ||
88 | 98 | ||
89 | if (options.state) { | 99 | if (options.videoIs === 'deleted') { |
90 | where = Object.assign(where, { | 100 | Object.assign(where, { |
91 | state: options.state | 101 | deletedVideo: { |
102 | [Op.not]: null | ||
103 | } | ||
92 | }) | 104 | }) |
93 | } | 105 | } |
94 | 106 | ||
95 | let onlyBlacklisted = false | 107 | const onlyBlacklisted = options.videoIs === 'blacklisted' |
96 | if (options.is === 'deleted') { | ||
97 | where = Object.assign(where, { | ||
98 | deletedVideo: { [Op.not]: null } | ||
99 | }) | ||
100 | } else if (options.is === 'blacklisted') { | ||
101 | onlyBlacklisted = true | ||
102 | } | ||
103 | 108 | ||
104 | return { | 109 | return { |
105 | attributes: { | 110 | attributes: { |
@@ -189,7 +194,7 @@ export enum ScopeNames { | |||
189 | }, | 194 | }, |
190 | { | 195 | { |
191 | model: VideoModel, | 196 | model: VideoModel, |
192 | required: onlyBlacklisted, | 197 | required: !!(onlyBlacklisted || options.searchVideo || options.searchReportee || options.searchVideoChannel), |
193 | where: searchAttribute(options.searchVideo, 'name'), | 198 | where: searchAttribute(options.searchVideo, 'name'), |
194 | include: [ | 199 | include: [ |
195 | { | 200 | { |
@@ -301,11 +306,36 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
301 | start: number | 306 | start: number |
302 | count: number | 307 | count: number |
303 | sort: string | 308 | sort: string |
304 | search?: string | 309 | |
305 | serverAccountId: number | 310 | serverAccountId: number |
306 | user?: MUserAccountId | 311 | user?: MUserAccountId |
312 | |||
313 | id?: number | ||
314 | state?: VideoAbuseState | ||
315 | videoIs?: VideoAbuseVideoIs | ||
316 | |||
317 | search?: string | ||
318 | searchReporter?: string | ||
319 | searchReportee?: string | ||
320 | searchVideo?: string | ||
321 | searchVideoChannel?: string | ||
307 | }) { | 322 | }) { |
308 | const { start, count, sort, search, user, serverAccountId } = parameters | 323 | const { |
324 | start, | ||
325 | count, | ||
326 | sort, | ||
327 | search, | ||
328 | user, | ||
329 | serverAccountId, | ||
330 | state, | ||
331 | videoIs, | ||
332 | searchReportee, | ||
333 | searchVideo, | ||
334 | searchVideoChannel, | ||
335 | searchReporter, | ||
336 | id | ||
337 | } = parameters | ||
338 | |||
309 | const userAccountId = user ? user.Account.id : undefined | 339 | const userAccountId = user ? user.Account.id : undefined |
310 | 340 | ||
311 | const query = { | 341 | const query = { |
@@ -317,37 +347,14 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
317 | } | 347 | } |
318 | 348 | ||
319 | const filters = { | 349 | const filters = { |
320 | ...parseQueryStringFilter(search, { | 350 | id, |
321 | id: { | 351 | search, |
322 | prefix: '#', | 352 | state, |
323 | handler: v => v | 353 | videoIs, |
324 | }, | 354 | searchReportee, |
325 | state: { | 355 | searchVideo, |
326 | prefix: 'state:', | 356 | searchVideoChannel, |
327 | handler: v => { | 357 | searchReporter, |
328 | if (v === 'accepted') return VideoAbuseState.ACCEPTED | ||
329 | if (v === 'pending') return VideoAbuseState.PENDING | ||
330 | if (v === 'rejected') return VideoAbuseState.REJECTED | ||
331 | return undefined | ||
332 | } | ||
333 | }, | ||
334 | is: { | ||
335 | prefix: 'is:', | ||
336 | handler: v => { | ||
337 | if (v === 'deleted') return v | ||
338 | if (v === 'blacklisted') return v | ||
339 | return undefined | ||
340 | } | ||
341 | }, | ||
342 | searchReporter: { | ||
343 | prefix: 'reporter:', | ||
344 | handler: v => v | ||
345 | }, | ||
346 | searchReportee: { | ||
347 | prefix: 'reportee:', | ||
348 | handler: v => v | ||
349 | } | ||
350 | }), | ||
351 | serverAccountId, | 358 | serverAccountId, |
352 | userAccountId | 359 | userAccountId |
353 | } | 360 | } |
diff --git a/server/tests/api/check-params/video-abuses.ts b/server/tests/api/check-params/video-abuses.ts index bea2177f3..e643cb95e 100644 --- a/server/tests/api/check-params/video-abuses.ts +++ b/server/tests/api/check-params/video-abuses.ts | |||
@@ -76,6 +76,22 @@ describe('Test video abuses API validators', function () { | |||
76 | statusCodeExpected: 403 | 76 | statusCodeExpected: 403 |
77 | }) | 77 | }) |
78 | }) | 78 | }) |
79 | |||
80 | it('Should fail with a bad id filter', async function () { | ||
81 | await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { id: 'toto' } }) | ||
82 | }) | ||
83 | |||
84 | it('Should fail with a bad state filter', async function () { | ||
85 | await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { state: 'toto' } }) | ||
86 | }) | ||
87 | |||
88 | it('Should fail with a bad videoIs filter', async function () { | ||
89 | await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { videoIs: 'toto' } }) | ||
90 | }) | ||
91 | |||
92 | it('Should succeed with the correct params', async function () { | ||
93 | await makeGetRequest({ url: server.url, path, token: server.accessToken, query: { id: 13 }, statusCodeExpected: 200 }) | ||
94 | }) | ||
79 | }) | 95 | }) |
80 | 96 | ||
81 | describe('When reporting a video abuse', function () { | 97 | describe('When reporting a video abuse', function () { |
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index 60fbd2a20..f3b732632 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts | |||
@@ -901,7 +901,7 @@ describe('Test users', function () { | |||
901 | const reason = 'my super bad reason' | 901 | const reason = 'my super bad reason' |
902 | await reportVideoAbuse(server.url, user17AccessToken, videoId, reason) | 902 | await reportVideoAbuse(server.url, user17AccessToken, videoId, reason) |
903 | 903 | ||
904 | const res1 = await getVideoAbusesList(server.url, server.accessToken) | 904 | const res1 = await getVideoAbusesList({ url: server.url, token: server.accessToken }) |
905 | const abuseId = res1.body.data[0].id | 905 | const abuseId = res1.body.data[0].id |
906 | 906 | ||
907 | const res2 = await getUserInformation(server.url, server.accessToken, user17Id, true) | 907 | const res2 = await getUserInformation(server.url, server.accessToken, user17Id, true) |
diff --git a/server/tests/api/videos/video-abuse.ts b/server/tests/api/videos/video-abuse.ts index 26bc3783b..a96be97f6 100644 --- a/server/tests/api/videos/video-abuse.ts +++ b/server/tests/api/videos/video-abuse.ts | |||
@@ -71,7 +71,7 @@ describe('Test video abuses', function () { | |||
71 | }) | 71 | }) |
72 | 72 | ||
73 | it('Should not have video abuses', async function () { | 73 | it('Should not have video abuses', async function () { |
74 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 74 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
75 | 75 | ||
76 | expect(res.body.total).to.equal(0) | 76 | expect(res.body.total).to.equal(0) |
77 | expect(res.body.data).to.be.an('array') | 77 | expect(res.body.data).to.be.an('array') |
@@ -89,7 +89,7 @@ describe('Test video abuses', function () { | |||
89 | }) | 89 | }) |
90 | 90 | ||
91 | it('Should have 1 video abuses on server 1 and 0 on server 2', async function () { | 91 | it('Should have 1 video abuses on server 1 and 0 on server 2', async function () { |
92 | const res1 = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 92 | const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
93 | 93 | ||
94 | expect(res1.body.total).to.equal(1) | 94 | expect(res1.body.total).to.equal(1) |
95 | expect(res1.body.data).to.be.an('array') | 95 | expect(res1.body.data).to.be.an('array') |
@@ -106,7 +106,7 @@ describe('Test video abuses', function () { | |||
106 | expect(abuse.countReportsForReporter).to.equal(1) | 106 | expect(abuse.countReportsForReporter).to.equal(1) |
107 | expect(abuse.countReportsForReportee).to.equal(1) | 107 | expect(abuse.countReportsForReportee).to.equal(1) |
108 | 108 | ||
109 | const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken) | 109 | const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken }) |
110 | expect(res2.body.total).to.equal(0) | 110 | expect(res2.body.total).to.equal(0) |
111 | expect(res2.body.data).to.be.an('array') | 111 | expect(res2.body.data).to.be.an('array') |
112 | expect(res2.body.data.length).to.equal(0) | 112 | expect(res2.body.data.length).to.equal(0) |
@@ -123,7 +123,7 @@ describe('Test video abuses', function () { | |||
123 | }) | 123 | }) |
124 | 124 | ||
125 | it('Should have 2 video abuses on server 1 and 1 on server 2', async function () { | 125 | it('Should have 2 video abuses on server 1 and 1 on server 2', async function () { |
126 | const res1 = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 126 | const res1 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
127 | expect(res1.body.total).to.equal(2) | 127 | expect(res1.body.total).to.equal(2) |
128 | expect(res1.body.data).to.be.an('array') | 128 | expect(res1.body.data).to.be.an('array') |
129 | expect(res1.body.data.length).to.equal(2) | 129 | expect(res1.body.data.length).to.equal(2) |
@@ -148,7 +148,7 @@ describe('Test video abuses', function () { | |||
148 | expect(abuse2.state.label).to.equal('Pending') | 148 | expect(abuse2.state.label).to.equal('Pending') |
149 | expect(abuse2.moderationComment).to.be.null | 149 | expect(abuse2.moderationComment).to.be.null |
150 | 150 | ||
151 | const res2 = await getVideoAbusesList(servers[1].url, servers[1].accessToken) | 151 | const res2 = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken }) |
152 | expect(res2.body.total).to.equal(1) | 152 | expect(res2.body.total).to.equal(1) |
153 | expect(res2.body.data).to.be.an('array') | 153 | expect(res2.body.data).to.be.an('array') |
154 | expect(res2.body.data.length).to.equal(1) | 154 | expect(res2.body.data.length).to.equal(1) |
@@ -166,7 +166,7 @@ describe('Test video abuses', function () { | |||
166 | const body = { state: VideoAbuseState.REJECTED } | 166 | const body = { state: VideoAbuseState.REJECTED } |
167 | await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body) | 167 | await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body) |
168 | 168 | ||
169 | const res = await getVideoAbusesList(servers[1].url, servers[1].accessToken) | 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) | 170 | expect(res.body.data[0].state.id).to.equal(VideoAbuseState.REJECTED) |
171 | }) | 171 | }) |
172 | 172 | ||
@@ -174,7 +174,7 @@ describe('Test video abuses', function () { | |||
174 | const body = { state: VideoAbuseState.ACCEPTED, moderationComment: 'It is valid' } | 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) | 175 | await updateVideoAbuse(servers[1].url, servers[1].accessToken, abuseServer2.video.uuid, abuseServer2.id, body) |
176 | 176 | ||
177 | const res = await getVideoAbusesList(servers[1].url, servers[1].accessToken) | 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) | 178 | expect(res.body.data[0].state.id).to.equal(VideoAbuseState.ACCEPTED) |
179 | expect(res.body.data[0].moderationComment).to.equal('It is valid') | 179 | expect(res.body.data[0].moderationComment).to.equal('It is valid') |
180 | }) | 180 | }) |
@@ -186,7 +186,7 @@ describe('Test video abuses', function () { | |||
186 | await reportVideoAbuse(servers[1].url, servers[1].accessToken, servers[0].video.uuid, 'will mute this') | 186 | await reportVideoAbuse(servers[1].url, servers[1].accessToken, servers[0].video.uuid, 'will mute this') |
187 | await waitJobs(servers) | 187 | await waitJobs(servers) |
188 | 188 | ||
189 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 189 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
190 | expect(res.body.total).to.equal(3) | 190 | expect(res.body.total).to.equal(3) |
191 | } | 191 | } |
192 | 192 | ||
@@ -195,7 +195,7 @@ describe('Test video abuses', function () { | |||
195 | { | 195 | { |
196 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) | 196 | await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) |
197 | 197 | ||
198 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 198 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
199 | expect(res.body.total).to.equal(2) | 199 | expect(res.body.total).to.equal(2) |
200 | 200 | ||
201 | const abuse = res.body.data.find(a => a.reason === 'will mute this') | 201 | const abuse = res.body.data.find(a => a.reason === 'will mute this') |
@@ -205,7 +205,7 @@ describe('Test video abuses', function () { | |||
205 | { | 205 | { |
206 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) | 206 | await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock) |
207 | 207 | ||
208 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 208 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
209 | expect(res.body.total).to.equal(3) | 209 | expect(res.body.total).to.equal(3) |
210 | } | 210 | } |
211 | }) | 211 | }) |
@@ -216,7 +216,7 @@ describe('Test video abuses', function () { | |||
216 | { | 216 | { |
217 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host) | 217 | await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host) |
218 | 218 | ||
219 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 219 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
220 | expect(res.body.total).to.equal(2) | 220 | expect(res.body.total).to.equal(2) |
221 | 221 | ||
222 | const abuse = res.body.data.find(a => a.reason === 'will mute this') | 222 | const abuse = res.body.data.find(a => a.reason === 'will mute this') |
@@ -226,7 +226,7 @@ describe('Test video abuses', function () { | |||
226 | { | 226 | { |
227 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock) | 227 | await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock) |
228 | 228 | ||
229 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 229 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
230 | expect(res.body.total).to.equal(3) | 230 | expect(res.body.total).to.equal(3) |
231 | } | 231 | } |
232 | }) | 232 | }) |
@@ -238,7 +238,7 @@ describe('Test video abuses', function () { | |||
238 | 238 | ||
239 | await waitJobs(servers) | 239 | await waitJobs(servers) |
240 | 240 | ||
241 | const res = await getVideoAbusesList(servers[1].url, servers[1].accessToken) | 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") | 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") | 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") | 244 | expect(res.body.data[0].id).to.equal(abuseServer2.id, "wrong origin server id for first video") |
@@ -274,7 +274,7 @@ describe('Test video abuses', function () { | |||
274 | const reason4 = 'my super bad reason 4' | 274 | const reason4 = 'my super bad reason 4' |
275 | await reportVideoAbuse(servers[0].url, userAccessToken, servers[0].video.id, reason4) | 275 | await reportVideoAbuse(servers[0].url, userAccessToken, servers[0].video.id, reason4) |
276 | 276 | ||
277 | const res2 = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 277 | const res2 = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
278 | 278 | ||
279 | { | 279 | { |
280 | for (const abuse of res2.body.data as VideoAbuse[]) { | 280 | for (const abuse of res2.body.data as VideoAbuse[]) { |
@@ -299,18 +299,56 @@ describe('Test video abuses', function () { | |||
299 | await waitJobs(servers) | 299 | await waitJobs(servers) |
300 | 300 | ||
301 | { | 301 | { |
302 | const res = await getVideoAbusesList(servers[1].url, servers[1].accessToken) | 302 | const res = await getVideoAbusesList({ url: servers[1].url, token: servers[1].accessToken }) |
303 | expect(res.body.total).to.equal(1) | 303 | expect(res.body.total).to.equal(1) |
304 | expect(res.body.data.length).to.equal(1) | 304 | expect(res.body.data.length).to.equal(1) |
305 | expect(res.body.data[0].id).to.not.equal(abuseServer2.id) | 305 | expect(res.body.data[0].id).to.not.equal(abuseServer2.id) |
306 | } | 306 | } |
307 | 307 | ||
308 | { | 308 | { |
309 | const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken) | 309 | const res = await getVideoAbusesList({ url: servers[0].url, token: servers[0].accessToken }) |
310 | expect(res.body.total).to.equal(5) | 310 | expect(res.body.total).to.equal(5) |
311 | } | 311 | } |
312 | }) | 312 | }) |
313 | 313 | ||
314 | it('Should list and filter video abuses', async function () { | ||
315 | async function list (query: Omit<Parameters<typeof getVideoAbusesList>[0], 'url' | 'token'>) { | ||
316 | const options = { | ||
317 | url: servers[0].url, | ||
318 | token: servers[0].accessToken | ||
319 | } | ||
320 | |||
321 | Object.assign(options, query) | ||
322 | |||
323 | const res = await getVideoAbusesList(options) | ||
324 | |||
325 | return res.body.data as VideoAbuse[] | ||
326 | } | ||
327 | |||
328 | expect(await list({ id: 56 })).to.have.lengthOf(0) | ||
329 | expect(await list({ id: 1 })).to.have.lengthOf(1) | ||
330 | |||
331 | expect(await list({ search: 'my super name for server 1' })).to.have.lengthOf(3) | ||
332 | expect(await list({ search: 'aaaaaaaaaaaaaaaaaaaaaaaaaa' })).to.have.lengthOf(0) | ||
333 | |||
334 | expect(await list({ searchVideo: 'my second super name for server 1' })).to.have.lengthOf(1) | ||
335 | |||
336 | expect(await list({ searchVideoChannel: 'root' })).to.have.lengthOf(3) | ||
337 | expect(await list({ searchVideoChannel: 'aaaa' })).to.have.lengthOf(0) | ||
338 | |||
339 | expect(await list({ searchReporter: 'user2' })).to.have.lengthOf(1) | ||
340 | expect(await list({ searchReporter: 'root' })).to.have.lengthOf(4) | ||
341 | |||
342 | expect(await list({ searchReportee: 'root' })).to.have.lengthOf(3) | ||
343 | expect(await list({ searchReportee: 'aaaa' })).to.have.lengthOf(0) | ||
344 | |||
345 | expect(await list({ videoIs: 'deleted' })).to.have.lengthOf(1) | ||
346 | expect(await list({ videoIs: 'blacklisted' })).to.have.lengthOf(0) | ||
347 | |||
348 | expect(await list({ state: VideoAbuseState.ACCEPTED })).to.have.lengthOf(0) | ||
349 | expect(await list({ state: VideoAbuseState.PENDING })).to.have.lengthOf(5) | ||
350 | }) | ||
351 | |||
314 | after(async function () { | 352 | after(async function () { |
315 | await cleanupTests(servers) | 353 | await cleanupTests(servers) |
316 | }) | 354 | }) |
diff --git a/shared/extra-utils/videos/video-abuses.ts b/shared/extra-utils/videos/video-abuses.ts index 7f011ec0f..81582bfc7 100644 --- a/shared/extra-utils/videos/video-abuses.ts +++ b/shared/extra-utils/videos/video-abuses.ts | |||
@@ -1,6 +1,8 @@ | |||
1 | import * as request from 'supertest' | 1 | import * as request from 'supertest' |
2 | import { VideoAbuseUpdate } from '../../models/videos/abuse/video-abuse-update.model' | 2 | import { VideoAbuseUpdate } from '../../models/videos/abuse/video-abuse-update.model' |
3 | import { makeDeleteRequest, makePutBodyRequest } from '../requests/requests' | 3 | import { makeDeleteRequest, makePutBodyRequest, makeGetRequest } from '../requests/requests' |
4 | import { VideoAbuseState } from '@shared/models' | ||
5 | import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type' | ||
4 | 6 | ||
5 | function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 200) { | 7 | function reportVideoAbuse (url: string, token: string, videoId: number | string, reason: string, specialStatus = 200) { |
6 | const path = '/api/v1/videos/' + videoId + '/abuse' | 8 | const path = '/api/v1/videos/' + videoId + '/abuse' |
@@ -13,16 +15,51 @@ function reportVideoAbuse (url: string, token: string, videoId: number | string, | |||
13 | .expect(specialStatus) | 15 | .expect(specialStatus) |
14 | } | 16 | } |
15 | 17 | ||
16 | function getVideoAbusesList (url: string, token: string) { | 18 | function getVideoAbusesList (options: { |
19 | url: string | ||
20 | token: string | ||
21 | id?: number | ||
22 | search?: string | ||
23 | state?: VideoAbuseState | ||
24 | videoIs?: VideoAbuseVideoIs | ||
25 | searchReporter?: string | ||
26 | searchReportee?: string | ||
27 | searchVideo?: string | ||
28 | searchVideoChannel?: string | ||
29 | }) { | ||
30 | const { | ||
31 | url, | ||
32 | token, | ||
33 | id, | ||
34 | search, | ||
35 | state, | ||
36 | videoIs, | ||
37 | searchReporter, | ||
38 | searchReportee, | ||
39 | searchVideo, | ||
40 | searchVideoChannel | ||
41 | } = options | ||
17 | const path = '/api/v1/videos/abuse' | 42 | const path = '/api/v1/videos/abuse' |
18 | 43 | ||
19 | return request(url) | 44 | const query = { |
20 | .get(path) | 45 | sort: 'createdAt', |
21 | .query({ sort: 'createdAt' }) | 46 | id, |
22 | .set('Accept', 'application/json') | 47 | search, |
23 | .set('Authorization', 'Bearer ' + token) | 48 | state, |
24 | .expect(200) | 49 | videoIs, |
25 | .expect('Content-Type', /json/) | 50 | searchReporter, |
51 | searchReportee, | ||
52 | searchVideo, | ||
53 | searchVideoChannel | ||
54 | } | ||
55 | |||
56 | return makeGetRequest({ | ||
57 | url, | ||
58 | path, | ||
59 | token, | ||
60 | query, | ||
61 | statusCodeExpected: 200 | ||
62 | }) | ||
26 | } | 63 | } |
27 | 64 | ||
28 | function updateVideoAbuse ( | 65 | function updateVideoAbuse ( |
diff --git a/shared/models/videos/abuse/video-abuse-video-is.type.ts b/shared/models/videos/abuse/video-abuse-video-is.type.ts new file mode 100644 index 000000000..e86018993 --- /dev/null +++ b/shared/models/videos/abuse/video-abuse-video-is.type.ts | |||
@@ -0,0 +1 @@ | |||
export type VideoAbuseVideoIs = 'deleted' | 'blacklisted' | |||