diff options
author | Green-Star <Green-Star@users.noreply.github.com> | 2017-09-22 09:13:43 +0200 |
---|---|---|
committer | Bigard Florian <florian.bigard@gmail.com> | 2017-09-22 09:13:43 +0200 |
commit | 792dbaf07f83fbe3f1d209cd9edf190442c7d2f3 (patch) | |
tree | f7edf9caf17baaaf95c219c3ac73d598e3fd3df8 | |
parent | c9d6d155c397d0da0cb2d50064264fc1716f0501 (diff) | |
download | PeerTube-792dbaf07f83fbe3f1d209cd9edf190442c7d2f3.tar.gz PeerTube-792dbaf07f83fbe3f1d209cd9edf190442c7d2f3.tar.zst PeerTube-792dbaf07f83fbe3f1d209cd9edf190442c7d2f3.zip |
Handle blacklist (#84)
* Client: Add list blacklist feature
* Server: Add list blacklist feature
* Client: Add videoId column
* Server: Add some video infos in the REST api
* Client: Add video information in the blacklist list
* Fix sortable columns :)
* Client: Add removeFromBlacklist feature
* Server: Add removeFromBlacklist feature
* Move to TypeScript
* Move to TypeScript and Promises
* Server: Fix blacklist list sort
* Server: Fetch videos informations
* Use common shared interface for client and server
* Add check-params remove blacklisted video tests
* Add check-params list blacklisted videos tests
* Add list blacklist tests
* Add remove from blacklist tests
* Add video blacklist management tests
* Fix rebase onto develop issues
* Server: Add sort on blacklist id column
* Server: Add blacklists library
* Add blacklist id sort test
* Add check-params tests for blacklist list pagination, count and sort
* Fix coding style
* Increase Remote API tests timeout
* Increase Request scheduler API tests timeout
* Fix typo
* Increase video transcoding API tests timeout
* Move tests to Typescript
* Use lodash orderBy method
* Fix typos
* Client: Remove optional tests in blacklist model attributes
* Move blacklist routes from 'blacklists' to 'blacklist'
* CLient: Remove blacklist-list.component.scss
* Rename 'blacklists' files to 'blacklist'
* Use only BlacklistedVideo interface
* Server: Use getFormattedObjects method in listBlacklist method
* Client: Use new coding style
* Server: Use new sort validator methods
* Server: Use new checkParams methods
* Client: Fix sortable columns
36 files changed, 805 insertions, 124 deletions
diff --git a/client/src/app/+admin/admin-routing.module.ts b/client/src/app/+admin/admin-routing.module.ts index a3845b72c..0cd3e54c2 100644 --- a/client/src/app/+admin/admin-routing.module.ts +++ b/client/src/app/+admin/admin-routing.module.ts | |||
@@ -9,6 +9,7 @@ import { RequestSchedulersRoutes } from './request-schedulers' | |||
9 | import { UsersRoutes } from './users' | 9 | import { UsersRoutes } from './users' |
10 | import { VideoAbusesRoutes } from './video-abuses' | 10 | import { VideoAbusesRoutes } from './video-abuses' |
11 | import { AdminGuard } from './admin-guard.service' | 11 | import { AdminGuard } from './admin-guard.service' |
12 | import { BlacklistRoutes } from './blacklist' | ||
12 | 13 | ||
13 | const adminRoutes: Routes = [ | 14 | const adminRoutes: Routes = [ |
14 | { | 15 | { |
@@ -25,7 +26,8 @@ const adminRoutes: Routes = [ | |||
25 | ...FriendsRoutes, | 26 | ...FriendsRoutes, |
26 | ...RequestSchedulersRoutes, | 27 | ...RequestSchedulersRoutes, |
27 | ...UsersRoutes, | 28 | ...UsersRoutes, |
28 | ...VideoAbusesRoutes | 29 | ...VideoAbusesRoutes, |
30 | ...BlacklistRoutes | ||
29 | ] | 31 | ] |
30 | } | 32 | } |
31 | ] | 33 | ] |
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index 786dbc15c..c2dd60774 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -6,6 +6,7 @@ import { FriendsComponent, FriendAddComponent, FriendListComponent, FriendServic | |||
6 | import { RequestSchedulersComponent, RequestSchedulersStatsComponent, RequestSchedulersService } from './request-schedulers' | 6 | import { RequestSchedulersComponent, RequestSchedulersStatsComponent, RequestSchedulersService } from './request-schedulers' |
7 | import { UsersComponent, UserAddComponent, UserUpdateComponent, UserListComponent, UserService } from './users' | 7 | import { UsersComponent, UserAddComponent, UserUpdateComponent, UserListComponent, UserService } from './users' |
8 | import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses' | 8 | import { VideoAbusesComponent, VideoAbuseListComponent } from './video-abuses' |
9 | import { BlacklistComponent, BlacklistListComponent, BlacklistService } from './blacklist' | ||
9 | import { SharedModule } from '../shared' | 10 | import { SharedModule } from '../shared' |
10 | import { AdminGuard } from './admin-guard.service' | 11 | import { AdminGuard } from './admin-guard.service' |
11 | 12 | ||
@@ -30,6 +31,9 @@ import { AdminGuard } from './admin-guard.service' | |||
30 | UserUpdateComponent, | 31 | UserUpdateComponent, |
31 | UserListComponent, | 32 | UserListComponent, |
32 | 33 | ||
34 | BlacklistComponent, | ||
35 | BlacklistListComponent, | ||
36 | |||
33 | VideoAbusesComponent, | 37 | VideoAbusesComponent, |
34 | VideoAbuseListComponent | 38 | VideoAbuseListComponent |
35 | ], | 39 | ], |
@@ -42,7 +46,8 @@ import { AdminGuard } from './admin-guard.service' | |||
42 | FriendService, | 46 | FriendService, |
43 | RequestSchedulersService, | 47 | RequestSchedulersService, |
44 | UserService, | 48 | UserService, |
45 | AdminGuard | 49 | AdminGuard, |
50 | BlacklistService | ||
46 | ] | 51 | ] |
47 | }) | 52 | }) |
48 | export class AdminModule { } | 53 | export class AdminModule { } |
diff --git a/client/src/app/+admin/blacklist/blacklist-list/blacklist-list.component.html b/client/src/app/+admin/blacklist/blacklist-list/blacklist-list.component.html new file mode 100644 index 000000000..5d4636ee9 --- /dev/null +++ b/client/src/app/+admin/blacklist/blacklist-list/blacklist-list.component.html | |||
@@ -0,0 +1,26 @@ | |||
1 | <div class="row"> | ||
2 | <div class="content-padding"> | ||
3 | <h3>Blacklisted videos</h3> | ||
4 | |||
5 | <p-dataTable | ||
6 | [value]="blacklist" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
7 | sortField="id" (onLazyLoad)="loadLazy($event)" | ||
8 | > | ||
9 | <p-column field="id" header="ID" [sortable]="true"></p-column> | ||
10 | <p-column field="name" header="Name" [sortable]="true"></p-column> | ||
11 | <p-column field="description" header="Description"></p-column> | ||
12 | <p-column field="duration" header="Duration" [sortable]="true"></p-column> | ||
13 | <p-column field="views" header="Views" [sortable]="true"></p-column> | ||
14 | <p-column field="likes" header="Likes" [sortable]="true"></p-column> | ||
15 | <p-column field="dislikes" header="Dislikes" [sortable]="true"></p-column> | ||
16 | <p-column field="nsfw" header="NSFW"></p-column> | ||
17 | <p-column field="uuid" header="UUID" [sortable]="true"></p-column> | ||
18 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> | ||
19 | <p-column header="Delete" styleClass="action-cell"> | ||
20 | <ng-template pTemplate="body" let-entry="rowData"> | ||
21 | <span (click)="removeVideoFromBlacklist(entry)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this video"></span> | ||
22 | </ng-template> | ||
23 | </p-column> | ||
24 | </p-dataTable> | ||
25 | </div> | ||
26 | </div> | ||
diff --git a/client/src/app/+admin/blacklist/blacklist-list/blacklist-list.component.ts b/client/src/app/+admin/blacklist/blacklist-list/blacklist-list.component.ts new file mode 100644 index 000000000..b308054ed --- /dev/null +++ b/client/src/app/+admin/blacklist/blacklist-list/blacklist-list.component.ts | |||
@@ -0,0 +1,65 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { SortMeta } from 'primeng/components/common/sortmeta' | ||
3 | |||
4 | import { NotificationsService } from 'angular2-notifications' | ||
5 | |||
6 | import { ConfirmService } from '../../../core' | ||
7 | import { RestTable, RestPagination } from '../../../shared' | ||
8 | import { BlacklistService } from '../shared' | ||
9 | import { BlacklistedVideo } from '../../../../../../shared' | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-blacklist-list', | ||
13 | templateUrl: './blacklist-list.component.html', | ||
14 | styleUrls: [] | ||
15 | }) | ||
16 | export class BlacklistListComponent extends RestTable implements OnInit { | ||
17 | blacklist: BlacklistedVideo[] = [] | ||
18 | totalRecords = 0 | ||
19 | rowsPerPage = 10 | ||
20 | sort: SortMeta = { field: 'id', order: 1 } | ||
21 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
22 | |||
23 | constructor ( | ||
24 | private notificationsService: NotificationsService, | ||
25 | private confirmService: ConfirmService, | ||
26 | private blacklistService: BlacklistService | ||
27 | ) { | ||
28 | super() | ||
29 | } | ||
30 | |||
31 | ngOnInit () { | ||
32 | this.loadData() | ||
33 | } | ||
34 | |||
35 | removeVideoFromBlacklist (entry: BlacklistedVideo) { | ||
36 | const confirmMessage = 'Do you really want to remove this video from the blacklist ? It will be available again in the video list.' | ||
37 | |||
38 | this.confirmService.confirm(confirmMessage, 'Remove').subscribe( | ||
39 | res => { | ||
40 | if (res === false) return | ||
41 | |||
42 | this.blacklistService.removeVideoFromBlacklist(entry).subscribe( | ||
43 | status => { | ||
44 | this.notificationsService.success('Success', `Video ${entry.name} removed from the blacklist.`) | ||
45 | this.loadData() | ||
46 | }, | ||
47 | |||
48 | err => this.notificationsService.error('Error', err.message) | ||
49 | ) | ||
50 | } | ||
51 | ) | ||
52 | } | ||
53 | |||
54 | protected loadData () { | ||
55 | this.blacklistService.getBlacklist(this.pagination, this.sort) | ||
56 | .subscribe( | ||
57 | resultList => { | ||
58 | this.blacklist = resultList.data | ||
59 | this.totalRecords = resultList.total | ||
60 | }, | ||
61 | |||
62 | err => this.notificationsService.error('Error', err.message) | ||
63 | ) | ||
64 | } | ||
65 | } | ||
diff --git a/client/src/app/+admin/blacklist/blacklist-list/index.ts b/client/src/app/+admin/blacklist/blacklist-list/index.ts new file mode 100644 index 000000000..45f60a2b9 --- /dev/null +++ b/client/src/app/+admin/blacklist/blacklist-list/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './blacklist-list.component' | |||
diff --git a/client/src/app/+admin/blacklist/blacklist.component.ts b/client/src/app/+admin/blacklist/blacklist.component.ts new file mode 100644 index 000000000..ce8fe4298 --- /dev/null +++ b/client/src/app/+admin/blacklist/blacklist.component.ts | |||
@@ -0,0 +1,8 @@ | |||
1 | import { Component } from '@angular/core' | ||
2 | |||
3 | @Component({ | ||
4 | template: '<router-outlet></router-outlet>' | ||
5 | }) | ||
6 | |||
7 | export class BlacklistComponent { | ||
8 | } | ||
diff --git a/client/src/app/+admin/blacklist/blacklist.routes.ts b/client/src/app/+admin/blacklist/blacklist.routes.ts new file mode 100644 index 000000000..780347ca8 --- /dev/null +++ b/client/src/app/+admin/blacklist/blacklist.routes.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import { Routes } from '@angular/router' | ||
2 | |||
3 | import { BlacklistComponent } from './blacklist.component' | ||
4 | import { BlacklistListComponent } from './blacklist-list' | ||
5 | |||
6 | export const BlacklistRoutes: Routes = [ | ||
7 | { | ||
8 | path: 'blacklist', | ||
9 | component: BlacklistComponent, | ||
10 | children: [ | ||
11 | { | ||
12 | path: '', | ||
13 | redirectTo: 'list', | ||
14 | pathMatch: 'full' | ||
15 | }, | ||
16 | { | ||
17 | path: 'list', | ||
18 | component: BlacklistListComponent, | ||
19 | data: { | ||
20 | meta: { | ||
21 | title: 'Blacklisted videos' | ||
22 | } | ||
23 | } | ||
24 | } | ||
25 | ] | ||
26 | } | ||
27 | ] | ||
diff --git a/client/src/app/+admin/blacklist/index.ts b/client/src/app/+admin/blacklist/index.ts new file mode 100644 index 000000000..675dc1263 --- /dev/null +++ b/client/src/app/+admin/blacklist/index.ts | |||
@@ -0,0 +1,4 @@ | |||
1 | export * from './shared' | ||
2 | export * from './blacklist-list' | ||
3 | export * from './blacklist.component' | ||
4 | export * from './blacklist.routes' | ||
diff --git a/client/src/app/+admin/blacklist/shared/blacklist.service.ts b/client/src/app/+admin/blacklist/shared/blacklist.service.ts new file mode 100644 index 000000000..1b090c9c5 --- /dev/null +++ b/client/src/app/+admin/blacklist/shared/blacklist.service.ts | |||
@@ -0,0 +1,44 @@ | |||
1 | import { Injectable } from '@angular/core' | ||
2 | import { HttpClient, HttpParams } from '@angular/common/http' | ||
3 | import { Observable } from 'rxjs/Observable' | ||
4 | import 'rxjs/add/operator/catch' | ||
5 | import 'rxjs/add/operator/map' | ||
6 | |||
7 | import { SortMeta } from 'primeng/components/common/sortmeta' | ||
8 | |||
9 | import { RestExtractor, RestPagination, RestService } from '../../../shared' | ||
10 | import { Utils } from '../../../shared' | ||
11 | import { BlacklistedVideo, ResultList } from '../../../../../../shared' | ||
12 | |||
13 | @Injectable() | ||
14 | export class BlacklistService { | ||
15 | private static BASE_BLACKLISTS_URL = '/api/v1/blacklist/' | ||
16 | |||
17 | constructor ( | ||
18 | private authHttp: HttpClient, | ||
19 | private restService: RestService, | ||
20 | private restExtractor: RestExtractor | ||
21 | ) {} | ||
22 | |||
23 | getBlacklist (pagination: RestPagination, sort: SortMeta): Observable<ResultList<BlacklistedVideo>> { | ||
24 | let params = new HttpParams() | ||
25 | params = this.restService.addRestGetParams(params, pagination, sort) | ||
26 | |||
27 | return this.authHttp.get<ResultList<BlacklistedVideo>>(BlacklistService.BASE_BLACKLISTS_URL, { params }) | ||
28 | .map(res => this.restExtractor.convertResultListDateToHuman(res)) | ||
29 | .map(res => this.restExtractor.applyToResultListData(res, this.formatBlacklistedVideo.bind(this))) | ||
30 | .catch(res => this.restExtractor.handleError(res)) | ||
31 | } | ||
32 | |||
33 | removeVideoFromBlacklist (entry: BlacklistedVideo) { | ||
34 | return this.authHttp.delete(BlacklistService.BASE_BLACKLISTS_URL + entry.id) | ||
35 | .map(this.restExtractor.extractDataBool) | ||
36 | .catch(res => this.restExtractor.handleError(res)) | ||
37 | } | ||
38 | |||
39 | private formatBlacklistedVideo (blacklistedVideo: BlacklistedVideo) { | ||
40 | return Object.assign(blacklistedVideo, { | ||
41 | createdAt: Utils.dateToHuman(blacklistedVideo.createdAt) | ||
42 | }) | ||
43 | } | ||
44 | } | ||
diff --git a/client/src/app/+admin/blacklist/shared/index.ts b/client/src/app/+admin/blacklist/shared/index.ts new file mode 100644 index 000000000..ad22e2d51 --- /dev/null +++ b/client/src/app/+admin/blacklist/shared/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './blacklist.service' | |||
diff --git a/client/src/app/core/menu/menu-admin.component.html b/client/src/app/core/menu/menu-admin.component.html index 0dfe22d84..f512a4e67 100644 --- a/client/src/app/core/menu/menu-admin.component.html +++ b/client/src/app/core/menu/menu-admin.component.html | |||
@@ -19,6 +19,11 @@ | |||
19 | <span class="hidden-xs glyphicon glyphicon-alert"></span> | 19 | <span class="hidden-xs glyphicon glyphicon-alert"></span> |
20 | Video abuses | 20 | Video abuses |
21 | </a> | 21 | </a> |
22 | |||
23 | <a routerLink="/admin/blacklist/list" routerLinkActive="active"> | ||
24 | <span class="hidden-xs glyphicon glyphicon-eye-close"></span> | ||
25 | Video blacklist | ||
26 | </a> | ||
22 | </div> | 27 | </div> |
23 | 28 | ||
24 | <div class="panel-block"> | 29 | <div class="panel-block"> |
diff --git a/server/controllers/api/blacklist.ts b/server/controllers/api/blacklist.ts new file mode 100644 index 000000000..9b2d8017e --- /dev/null +++ b/server/controllers/api/blacklist.ts | |||
@@ -0,0 +1,60 @@ | |||
1 | import * as express from 'express' | ||
2 | |||
3 | import { database } from '../../initializers' | ||
4 | import { getFormattedObjects } from '../../helpers' | ||
5 | import { BlacklistedVideo } from '../../../shared' | ||
6 | import { BlacklistedVideoInstance } from '../../models' | ||
7 | |||
8 | import { | ||
9 | removeVideoFromBlacklist | ||
10 | } from '../../lib' | ||
11 | import { | ||
12 | authenticate, | ||
13 | ensureIsAdmin, | ||
14 | paginationValidator, | ||
15 | blacklistSortValidator, | ||
16 | setBlacklistSort, | ||
17 | setPagination, | ||
18 | blacklistRemoveValidator | ||
19 | } from '../../middlewares' | ||
20 | |||
21 | const blacklistRouter = express.Router() | ||
22 | |||
23 | blacklistRouter.get('/', | ||
24 | authenticate, | ||
25 | ensureIsAdmin, | ||
26 | paginationValidator, | ||
27 | blacklistSortValidator, | ||
28 | setBlacklistSort, | ||
29 | setPagination, | ||
30 | listBlacklist | ||
31 | ) | ||
32 | |||
33 | blacklistRouter.delete('/:id', | ||
34 | authenticate, | ||
35 | ensureIsAdmin, | ||
36 | blacklistRemoveValidator, | ||
37 | removeVideoFromBlacklistController | ||
38 | ) | ||
39 | |||
40 | // --------------------------------------------------------------------------- | ||
41 | |||
42 | export { | ||
43 | blacklistRouter | ||
44 | } | ||
45 | |||
46 | // --------------------------------------------------------------------------- | ||
47 | |||
48 | function listBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
49 | database.BlacklistedVideo.listForApi(req.query.start, req.query.count, req.query.sort) | ||
50 | .then(resultList => res.json(getFormattedObjects<BlacklistedVideo, BlacklistedVideoInstance>(resultList.data, resultList.total))) | ||
51 | .catch(err => next(err)) | ||
52 | } | ||
53 | |||
54 | function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
55 | const entry = res.locals.blacklistEntryToRemove as BlacklistedVideoInstance | ||
56 | |||
57 | removeVideoFromBlacklist(entry) | ||
58 | .then(() => res.sendStatus(204)) | ||
59 | .catch(err => next(err)) | ||
60 | } | ||
diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts index a9205b33c..fdc887915 100644 --- a/server/controllers/api/index.ts +++ b/server/controllers/api/index.ts | |||
@@ -9,6 +9,7 @@ import { remoteRouter } from './remote' | |||
9 | import { requestSchedulerRouter } from './request-schedulers' | 9 | import { requestSchedulerRouter } from './request-schedulers' |
10 | import { usersRouter } from './users' | 10 | import { usersRouter } from './users' |
11 | import { videosRouter } from './videos' | 11 | import { videosRouter } from './videos' |
12 | import { blacklistRouter } from './blacklist' | ||
12 | 13 | ||
13 | const apiRouter = express.Router() | 14 | const apiRouter = express.Router() |
14 | 15 | ||
@@ -19,6 +20,7 @@ apiRouter.use('/remote', remoteRouter) | |||
19 | apiRouter.use('/request-schedulers', requestSchedulerRouter) | 20 | apiRouter.use('/request-schedulers', requestSchedulerRouter) |
20 | apiRouter.use('/users', usersRouter) | 21 | apiRouter.use('/users', usersRouter) |
21 | apiRouter.use('/videos', videosRouter) | 22 | apiRouter.use('/videos', videosRouter) |
23 | apiRouter.use('/blacklist', blacklistRouter) | ||
22 | apiRouter.use('/ping', pong) | 24 | apiRouter.use('/ping', pong) |
23 | apiRouter.use('/*', badRequest) | 25 | apiRouter.use('/*', badRequest) |
24 | 26 | ||
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index af5be0c69..ce07ceff9 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts | |||
@@ -47,11 +47,14 @@ function isSignupAllowed () { | |||
47 | }) | 47 | }) |
48 | } | 48 | } |
49 | 49 | ||
50 | type SortType = { sortModel: any, sortValue: string } | ||
51 | |||
50 | // --------------------------------------------------------------------------- | 52 | // --------------------------------------------------------------------------- |
51 | 53 | ||
52 | export { | 54 | export { |
53 | badRequest, | 55 | badRequest, |
54 | generateRandomString, | 56 | generateRandomString, |
55 | getFormattedObjects, | 57 | getFormattedObjects, |
56 | isSignupAllowed | 58 | isSignupAllowed, |
59 | SortType | ||
57 | } | 60 | } |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index e01b6a4d4..54e91d35d 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -34,7 +34,8 @@ const SEARCHABLE_COLUMNS = { | |||
34 | const SORTABLE_COLUMNS = { | 34 | const SORTABLE_COLUMNS = { |
35 | USERS: [ 'id', 'username', 'createdAt' ], | 35 | USERS: [ 'id', 'username', 'createdAt' ], |
36 | VIDEO_ABUSES: [ 'id', 'createdAt' ], | 36 | VIDEO_ABUSES: [ 'id', 'createdAt' ], |
37 | VIDEOS: [ 'name', 'duration', 'createdAt', 'views', 'likes' ] | 37 | VIDEOS: [ 'name', 'duration', 'createdAt', 'views', 'likes' ], |
38 | BLACKLISTS: [ 'id', 'name', 'duration', 'views', 'likes', 'dislikes', 'uuid', 'createdAt' ] | ||
38 | } | 39 | } |
39 | 40 | ||
40 | const OAUTH_LIFETIME = { | 41 | const OAUTH_LIFETIME = { |
diff --git a/server/lib/blacklist.ts b/server/lib/blacklist.ts new file mode 100644 index 000000000..dcf8aa03c --- /dev/null +++ b/server/lib/blacklist.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | import { logger } from '../helpers' | ||
2 | import { BlacklistedVideoInstance } from '../models' | ||
3 | |||
4 | function removeVideoFromBlacklist (entry: BlacklistedVideoInstance) { | ||
5 | return entry.destroy() | ||
6 | .then(() => { | ||
7 | logger.info('Video removed from the blacklist') | ||
8 | }) | ||
9 | .catch(err => { | ||
10 | logger.error('Some error while removing video from the blacklist.', err) | ||
11 | }) | ||
12 | } | ||
13 | |||
14 | // --------------------------------------------------------------------------- | ||
15 | |||
16 | export { | ||
17 | removeVideoFromBlacklist | ||
18 | } | ||
19 | |||
20 | // --------------------------------------------------------------------------- | ||
diff --git a/server/lib/index.ts b/server/lib/index.ts index 8628da4dd..df781f29f 100644 --- a/server/lib/index.ts +++ b/server/lib/index.ts | |||
@@ -3,3 +3,4 @@ export * from './jobs' | |||
3 | export * from './request' | 3 | export * from './request' |
4 | export * from './friends' | 4 | export * from './friends' |
5 | export * from './oauth-model' | 5 | export * from './oauth-model' |
6 | export * from './blacklist' | ||
diff --git a/server/middlewares/sort.ts b/server/middlewares/sort.ts index 632b2fae4..687ce097b 100644 --- a/server/middlewares/sort.ts +++ b/server/middlewares/sort.ts | |||
@@ -1,6 +1,9 @@ | |||
1 | import 'express-validator' | 1 | import 'express-validator' |
2 | import * as express from 'express' | 2 | import * as express from 'express' |
3 | 3 | ||
4 | import { SortType } from '../helpers' | ||
5 | import { database } from '../initializers' | ||
6 | |||
4 | function setUsersSort (req: express.Request, res: express.Response, next: express.NextFunction) { | 7 | function setUsersSort (req: express.Request, res: express.Response, next: express.NextFunction) { |
5 | if (!req.query.sort) req.query.sort = '-createdAt' | 8 | if (!req.query.sort) req.query.sort = '-createdAt' |
6 | 9 | ||
@@ -19,10 +22,32 @@ function setVideosSort (req: express.Request, res: express.Response, next: expre | |||
19 | return next() | 22 | return next() |
20 | } | 23 | } |
21 | 24 | ||
25 | function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
26 | let newSort: SortType = { sortModel: undefined, sortValue: undefined } | ||
27 | |||
28 | if (!req.query.sort) req.query.sort = '-createdAt' | ||
29 | |||
30 | // Set model we want to sort onto | ||
31 | if (req.query.sort === '-createdAt' || req.query.sort === 'createdAt' || | ||
32 | req.query.sort === '-id' || req.query.sort === 'id') { | ||
33 | // If we want to sort onto the BlacklistedVideos relation, we won't specify it in the query parameter ... | ||
34 | newSort.sortModel = undefined | ||
35 | } else { | ||
36 | newSort.sortModel = database.Video | ||
37 | } | ||
38 | |||
39 | newSort.sortValue = req.query.sort | ||
40 | |||
41 | req.query.sort = newSort | ||
42 | |||
43 | return next() | ||
44 | } | ||
45 | |||
22 | // --------------------------------------------------------------------------- | 46 | // --------------------------------------------------------------------------- |
23 | 47 | ||
24 | export { | 48 | export { |
25 | setUsersSort, | 49 | setUsersSort, |
26 | setVideoAbusesSort, | 50 | setVideoAbusesSort, |
27 | setVideosSort | 51 | setVideosSort, |
52 | setBlacklistSort | ||
28 | } | 53 | } |
diff --git a/server/middlewares/validators/blacklist.ts b/server/middlewares/validators/blacklist.ts new file mode 100644 index 000000000..fe8fa40a4 --- /dev/null +++ b/server/middlewares/validators/blacklist.ts | |||
@@ -0,0 +1,35 @@ | |||
1 | import { param } from 'express-validator/check' | ||
2 | import * as express from 'express' | ||
3 | |||
4 | import { database as db } from '../../initializers/database' | ||
5 | import { checkErrors } from './utils' | ||
6 | import { logger } from '../../helpers' | ||
7 | |||
8 | const blacklistRemoveValidator = [ | ||
9 | param('id').isNumeric().not().isEmpty().withMessage('Should have a valid id'), | ||
10 | |||
11 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
12 | logger.debug('Checking blacklistRemove parameters.', { parameters: req.params }) | ||
13 | |||
14 | checkErrors(req, res, () => { | ||
15 | db.BlacklistedVideo.loadById(req.params.id) | ||
16 | .then(entry => { | ||
17 | if (!entry) return res.status(404).send('Blacklisted video not found') | ||
18 | |||
19 | res.locals.blacklistEntryToRemove = entry | ||
20 | |||
21 | next() | ||
22 | }) | ||
23 | .catch(err => { | ||
24 | logger.error('Error in blacklistRemove request validator', { error: err }) | ||
25 | return res.sendStatus(500) | ||
26 | }) | ||
27 | }) | ||
28 | } | ||
29 | ] | ||
30 | |||
31 | // --------------------------------------------------------------------------- | ||
32 | |||
33 | export { | ||
34 | blacklistRemoveValidator | ||
35 | } | ||
diff --git a/server/middlewares/validators/index.ts b/server/middlewares/validators/index.ts index 42ba465ec..a6198e22c 100644 --- a/server/middlewares/validators/index.ts +++ b/server/middlewares/validators/index.ts | |||
@@ -4,3 +4,4 @@ export * from './pods' | |||
4 | export * from './sort' | 4 | export * from './sort' |
5 | export * from './users' | 5 | export * from './users' |
6 | export * from './videos' | 6 | export * from './videos' |
7 | export * from './blacklist' | ||
diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index 71b18acb0..a6f5ccb6b 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts | |||
@@ -9,17 +9,20 @@ import { SORTABLE_COLUMNS } from '../../initializers' | |||
9 | const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS) | 9 | const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS) |
10 | const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES) | 10 | const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES) |
11 | const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS) | 11 | const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS) |
12 | const SORTABLE_BLACKLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.BLACKLISTS) | ||
12 | 13 | ||
13 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) | 14 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) |
14 | const videoAbusesSortValidator = checkSort(SORTABLE_VIDEO_ABUSES_COLUMNS) | 15 | const videoAbusesSortValidator = checkSort(SORTABLE_VIDEO_ABUSES_COLUMNS) |
15 | const videosSortValidator = checkSort(SORTABLE_VIDEOS_COLUMNS) | 16 | const videosSortValidator = checkSort(SORTABLE_VIDEOS_COLUMNS) |
17 | const blacklistSortValidator = checkSort(SORTABLE_BLACKLISTS_COLUMNS) | ||
16 | 18 | ||
17 | // --------------------------------------------------------------------------- | 19 | // --------------------------------------------------------------------------- |
18 | 20 | ||
19 | export { | 21 | export { |
20 | usersSortValidator, | 22 | usersSortValidator, |
21 | videoAbusesSortValidator, | 23 | videoAbusesSortValidator, |
22 | videosSortValidator | 24 | videosSortValidator, |
25 | blacklistSortValidator | ||
23 | } | 26 | } |
24 | 27 | ||
25 | // --------------------------------------------------------------------------- | 28 | // --------------------------------------------------------------------------- |
diff --git a/server/models/utils.ts b/server/models/utils.ts index 7ba96815e..1bf61d2a6 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts | |||
@@ -19,9 +19,17 @@ function addMethodsToModel (model: any, classMethods: Function[], instanceMethod | |||
19 | instanceMethods.forEach(m => model.prototype[m.name] = m) | 19 | instanceMethods.forEach(m => model.prototype[m.name] = m) |
20 | } | 20 | } |
21 | 21 | ||
22 | function getSortOnModel (model: any, value: string) { | ||
23 | let sort = getSort(value) | ||
24 | |||
25 | if (model) return [ { model: model }, sort[0], sort[1] ] | ||
26 | return sort | ||
27 | } | ||
28 | |||
22 | // --------------------------------------------------------------------------- | 29 | // --------------------------------------------------------------------------- |
23 | 30 | ||
24 | export { | 31 | export { |
25 | addMethodsToModel, | 32 | addMethodsToModel, |
26 | getSort | 33 | getSort, |
34 | getSortOnModel | ||
27 | } | 35 | } |
diff --git a/server/models/video/video-blacklist-interface.ts b/server/models/video/video-blacklist-interface.ts index ba48b1b6e..9d167c037 100644 --- a/server/models/video/video-blacklist-interface.ts +++ b/server/models/video/video-blacklist-interface.ts | |||
@@ -1,7 +1,9 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import * as Promise from 'bluebird' | 2 | import * as Promise from 'bluebird' |
3 | 3 | ||
4 | import { SortType } from '../../helpers' | ||
4 | import { ResultList } from '../../../shared' | 5 | import { ResultList } from '../../../shared' |
6 | import { VideoInstance } from './video-interface' | ||
5 | 7 | ||
6 | // Don't use barrel, import just what we need | 8 | // Don't use barrel, import just what we need |
7 | import { BlacklistedVideo as FormattedBlacklistedVideo } from '../../../shared/models/videos/video-blacklist.model' | 9 | import { BlacklistedVideo as FormattedBlacklistedVideo } from '../../../shared/models/videos/video-blacklist.model' |
@@ -13,7 +15,7 @@ export namespace BlacklistedVideoMethods { | |||
13 | 15 | ||
14 | export type List = () => Promise<BlacklistedVideoInstance[]> | 16 | export type List = () => Promise<BlacklistedVideoInstance[]> |
15 | 17 | ||
16 | export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList<BlacklistedVideoInstance> > | 18 | export type ListForApi = (start: number, count: number, sort: SortType) => Promise< ResultList<BlacklistedVideoInstance> > |
17 | 19 | ||
18 | export type LoadById = (id: number) => Promise<BlacklistedVideoInstance> | 20 | export type LoadById = (id: number) => Promise<BlacklistedVideoInstance> |
19 | 21 | ||
@@ -31,6 +33,8 @@ export interface BlacklistedVideoClass { | |||
31 | 33 | ||
32 | export interface BlacklistedVideoAttributes { | 34 | export interface BlacklistedVideoAttributes { |
33 | videoId: number | 35 | videoId: number |
36 | |||
37 | Video?: VideoInstance | ||
34 | } | 38 | } |
35 | 39 | ||
36 | export interface BlacklistedVideoInstance | 40 | export interface BlacklistedVideoInstance |
diff --git a/server/models/video/video-blacklist.ts b/server/models/video/video-blacklist.ts index dc49852b6..1c279b1ba 100644 --- a/server/models/video/video-blacklist.ts +++ b/server/models/video/video-blacklist.ts | |||
@@ -1,6 +1,8 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | 2 | ||
3 | import { addMethodsToModel, getSort } from '../utils' | 3 | import { SortType } from '../../helpers' |
4 | import { addMethodsToModel, getSortOnModel } from '../utils' | ||
5 | import { VideoInstance } from './video-interface' | ||
4 | import { | 6 | import { |
5 | BlacklistedVideoInstance, | 7 | BlacklistedVideoInstance, |
6 | BlacklistedVideoAttributes, | 8 | BlacklistedVideoAttributes, |
@@ -49,10 +51,23 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
49 | // ------------------------------ METHODS ------------------------------ | 51 | // ------------------------------ METHODS ------------------------------ |
50 | 52 | ||
51 | toFormattedJSON = function (this: BlacklistedVideoInstance) { | 53 | toFormattedJSON = function (this: BlacklistedVideoInstance) { |
54 | let video: VideoInstance | ||
55 | |||
56 | video = this.Video | ||
57 | |||
52 | return { | 58 | return { |
53 | id: this.id, | 59 | id: this.id, |
54 | videoId: this.videoId, | 60 | videoId: this.videoId, |
55 | createdAt: this.createdAt | 61 | createdAt: this.createdAt, |
62 | updatedAt: this.updatedAt, | ||
63 | name: video.name, | ||
64 | uuid: video.uuid, | ||
65 | description: video.description, | ||
66 | duration: video.duration, | ||
67 | views: video.views, | ||
68 | likes: video.likes, | ||
69 | dislikes: video.dislikes, | ||
70 | nsfw: video.nsfw | ||
56 | } | 71 | } |
57 | } | 72 | } |
58 | 73 | ||
@@ -76,11 +91,12 @@ list = function () { | |||
76 | return BlacklistedVideo.findAll() | 91 | return BlacklistedVideo.findAll() |
77 | } | 92 | } |
78 | 93 | ||
79 | listForApi = function (start: number, count: number, sort: string) { | 94 | listForApi = function (start: number, count: number, sort: SortType) { |
80 | const query = { | 95 | const query = { |
81 | offset: start, | 96 | offset: start, |
82 | limit: count, | 97 | limit: count, |
83 | order: [ getSort(sort) ] | 98 | order: [ getSortOnModel(sort.sortModel, sort.sortValue) ], |
99 | include: [ { model: BlacklistedVideo['sequelize'].models.Video } ] | ||
84 | } | 100 | } |
85 | 101 | ||
86 | return BlacklistedVideo.findAndCountAll(query).then(({ rows, count }) => { | 102 | return BlacklistedVideo.findAndCountAll(query).then(({ rows, count }) => { |
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts index 97f2a19d7..399a05bc3 100644 --- a/server/tests/api/check-params/index.ts +++ b/server/tests/api/check-params/index.ts | |||
@@ -5,4 +5,4 @@ import './users' | |||
5 | import './request-schedulers' | 5 | import './request-schedulers' |
6 | import './videos' | 6 | import './videos' |
7 | import './video-abuses' | 7 | import './video-abuses' |
8 | import './video-blacklists' | 8 | import './video-blacklist' |
diff --git a/server/tests/api/check-params/remotes.ts b/server/tests/api/check-params/remotes.ts index b36f1c08b..9456ae665 100644 --- a/server/tests/api/check-params/remotes.ts +++ b/server/tests/api/check-params/remotes.ts | |||
@@ -14,7 +14,7 @@ describe('Test remote videos API validators', function () { | |||
14 | // --------------------------------------------------------------- | 14 | // --------------------------------------------------------------- |
15 | 15 | ||
16 | before(async function () { | 16 | before(async function () { |
17 | this.timeout(20000) | 17 | this.timeout(60000) |
18 | 18 | ||
19 | await flushTests() | 19 | await flushTests() |
20 | 20 | ||
diff --git a/server/tests/api/check-params/request-schedulers.ts b/server/tests/api/check-params/request-schedulers.ts index c39f5947b..01a54ffa1 100644 --- a/server/tests/api/check-params/request-schedulers.ts +++ b/server/tests/api/check-params/request-schedulers.ts | |||
@@ -20,7 +20,7 @@ describe('Test request schedulers stats API validators', function () { | |||
20 | // --------------------------------------------------------------- | 20 | // --------------------------------------------------------------- |
21 | 21 | ||
22 | before(async function () { | 22 | before(async function () { |
23 | this.timeout(20000) | 23 | this.timeout(60000) |
24 | 24 | ||
25 | await flushTests() | 25 | await flushTests() |
26 | 26 | ||
diff --git a/server/tests/api/check-params/video-blacklist.ts b/server/tests/api/check-params/video-blacklist.ts new file mode 100644 index 000000000..80e6f8011 --- /dev/null +++ b/server/tests/api/check-params/video-blacklist.ts | |||
@@ -0,0 +1,195 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | ||
2 | |||
3 | import 'mocha' | ||
4 | import * as request from 'supertest' | ||
5 | |||
6 | import { | ||
7 | ServerInfo, | ||
8 | flushTests, | ||
9 | runServer, | ||
10 | uploadVideo, | ||
11 | getVideosList, | ||
12 | createUser, | ||
13 | setAccessTokensToServers, | ||
14 | killallServers, | ||
15 | makePostBodyRequest, | ||
16 | getUserAccessToken | ||
17 | } from '../../utils' | ||
18 | |||
19 | describe('Test video blacklist API validators', function () { | ||
20 | let server: ServerInfo | ||
21 | let userAccessToken = '' | ||
22 | |||
23 | // --------------------------------------------------------------- | ||
24 | |||
25 | before(async function () { | ||
26 | this.timeout(120000) | ||
27 | |||
28 | await flushTests() | ||
29 | |||
30 | server = await runServer(1) | ||
31 | |||
32 | await setAccessTokensToServers([ server ]) | ||
33 | |||
34 | const username = 'user1' | ||
35 | const password = 'my super password' | ||
36 | await createUser(server.url, server.accessToken, username, password) | ||
37 | userAccessToken = await getUserAccessToken(server, { username, password }) | ||
38 | |||
39 | // Upload a video | ||
40 | const videoAttributes = {} | ||
41 | await uploadVideo(server.url, server.accessToken, videoAttributes) | ||
42 | |||
43 | const res = await getVideosList(server.url) | ||
44 | |||
45 | const videos = res.body.data | ||
46 | server.video = videos[0] | ||
47 | }) | ||
48 | |||
49 | describe('When adding a video in blacklist', function () { | ||
50 | const basePath = '/api/v1/videos/' | ||
51 | |||
52 | it('Should fail with nothing', async function () { | ||
53 | const path = basePath + server.video + '/blacklist' | ||
54 | const fields = {} | ||
55 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
56 | }) | ||
57 | |||
58 | it('Should fail with a wrong video', async function () { | ||
59 | const wrongPath = '/api/v1/videos/blabla/blacklist' | ||
60 | const fields = {} | ||
61 | await makePostBodyRequest({ url: server.url, path: wrongPath, token: server.accessToken, fields }) | ||
62 | }) | ||
63 | |||
64 | it('Should fail with a non authenticated user', async function () { | ||
65 | const fields = {} | ||
66 | const path = basePath + server.video + '/blacklist' | ||
67 | await makePostBodyRequest({ url: server.url, path, token: 'hello', fields, statusCodeExpected: 401 }) | ||
68 | }) | ||
69 | |||
70 | it('Should fail with a non admin user', async function () { | ||
71 | const fields = {} | ||
72 | const path = basePath + server.video + '/blacklist' | ||
73 | await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields, statusCodeExpected: 403 }) | ||
74 | }) | ||
75 | |||
76 | it('Should fail with a local video', async function () { | ||
77 | const fields = {} | ||
78 | const path = basePath + server.video.id + '/blacklist' | ||
79 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 403 }) | ||
80 | }) | ||
81 | }) | ||
82 | |||
83 | describe('When removing a video in blacklist', function () { | ||
84 | const basePath = '/api/v1/blacklist/' | ||
85 | |||
86 | it('Should fail with a non authenticated user', async function () { | ||
87 | const path = basePath + server.video.id | ||
88 | |||
89 | await request(server.url) | ||
90 | .delete(path) | ||
91 | .set('Authorization', 'Bearer ' + 'fake token') | ||
92 | .set('Accept', 'application/json') | ||
93 | .expect(401) | ||
94 | }) | ||
95 | |||
96 | it('Should fail with a non admin user', async function () { | ||
97 | const path = basePath + server.video.id | ||
98 | |||
99 | await request(server.url) | ||
100 | .delete(path) | ||
101 | .set('Authorization', 'Bearer ' + userAccessToken) | ||
102 | .set('Accept', 'application/json') | ||
103 | .expect(403) | ||
104 | }) | ||
105 | |||
106 | it('Should fail with an incorrect id', async function () { | ||
107 | const path = basePath + 'foobar' | ||
108 | |||
109 | await request(server.url) | ||
110 | .delete(path) | ||
111 | .set('Authorization', 'Bearer ' + server.accessToken) | ||
112 | .set('Accept', 'application/json') | ||
113 | .expect(400) | ||
114 | }) | ||
115 | |||
116 | it('Should fail with a not blacklisted video', async function () { | ||
117 | // The video was not added to the blacklist so it should fail | ||
118 | const path = basePath + server.video.id | ||
119 | |||
120 | await request(server.url) | ||
121 | .delete(path) | ||
122 | .set('Authorization', 'Bearer ' + server.accessToken) | ||
123 | .set('Accept', 'application/json') | ||
124 | .expect(404) | ||
125 | }) | ||
126 | }) | ||
127 | |||
128 | describe('When listing videos in blacklist', function () { | ||
129 | const basePath = '/api/v1/blacklist/' | ||
130 | |||
131 | it('Should fail with a non authenticated user', async function () { | ||
132 | const path = basePath | ||
133 | |||
134 | await request(server.url) | ||
135 | .get(path) | ||
136 | .query({ sort: 'createdAt' }) | ||
137 | .set('Accept', 'application/json') | ||
138 | .set('Authorization', 'Bearer ' + 'fake token') | ||
139 | .expect(401) | ||
140 | }) | ||
141 | |||
142 | it('Should fail with a non admin user', async function () { | ||
143 | const path = basePath | ||
144 | |||
145 | await request(server.url) | ||
146 | .get(path) | ||
147 | .query({ sort: 'createdAt' }) | ||
148 | .set('Authorization', 'Bearer ' + userAccessToken) | ||
149 | .set('Accept', 'application/json') | ||
150 | .expect(403) | ||
151 | }) | ||
152 | |||
153 | it('Should fail with a bad start pagination', async function () { | ||
154 | const path = basePath | ||
155 | |||
156 | await request(server.url) | ||
157 | .get(path) | ||
158 | .query({ start: 'foobar' }) | ||
159 | .set('Accept', 'application/json') | ||
160 | .set('Authorization', 'Bearer ' + server.accessToken) | ||
161 | .expect(400) | ||
162 | }) | ||
163 | |||
164 | it('Should fail with a bad count pagination', async function () { | ||
165 | const path = basePath | ||
166 | |||
167 | await request(server.url) | ||
168 | .get(path) | ||
169 | .query({ count: 'foobar' }) | ||
170 | .set('Accept', 'application/json') | ||
171 | .set('Authorization', 'Bearer ' + server.accessToken) | ||
172 | .expect(400) | ||
173 | }) | ||
174 | |||
175 | it('Should fail with an incorrect sort', async function () { | ||
176 | const path = basePath | ||
177 | |||
178 | await request(server.url) | ||
179 | .get(path) | ||
180 | .query({ sort: 'foobar' }) | ||
181 | .set('Accept', 'application/json') | ||
182 | .set('Authorization', 'Bearer ' + server.accessToken) | ||
183 | .expect(400) | ||
184 | }) | ||
185 | }) | ||
186 | |||
187 | after(async function () { | ||
188 | killallServers([ server ]) | ||
189 | |||
190 | // Keep the logs if the test failed | ||
191 | if (this['ok']) { | ||
192 | await flushTests() | ||
193 | } | ||
194 | }) | ||
195 | }) | ||
diff --git a/server/tests/api/check-params/video-blacklists.ts b/server/tests/api/check-params/video-blacklists.ts deleted file mode 100644 index d0ad78ff1..000000000 --- a/server/tests/api/check-params/video-blacklists.ts +++ /dev/null | |||
@@ -1,90 +0,0 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | ||
2 | |||
3 | import 'mocha' | ||
4 | |||
5 | import { | ||
6 | ServerInfo, | ||
7 | flushTests, | ||
8 | runServer, | ||
9 | uploadVideo, | ||
10 | getVideosList, | ||
11 | createUser, | ||
12 | setAccessTokensToServers, | ||
13 | killallServers, | ||
14 | makePostBodyRequest, | ||
15 | getUserAccessToken | ||
16 | } from '../../utils' | ||
17 | |||
18 | describe('Test video blacklists API validators', function () { | ||
19 | let server: ServerInfo | ||
20 | let userAccessToken = '' | ||
21 | |||
22 | // --------------------------------------------------------------- | ||
23 | |||
24 | before(async function () { | ||
25 | this.timeout(120000) | ||
26 | |||
27 | await flushTests() | ||
28 | |||
29 | server = await runServer(1) | ||
30 | |||
31 | await setAccessTokensToServers([ server ]) | ||
32 | |||
33 | const username = 'user1' | ||
34 | const password = 'my super password' | ||
35 | await createUser(server.url, server.accessToken, username, password) | ||
36 | userAccessToken = await getUserAccessToken(server, { username, password }) | ||
37 | |||
38 | // Upload a video | ||
39 | const videoAttributes = {} | ||
40 | await uploadVideo(server.url, server.accessToken, videoAttributes) | ||
41 | |||
42 | const res = await getVideosList(server.url) | ||
43 | |||
44 | const videos = res.body.data | ||
45 | server.video = videos[0] | ||
46 | }) | ||
47 | |||
48 | describe('When adding a video in blacklist', function () { | ||
49 | const basePath = '/api/v1/videos/' | ||
50 | |||
51 | it('Should fail with nothing', async function () { | ||
52 | const path = basePath + server.video + '/blacklist' | ||
53 | const fields = {} | ||
54 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
55 | }) | ||
56 | |||
57 | it('Should fail with a wrong video', async function () { | ||
58 | const wrongPath = '/api/v1/videos/blabla/blacklist' | ||
59 | const fields = {} | ||
60 | await makePostBodyRequest({ url: server.url, path: wrongPath, token: server.accessToken, fields }) | ||
61 | }) | ||
62 | |||
63 | it('Should fail with a non authenticated user', async function () { | ||
64 | const fields = {} | ||
65 | const path = basePath + server.video + '/blacklist' | ||
66 | await makePostBodyRequest({ url: server.url, path, token: 'hello', fields, statusCodeExpected: 401 }) | ||
67 | }) | ||
68 | |||
69 | it('Should fail with a non admin user', async function () { | ||
70 | const fields = {} | ||
71 | const path = basePath + server.video + '/blacklist' | ||
72 | await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields, statusCodeExpected: 403 }) | ||
73 | }) | ||
74 | |||
75 | it('Should fail with a local video', async function () { | ||
76 | const fields = {} | ||
77 | const path = basePath + server.video.id + '/blacklist' | ||
78 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 403 }) | ||
79 | }) | ||
80 | }) | ||
81 | |||
82 | after(async function () { | ||
83 | killallServers([ server ]) | ||
84 | |||
85 | // Keep the logs if the test failed | ||
86 | if (this['ok']) { | ||
87 | await flushTests() | ||
88 | } | ||
89 | }) | ||
90 | }) | ||
diff --git a/server/tests/api/index.ts b/server/tests/api/index.ts index f60d709c8..03711e68a 100644 --- a/server/tests/api/index.ts +++ b/server/tests/api/index.ts | |||
@@ -6,6 +6,7 @@ import './users' | |||
6 | import './single-pod' | 6 | import './single-pod' |
7 | import './video-abuse' | 7 | import './video-abuse' |
8 | import './video-blacklist' | 8 | import './video-blacklist' |
9 | import './video-blacklist-management' | ||
9 | import './multiple-pods' | 10 | import './multiple-pods' |
10 | import './request-schedulers' | 11 | import './request-schedulers' |
11 | import './friends-advanced' | 12 | import './friends-advanced' |
diff --git a/server/tests/api/video-blacklist-management.ts b/server/tests/api/video-blacklist-management.ts new file mode 100644 index 000000000..7057f4b23 --- /dev/null +++ b/server/tests/api/video-blacklist-management.ts | |||
@@ -0,0 +1,162 @@ | |||
1 | /* tslint:disable:no-unused-expressions */ | ||
2 | |||
3 | import 'mocha' | ||
4 | import * as chai from 'chai' | ||
5 | const expect = chai.expect | ||
6 | import * as lodash from 'lodash' | ||
7 | const orderBy = lodash.orderBy | ||
8 | |||
9 | import { | ||
10 | ServerInfo, | ||
11 | flushTests, | ||
12 | wait, | ||
13 | setAccessTokensToServers, | ||
14 | flushAndRunMultipleServers, | ||
15 | killallServers, | ||
16 | makeFriends, | ||
17 | getVideosList, | ||
18 | uploadVideo, | ||
19 | addVideoToBlacklist, | ||
20 | removeVideoFromBlacklist, | ||
21 | getBlacklistedVideosList, | ||
22 | getSortedBlacklistedVideosList | ||
23 | } from '../utils' | ||
24 | |||
25 | describe('Test video blacklist management', function () { | ||
26 | let servers: ServerInfo[] = [] | ||
27 | |||
28 | async function blacklistVideosOnPod (server: ServerInfo) { | ||
29 | const res = await getVideosList(server.url) | ||
30 | |||
31 | const videos = res.body.data | ||
32 | for (let video of videos) { | ||
33 | await addVideoToBlacklist(server.url, server.accessToken, video.id) | ||
34 | } | ||
35 | } | ||
36 | |||
37 | before(async function () { | ||
38 | this.timeout(120000) | ||
39 | |||
40 | // Run servers | ||
41 | servers = await flushAndRunMultipleServers(2) | ||
42 | |||
43 | // Get the access tokens | ||
44 | await setAccessTokensToServers(servers) | ||
45 | |||
46 | // Pod 1 makes friend with pod 2 | ||
47 | await makeFriends(servers[0].url, servers[0].accessToken) | ||
48 | |||
49 | // Upload 2 videos on pod 2 | ||
50 | await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'My 1st video', description: 'A video on pod 2' }) | ||
51 | await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'My 2nd video', description: 'A video on pod 2' }) | ||
52 | |||
53 | // Wait videos propagation | ||
54 | await wait(22000) | ||
55 | |||
56 | // Blacklist the two videos on pod 1 | ||
57 | await blacklistVideosOnPod(servers[0]) | ||
58 | }) | ||
59 | |||
60 | describe('When listing blacklisted videos', function () { | ||
61 | it('Should display all the blacklisted videos', async function () { | ||
62 | const res = await getBlacklistedVideosList(servers[0].url, servers[0].accessToken) | ||
63 | |||
64 | expect(res.body.total).to.equal(2) | ||
65 | |||
66 | const videos = res.body.data | ||
67 | expect(videos).to.be.an('array') | ||
68 | expect(videos.length).to.equal(2) | ||
69 | }) | ||
70 | |||
71 | it('Should get the correct sort when sorting by descending id', async function () { | ||
72 | const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, '-id') | ||
73 | expect(res.body.total).to.equal(2) | ||
74 | |||
75 | const videos = res.body.data | ||
76 | expect(videos).to.be.an('array') | ||
77 | expect(videos.length).to.equal(2) | ||
78 | |||
79 | const result = orderBy(res.body.data, [ 'id' ], [ 'desc' ]) | ||
80 | |||
81 | expect(videos).to.deep.equal(result) | ||
82 | }) | ||
83 | |||
84 | it('Should get the correct sort when sorting by descending video name', async function () { | ||
85 | const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, '-name') | ||
86 | expect(res.body.total).to.equal(2) | ||
87 | |||
88 | const videos = res.body.data | ||
89 | expect(videos).to.be.an('array') | ||
90 | expect(videos.length).to.equal(2) | ||
91 | |||
92 | const result = orderBy(res.body.data, [ 'name' ], [ 'desc' ]) | ||
93 | |||
94 | expect(videos).to.deep.equal(result) | ||
95 | }) | ||
96 | |||
97 | it('Should get the correct sort when sorting by ascending creation date', async function () { | ||
98 | const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, 'createdAt') | ||
99 | expect(res.body.total).to.equal(2) | ||
100 | |||
101 | const videos = res.body.data | ||
102 | expect(videos).to.be.an('array') | ||
103 | expect(videos.length).to.equal(2) | ||
104 | |||
105 | const result = orderBy(res.body.data, [ 'createdAt' ]) | ||
106 | |||
107 | expect(videos).to.deep.equal(result) | ||
108 | }) | ||
109 | }) | ||
110 | |||
111 | describe('When removing a blacklisted video', function () { | ||
112 | let videoToRemove | ||
113 | let blacklist = [] | ||
114 | |||
115 | it('Should not have any video in videos list on pod 1', async function () { | ||
116 | const res = await getVideosList(servers[0].url) | ||
117 | expect(res.body.total).to.equal(0) | ||
118 | expect(res.body.data).to.be.an('array') | ||
119 | expect(res.body.data.length).to.equal(0) | ||
120 | }) | ||
121 | |||
122 | it('Should remove a video from the blacklist on pod 1', async function () { | ||
123 | // Get one video in the blacklist | ||
124 | const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, '-name') | ||
125 | videoToRemove = res.body.data[0] | ||
126 | blacklist = res.body.data.slice(1) | ||
127 | |||
128 | // Remove it | ||
129 | await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, videoToRemove.videoId) | ||
130 | }) | ||
131 | |||
132 | it('Should have the ex-blacklisted video in videos list on pod 1', async function () { | ||
133 | const res = await getVideosList(servers[0].url) | ||
134 | expect(res.body.total).to.equal(1) | ||
135 | |||
136 | const videos = res.body.data | ||
137 | expect(videos).to.be.an('array') | ||
138 | expect(videos.length).to.equal(1) | ||
139 | |||
140 | expect(videos[0].name).to.equal(videoToRemove.name) | ||
141 | expect(videos[0].id).to.equal(videoToRemove.videoId) | ||
142 | }) | ||
143 | |||
144 | it('Should not have the ex-blacklisted video in videos blacklist list on pod 1', async function () { | ||
145 | const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, '-name') | ||
146 | expect(res.body.total).to.equal(1) | ||
147 | |||
148 | const videos = res.body.data | ||
149 | expect(videos).to.be.an('array') | ||
150 | expect(videos.length).to.equal(1) | ||
151 | expect(videos).to.deep.equal(blacklist) | ||
152 | }) | ||
153 | }) | ||
154 | |||
155 | after(async function () { | ||
156 | killallServers(servers) | ||
157 | |||
158 | if (this['ok']) { | ||
159 | await flushTests() | ||
160 | } | ||
161 | }) | ||
162 | }) | ||
diff --git a/server/tests/api/video-transcoder.ts b/server/tests/api/video-transcoder.ts index 228cef007..c6d4c61f5 100644 --- a/server/tests/api/video-transcoder.ts +++ b/server/tests/api/video-transcoder.ts | |||
@@ -20,7 +20,7 @@ describe('Test video transcoding', function () { | |||
20 | let servers: ServerInfo[] = [] | 20 | let servers: ServerInfo[] = [] |
21 | 21 | ||
22 | before(async function () { | 22 | before(async function () { |
23 | this.timeout(30000) | 23 | this.timeout(60000) |
24 | 24 | ||
25 | // Run servers | 25 | // Run servers |
26 | servers = await flushAndRunMultipleServers(2) | 26 | servers = await flushAndRunMultipleServers(2) |
diff --git a/server/tests/utils/index.ts b/server/tests/utils/index.ts index 0fa28f2af..99c445887 100644 --- a/server/tests/utils/index.ts +++ b/server/tests/utils/index.ts | |||
@@ -9,5 +9,5 @@ export * from './requests' | |||
9 | export * from './servers' | 9 | export * from './servers' |
10 | export * from './users' | 10 | export * from './users' |
11 | export * from './video-abuses' | 11 | export * from './video-abuses' |
12 | export * from './video-blacklists' | 12 | export * from './video-blacklist' |
13 | export * from './videos' | 13 | export * from './videos' |
diff --git a/server/tests/utils/video-blacklist.ts b/server/tests/utils/video-blacklist.ts new file mode 100644 index 000000000..5729d13d8 --- /dev/null +++ b/server/tests/utils/video-blacklist.ts | |||
@@ -0,0 +1,54 @@ | |||
1 | import * as request from 'supertest' | ||
2 | |||
3 | function addVideoToBlacklist (url: string, token: string, videoId: number, specialStatus = 204) { | ||
4 | const path = '/api/v1/videos/' + videoId + '/blacklist' | ||
5 | |||
6 | return request(url) | ||
7 | .post(path) | ||
8 | .set('Accept', 'application/json') | ||
9 | .set('Authorization', 'Bearer ' + token) | ||
10 | .expect(specialStatus) | ||
11 | } | ||
12 | |||
13 | function removeVideoFromBlacklist (url: string, token: string, videoId: number, specialStatus = 204) { | ||
14 | const path = '/api/v1/blacklist/' + videoId | ||
15 | |||
16 | return request(url) | ||
17 | .delete(path) | ||
18 | .set('Accept', 'application/json') | ||
19 | .set('Authorization', 'Bearer ' + token) | ||
20 | .expect(specialStatus) | ||
21 | } | ||
22 | |||
23 | function getBlacklistedVideosList (url: string, token: string, specialStatus = 200) { | ||
24 | const path = '/api/v1/blacklist/' | ||
25 | |||
26 | return request(url) | ||
27 | .get(path) | ||
28 | .query({ sort: 'createdAt' }) | ||
29 | .set('Accept', 'application/json') | ||
30 | .set('Authorization', 'Bearer ' + token) | ||
31 | .expect(specialStatus) | ||
32 | .expect('Content-Type', /json/) | ||
33 | } | ||
34 | |||
35 | function getSortedBlacklistedVideosList (url: string, token: string, sort: string, specialStatus = 200) { | ||
36 | const path = '/api/v1/blacklist/' | ||
37 | |||
38 | return request(url) | ||
39 | .get(path) | ||
40 | .query({ sort: sort }) | ||
41 | .set('Accept', 'application/json') | ||
42 | .set('Authorization', 'Bearer ' + token) | ||
43 | .expect(specialStatus) | ||
44 | .expect('Content-Type', /json/) | ||
45 | } | ||
46 | |||
47 | // --------------------------------------------------------------------------- | ||
48 | |||
49 | export { | ||
50 | addVideoToBlacklist, | ||
51 | removeVideoFromBlacklist, | ||
52 | getBlacklistedVideosList, | ||
53 | getSortedBlacklistedVideosList | ||
54 | } | ||
diff --git a/server/tests/utils/video-blacklists.ts b/server/tests/utils/video-blacklists.ts deleted file mode 100644 index 6812d3ad4..000000000 --- a/server/tests/utils/video-blacklists.ts +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | import * as request from 'supertest' | ||
2 | |||
3 | function addVideoToBlacklist (url: string, token: string, videoId: number, specialStatus = 204) { | ||
4 | const path = '/api/v1/videos/' + videoId + '/blacklist' | ||
5 | |||
6 | return request(url) | ||
7 | .post(path) | ||
8 | .set('Accept', 'application/json') | ||
9 | .set('Authorization', 'Bearer ' + token) | ||
10 | .expect(specialStatus) | ||
11 | } | ||
12 | |||
13 | // --------------------------------------------------------------------------- | ||
14 | |||
15 | export { | ||
16 | addVideoToBlacklist | ||
17 | } | ||
diff --git a/shared/models/videos/video-blacklist.model.ts b/shared/models/videos/video-blacklist.model.ts index 6086250ac..af04502e8 100644 --- a/shared/models/videos/video-blacklist.model.ts +++ b/shared/models/videos/video-blacklist.model.ts | |||
@@ -2,4 +2,13 @@ export interface BlacklistedVideo { | |||
2 | id: number | 2 | id: number |
3 | videoId: number | 3 | videoId: number |
4 | createdAt: Date | 4 | createdAt: Date |
5 | updatedAt: Date | ||
6 | name: string | ||
7 | uuid: string | ||
8 | description: string | ||
9 | duration: number | ||
10 | views: number | ||
11 | likes: number | ||
12 | dislikes: number | ||
13 | nsfw: boolean | ||
5 | } | 14 | } |