>(BlacklistService.BASE_BLACKLISTS_URL, { params })
+ .map(res => this.restExtractor.convertResultListDateToHuman(res))
+ .map(res => this.restExtractor.applyToResultListData(res, this.formatBlacklistedVideo.bind(this)))
+ .catch(res => this.restExtractor.handleError(res))
+ }
+
+ removeVideoFromBlacklist (entry: BlacklistedVideo) {
+ return this.authHttp.delete(BlacklistService.BASE_BLACKLISTS_URL + entry.id)
+ .map(this.restExtractor.extractDataBool)
+ .catch(res => this.restExtractor.handleError(res))
+ }
+
+ private formatBlacklistedVideo (blacklistedVideo: BlacklistedVideo) {
+ return Object.assign(blacklistedVideo, {
+ createdAt: Utils.dateToHuman(blacklistedVideo.createdAt)
+ })
+ }
+}
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 @@
Video abuses
+
+
+
+ Video blacklist
+
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 @@
+import * as express from 'express'
+
+import { database } from '../../initializers'
+import { getFormattedObjects } from '../../helpers'
+import { BlacklistedVideo } from '../../../shared'
+import { BlacklistedVideoInstance } from '../../models'
+
+import {
+ removeVideoFromBlacklist
+} from '../../lib'
+import {
+ authenticate,
+ ensureIsAdmin,
+ paginationValidator,
+ blacklistSortValidator,
+ setBlacklistSort,
+ setPagination,
+ blacklistRemoveValidator
+} from '../../middlewares'
+
+const blacklistRouter = express.Router()
+
+blacklistRouter.get('/',
+ authenticate,
+ ensureIsAdmin,
+ paginationValidator,
+ blacklistSortValidator,
+ setBlacklistSort,
+ setPagination,
+ listBlacklist
+)
+
+blacklistRouter.delete('/:id',
+ authenticate,
+ ensureIsAdmin,
+ blacklistRemoveValidator,
+ removeVideoFromBlacklistController
+)
+
+// ---------------------------------------------------------------------------
+
+export {
+ blacklistRouter
+}
+
+// ---------------------------------------------------------------------------
+
+function listBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) {
+ database.BlacklistedVideo.listForApi(req.query.start, req.query.count, req.query.sort)
+ .then(resultList => res.json(getFormattedObjects(resultList.data, resultList.total)))
+ .catch(err => next(err))
+}
+
+function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) {
+ const entry = res.locals.blacklistEntryToRemove as BlacklistedVideoInstance
+
+ removeVideoFromBlacklist(entry)
+ .then(() => res.sendStatus(204))
+ .catch(err => next(err))
+}
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'
import { requestSchedulerRouter } from './request-schedulers'
import { usersRouter } from './users'
import { videosRouter } from './videos'
+import { blacklistRouter } from './blacklist'
const apiRouter = express.Router()
@@ -19,6 +20,7 @@ apiRouter.use('/remote', remoteRouter)
apiRouter.use('/request-schedulers', requestSchedulerRouter)
apiRouter.use('/users', usersRouter)
apiRouter.use('/videos', videosRouter)
+apiRouter.use('/blacklist', blacklistRouter)
apiRouter.use('/ping', pong)
apiRouter.use('/*', badRequest)
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 () {
})
}
+type SortType = { sortModel: any, sortValue: string }
+
// ---------------------------------------------------------------------------
export {
badRequest,
generateRandomString,
getFormattedObjects,
- isSignupAllowed
+ isSignupAllowed,
+ SortType
}
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 = {
const SORTABLE_COLUMNS = {
USERS: [ 'id', 'username', 'createdAt' ],
VIDEO_ABUSES: [ 'id', 'createdAt' ],
- VIDEOS: [ 'name', 'duration', 'createdAt', 'views', 'likes' ]
+ VIDEOS: [ 'name', 'duration', 'createdAt', 'views', 'likes' ],
+ BLACKLISTS: [ 'id', 'name', 'duration', 'views', 'likes', 'dislikes', 'uuid', 'createdAt' ]
}
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 @@
+import { logger } from '../helpers'
+import { BlacklistedVideoInstance } from '../models'
+
+function removeVideoFromBlacklist (entry: BlacklistedVideoInstance) {
+ return entry.destroy()
+ .then(() => {
+ logger.info('Video removed from the blacklist')
+ })
+ .catch(err => {
+ logger.error('Some error while removing video from the blacklist.', err)
+ })
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+ removeVideoFromBlacklist
+}
+
+// ---------------------------------------------------------------------------
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'
export * from './request'
export * from './friends'
export * from './oauth-model'
+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 @@
import 'express-validator'
import * as express from 'express'
+import { SortType } from '../helpers'
+import { database } from '../initializers'
+
function setUsersSort (req: express.Request, res: express.Response, next: express.NextFunction) {
if (!req.query.sort) req.query.sort = '-createdAt'
@@ -19,10 +22,32 @@ function setVideosSort (req: express.Request, res: express.Response, next: expre
return next()
}
+function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) {
+ let newSort: SortType = { sortModel: undefined, sortValue: undefined }
+
+ if (!req.query.sort) req.query.sort = '-createdAt'
+
+ // Set model we want to sort onto
+ if (req.query.sort === '-createdAt' || req.query.sort === 'createdAt' ||
+ req.query.sort === '-id' || req.query.sort === 'id') {
+ // If we want to sort onto the BlacklistedVideos relation, we won't specify it in the query parameter ...
+ newSort.sortModel = undefined
+ } else {
+ newSort.sortModel = database.Video
+ }
+
+ newSort.sortValue = req.query.sort
+
+ req.query.sort = newSort
+
+ return next()
+}
+
// ---------------------------------------------------------------------------
export {
setUsersSort,
setVideoAbusesSort,
- setVideosSort
+ setVideosSort,
+ setBlacklistSort
}
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 @@
+import { param } from 'express-validator/check'
+import * as express from 'express'
+
+import { database as db } from '../../initializers/database'
+import { checkErrors } from './utils'
+import { logger } from '../../helpers'
+
+const blacklistRemoveValidator = [
+ param('id').isNumeric().not().isEmpty().withMessage('Should have a valid id'),
+
+ (req: express.Request, res: express.Response, next: express.NextFunction) => {
+ logger.debug('Checking blacklistRemove parameters.', { parameters: req.params })
+
+ checkErrors(req, res, () => {
+ db.BlacklistedVideo.loadById(req.params.id)
+ .then(entry => {
+ if (!entry) return res.status(404).send('Blacklisted video not found')
+
+ res.locals.blacklistEntryToRemove = entry
+
+ next()
+ })
+ .catch(err => {
+ logger.error('Error in blacklistRemove request validator', { error: err })
+ return res.sendStatus(500)
+ })
+ })
+ }
+]
+
+// ---------------------------------------------------------------------------
+
+export {
+ blacklistRemoveValidator
+}
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'
export * from './sort'
export * from './users'
export * from './videos'
+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'
const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS)
const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES)
const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS)
+const SORTABLE_BLACKLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.BLACKLISTS)
const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS)
const videoAbusesSortValidator = checkSort(SORTABLE_VIDEO_ABUSES_COLUMNS)
const videosSortValidator = checkSort(SORTABLE_VIDEOS_COLUMNS)
+const blacklistSortValidator = checkSort(SORTABLE_BLACKLISTS_COLUMNS)
// ---------------------------------------------------------------------------
export {
usersSortValidator,
videoAbusesSortValidator,
- videosSortValidator
+ videosSortValidator,
+ blacklistSortValidator
}
// ---------------------------------------------------------------------------
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
instanceMethods.forEach(m => model.prototype[m.name] = m)
}
+function getSortOnModel (model: any, value: string) {
+ let sort = getSort(value)
+
+ if (model) return [ { model: model }, sort[0], sort[1] ]
+ return sort
+}
+
// ---------------------------------------------------------------------------
export {
addMethodsToModel,
- getSort
+ getSort,
+ getSortOnModel
}
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 @@
import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird'
+import { SortType } from '../../helpers'
import { ResultList } from '../../../shared'
+import { VideoInstance } from './video-interface'
// Don't use barrel, import just what we need
import { BlacklistedVideo as FormattedBlacklistedVideo } from '../../../shared/models/videos/video-blacklist.model'
@@ -13,7 +15,7 @@ export namespace BlacklistedVideoMethods {
export type List = () => Promise
- export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList >
+ export type ListForApi = (start: number, count: number, sort: SortType) => Promise< ResultList >
export type LoadById = (id: number) => Promise
@@ -31,6 +33,8 @@ export interface BlacklistedVideoClass {
export interface BlacklistedVideoAttributes {
videoId: number
+
+ Video?: VideoInstance
}
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 @@
import * as Sequelize from 'sequelize'
-import { addMethodsToModel, getSort } from '../utils'
+import { SortType } from '../../helpers'
+import { addMethodsToModel, getSortOnModel } from '../utils'
+import { VideoInstance } from './video-interface'
import {
BlacklistedVideoInstance,
BlacklistedVideoAttributes,
@@ -49,10 +51,23 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
// ------------------------------ METHODS ------------------------------
toFormattedJSON = function (this: BlacklistedVideoInstance) {
+ let video: VideoInstance
+
+ video = this.Video
+
return {
id: this.id,
videoId: this.videoId,
- createdAt: this.createdAt
+ createdAt: this.createdAt,
+ updatedAt: this.updatedAt,
+ name: video.name,
+ uuid: video.uuid,
+ description: video.description,
+ duration: video.duration,
+ views: video.views,
+ likes: video.likes,
+ dislikes: video.dislikes,
+ nsfw: video.nsfw
}
}
@@ -76,11 +91,12 @@ list = function () {
return BlacklistedVideo.findAll()
}
-listForApi = function (start: number, count: number, sort: string) {
+listForApi = function (start: number, count: number, sort: SortType) {
const query = {
offset: start,
limit: count,
- order: [ getSort(sort) ]
+ order: [ getSortOnModel(sort.sortModel, sort.sortValue) ],
+ include: [ { model: BlacklistedVideo['sequelize'].models.Video } ]
}
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'
import './request-schedulers'
import './videos'
import './video-abuses'
-import './video-blacklists'
+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 () {
// ---------------------------------------------------------------
before(async function () {
- this.timeout(20000)
+ this.timeout(60000)
await flushTests()
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 () {
// ---------------------------------------------------------------
before(async function () {
- this.timeout(20000)
+ this.timeout(60000)
await flushTests()
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 @@
+/* tslint:disable:no-unused-expression */
+
+import 'mocha'
+import * as request from 'supertest'
+
+import {
+ ServerInfo,
+ flushTests,
+ runServer,
+ uploadVideo,
+ getVideosList,
+ createUser,
+ setAccessTokensToServers,
+ killallServers,
+ makePostBodyRequest,
+ getUserAccessToken
+} from '../../utils'
+
+describe('Test video blacklist API validators', function () {
+ let server: ServerInfo
+ let userAccessToken = ''
+
+ // ---------------------------------------------------------------
+
+ before(async function () {
+ this.timeout(120000)
+
+ await flushTests()
+
+ server = await runServer(1)
+
+ await setAccessTokensToServers([ server ])
+
+ const username = 'user1'
+ const password = 'my super password'
+ await createUser(server.url, server.accessToken, username, password)
+ userAccessToken = await getUserAccessToken(server, { username, password })
+
+ // Upload a video
+ const videoAttributes = {}
+ await uploadVideo(server.url, server.accessToken, videoAttributes)
+
+ const res = await getVideosList(server.url)
+
+ const videos = res.body.data
+ server.video = videos[0]
+ })
+
+ describe('When adding a video in blacklist', function () {
+ const basePath = '/api/v1/videos/'
+
+ it('Should fail with nothing', async function () {
+ const path = basePath + server.video + '/blacklist'
+ const fields = {}
+ await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
+ })
+
+ it('Should fail with a wrong video', async function () {
+ const wrongPath = '/api/v1/videos/blabla/blacklist'
+ const fields = {}
+ await makePostBodyRequest({ url: server.url, path: wrongPath, token: server.accessToken, fields })
+ })
+
+ it('Should fail with a non authenticated user', async function () {
+ const fields = {}
+ const path = basePath + server.video + '/blacklist'
+ await makePostBodyRequest({ url: server.url, path, token: 'hello', fields, statusCodeExpected: 401 })
+ })
+
+ it('Should fail with a non admin user', async function () {
+ const fields = {}
+ const path = basePath + server.video + '/blacklist'
+ await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields, statusCodeExpected: 403 })
+ })
+
+ it('Should fail with a local video', async function () {
+ const fields = {}
+ const path = basePath + server.video.id + '/blacklist'
+ await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 403 })
+ })
+ })
+
+ describe('When removing a video in blacklist', function () {
+ const basePath = '/api/v1/blacklist/'
+
+ it('Should fail with a non authenticated user', async function () {
+ const path = basePath + server.video.id
+
+ await request(server.url)
+ .delete(path)
+ .set('Authorization', 'Bearer ' + 'fake token')
+ .set('Accept', 'application/json')
+ .expect(401)
+ })
+
+ it('Should fail with a non admin user', async function () {
+ const path = basePath + server.video.id
+
+ await request(server.url)
+ .delete(path)
+ .set('Authorization', 'Bearer ' + userAccessToken)
+ .set('Accept', 'application/json')
+ .expect(403)
+ })
+
+ it('Should fail with an incorrect id', async function () {
+ const path = basePath + 'foobar'
+
+ await request(server.url)
+ .delete(path)
+ .set('Authorization', 'Bearer ' + server.accessToken)
+ .set('Accept', 'application/json')
+ .expect(400)
+ })
+
+ it('Should fail with a not blacklisted video', async function () {
+ // The video was not added to the blacklist so it should fail
+ const path = basePath + server.video.id
+
+ await request(server.url)
+ .delete(path)
+ .set('Authorization', 'Bearer ' + server.accessToken)
+ .set('Accept', 'application/json')
+ .expect(404)
+ })
+ })
+
+ describe('When listing videos in blacklist', function () {
+ const basePath = '/api/v1/blacklist/'
+
+ it('Should fail with a non authenticated user', async function () {
+ const path = basePath
+
+ await request(server.url)
+ .get(path)
+ .query({ sort: 'createdAt' })
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + 'fake token')
+ .expect(401)
+ })
+
+ it('Should fail with a non admin user', async function () {
+ const path = basePath
+
+ await request(server.url)
+ .get(path)
+ .query({ sort: 'createdAt' })
+ .set('Authorization', 'Bearer ' + userAccessToken)
+ .set('Accept', 'application/json')
+ .expect(403)
+ })
+
+ it('Should fail with a bad start pagination', async function () {
+ const path = basePath
+
+ await request(server.url)
+ .get(path)
+ .query({ start: 'foobar' })
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + server.accessToken)
+ .expect(400)
+ })
+
+ it('Should fail with a bad count pagination', async function () {
+ const path = basePath
+
+ await request(server.url)
+ .get(path)
+ .query({ count: 'foobar' })
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + server.accessToken)
+ .expect(400)
+ })
+
+ it('Should fail with an incorrect sort', async function () {
+ const path = basePath
+
+ await request(server.url)
+ .get(path)
+ .query({ sort: 'foobar' })
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + server.accessToken)
+ .expect(400)
+ })
+ })
+
+ after(async function () {
+ killallServers([ server ])
+
+ // Keep the logs if the test failed
+ if (this['ok']) {
+ await flushTests()
+ }
+ })
+})
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 @@
-/* tslint:disable:no-unused-expression */
-
-import 'mocha'
-
-import {
- ServerInfo,
- flushTests,
- runServer,
- uploadVideo,
- getVideosList,
- createUser,
- setAccessTokensToServers,
- killallServers,
- makePostBodyRequest,
- getUserAccessToken
-} from '../../utils'
-
-describe('Test video blacklists API validators', function () {
- let server: ServerInfo
- let userAccessToken = ''
-
- // ---------------------------------------------------------------
-
- before(async function () {
- this.timeout(120000)
-
- await flushTests()
-
- server = await runServer(1)
-
- await setAccessTokensToServers([ server ])
-
- const username = 'user1'
- const password = 'my super password'
- await createUser(server.url, server.accessToken, username, password)
- userAccessToken = await getUserAccessToken(server, { username, password })
-
- // Upload a video
- const videoAttributes = {}
- await uploadVideo(server.url, server.accessToken, videoAttributes)
-
- const res = await getVideosList(server.url)
-
- const videos = res.body.data
- server.video = videos[0]
- })
-
- describe('When adding a video in blacklist', function () {
- const basePath = '/api/v1/videos/'
-
- it('Should fail with nothing', async function () {
- const path = basePath + server.video + '/blacklist'
- const fields = {}
- await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
- })
-
- it('Should fail with a wrong video', async function () {
- const wrongPath = '/api/v1/videos/blabla/blacklist'
- const fields = {}
- await makePostBodyRequest({ url: server.url, path: wrongPath, token: server.accessToken, fields })
- })
-
- it('Should fail with a non authenticated user', async function () {
- const fields = {}
- const path = basePath + server.video + '/blacklist'
- await makePostBodyRequest({ url: server.url, path, token: 'hello', fields, statusCodeExpected: 401 })
- })
-
- it('Should fail with a non admin user', async function () {
- const fields = {}
- const path = basePath + server.video + '/blacklist'
- await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields, statusCodeExpected: 403 })
- })
-
- it('Should fail with a local video', async function () {
- const fields = {}
- const path = basePath + server.video.id + '/blacklist'
- await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 403 })
- })
- })
-
- after(async function () {
- killallServers([ server ])
-
- // Keep the logs if the test failed
- if (this['ok']) {
- await flushTests()
- }
- })
-})
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'
import './single-pod'
import './video-abuse'
import './video-blacklist'
+import './video-blacklist-management'
import './multiple-pods'
import './request-schedulers'
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 @@
+/* tslint:disable:no-unused-expressions */
+
+import 'mocha'
+import * as chai from 'chai'
+const expect = chai.expect
+import * as lodash from 'lodash'
+const orderBy = lodash.orderBy
+
+import {
+ ServerInfo,
+ flushTests,
+ wait,
+ setAccessTokensToServers,
+ flushAndRunMultipleServers,
+ killallServers,
+ makeFriends,
+ getVideosList,
+ uploadVideo,
+ addVideoToBlacklist,
+ removeVideoFromBlacklist,
+ getBlacklistedVideosList,
+ getSortedBlacklistedVideosList
+} from '../utils'
+
+describe('Test video blacklist management', function () {
+ let servers: ServerInfo[] = []
+
+ async function blacklistVideosOnPod (server: ServerInfo) {
+ const res = await getVideosList(server.url)
+
+ const videos = res.body.data
+ for (let video of videos) {
+ await addVideoToBlacklist(server.url, server.accessToken, video.id)
+ }
+ }
+
+ before(async function () {
+ this.timeout(120000)
+
+ // Run servers
+ servers = await flushAndRunMultipleServers(2)
+
+ // Get the access tokens
+ await setAccessTokensToServers(servers)
+
+ // Pod 1 makes friend with pod 2
+ await makeFriends(servers[0].url, servers[0].accessToken)
+
+ // Upload 2 videos on pod 2
+ await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'My 1st video', description: 'A video on pod 2' })
+ await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'My 2nd video', description: 'A video on pod 2' })
+
+ // Wait videos propagation
+ await wait(22000)
+
+ // Blacklist the two videos on pod 1
+ await blacklistVideosOnPod(servers[0])
+ })
+
+ describe('When listing blacklisted videos', function () {
+ it('Should display all the blacklisted videos', async function () {
+ const res = await getBlacklistedVideosList(servers[0].url, servers[0].accessToken)
+
+ expect(res.body.total).to.equal(2)
+
+ const videos = res.body.data
+ expect(videos).to.be.an('array')
+ expect(videos.length).to.equal(2)
+ })
+
+ it('Should get the correct sort when sorting by descending id', async function () {
+ const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, '-id')
+ expect(res.body.total).to.equal(2)
+
+ const videos = res.body.data
+ expect(videos).to.be.an('array')
+ expect(videos.length).to.equal(2)
+
+ const result = orderBy(res.body.data, [ 'id' ], [ 'desc' ])
+
+ expect(videos).to.deep.equal(result)
+ })
+
+ it('Should get the correct sort when sorting by descending video name', async function () {
+ const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, '-name')
+ expect(res.body.total).to.equal(2)
+
+ const videos = res.body.data
+ expect(videos).to.be.an('array')
+ expect(videos.length).to.equal(2)
+
+ const result = orderBy(res.body.data, [ 'name' ], [ 'desc' ])
+
+ expect(videos).to.deep.equal(result)
+ })
+
+ it('Should get the correct sort when sorting by ascending creation date', async function () {
+ const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, 'createdAt')
+ expect(res.body.total).to.equal(2)
+
+ const videos = res.body.data
+ expect(videos).to.be.an('array')
+ expect(videos.length).to.equal(2)
+
+ const result = orderBy(res.body.data, [ 'createdAt' ])
+
+ expect(videos).to.deep.equal(result)
+ })
+ })
+
+ describe('When removing a blacklisted video', function () {
+ let videoToRemove
+ let blacklist = []
+
+ it('Should not have any video in videos list on pod 1', async function () {
+ const res = await getVideosList(servers[0].url)
+ expect(res.body.total).to.equal(0)
+ expect(res.body.data).to.be.an('array')
+ expect(res.body.data.length).to.equal(0)
+ })
+
+ it('Should remove a video from the blacklist on pod 1', async function () {
+ // Get one video in the blacklist
+ const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, '-name')
+ videoToRemove = res.body.data[0]
+ blacklist = res.body.data.slice(1)
+
+ // Remove it
+ await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, videoToRemove.videoId)
+ })
+
+ it('Should have the ex-blacklisted video in videos list on pod 1', async function () {
+ const res = await getVideosList(servers[0].url)
+ expect(res.body.total).to.equal(1)
+
+ const videos = res.body.data
+ expect(videos).to.be.an('array')
+ expect(videos.length).to.equal(1)
+
+ expect(videos[0].name).to.equal(videoToRemove.name)
+ expect(videos[0].id).to.equal(videoToRemove.videoId)
+ })
+
+ it('Should not have the ex-blacklisted video in videos blacklist list on pod 1', async function () {
+ const res = await getSortedBlacklistedVideosList(servers[0].url, servers[0].accessToken, '-name')
+ expect(res.body.total).to.equal(1)
+
+ const videos = res.body.data
+ expect(videos).to.be.an('array')
+ expect(videos.length).to.equal(1)
+ expect(videos).to.deep.equal(blacklist)
+ })
+ })
+
+ after(async function () {
+ killallServers(servers)
+
+ if (this['ok']) {
+ await flushTests()
+ }
+ })
+})
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 () {
let servers: ServerInfo[] = []
before(async function () {
- this.timeout(30000)
+ this.timeout(60000)
// Run servers
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'
export * from './servers'
export * from './users'
export * from './video-abuses'
-export * from './video-blacklists'
+export * from './video-blacklist'
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 @@
+import * as request from 'supertest'
+
+function addVideoToBlacklist (url: string, token: string, videoId: number, specialStatus = 204) {
+ const path = '/api/v1/videos/' + videoId + '/blacklist'
+
+ return request(url)
+ .post(path)
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + token)
+ .expect(specialStatus)
+}
+
+function removeVideoFromBlacklist (url: string, token: string, videoId: number, specialStatus = 204) {
+ const path = '/api/v1/blacklist/' + videoId
+
+ return request(url)
+ .delete(path)
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + token)
+ .expect(specialStatus)
+}
+
+function getBlacklistedVideosList (url: string, token: string, specialStatus = 200) {
+ const path = '/api/v1/blacklist/'
+
+ return request(url)
+ .get(path)
+ .query({ sort: 'createdAt' })
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + token)
+ .expect(specialStatus)
+ .expect('Content-Type', /json/)
+}
+
+function getSortedBlacklistedVideosList (url: string, token: string, sort: string, specialStatus = 200) {
+ const path = '/api/v1/blacklist/'
+
+ return request(url)
+ .get(path)
+ .query({ sort: sort })
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + token)
+ .expect(specialStatus)
+ .expect('Content-Type', /json/)
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+ addVideoToBlacklist,
+ removeVideoFromBlacklist,
+ getBlacklistedVideosList,
+ getSortedBlacklistedVideosList
+}
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 @@
-import * as request from 'supertest'
-
-function addVideoToBlacklist (url: string, token: string, videoId: number, specialStatus = 204) {
- const path = '/api/v1/videos/' + videoId + '/blacklist'
-
- return request(url)
- .post(path)
- .set('Accept', 'application/json')
- .set('Authorization', 'Bearer ' + token)
- .expect(specialStatus)
-}
-
-// ---------------------------------------------------------------------------
-
-export {
- addVideoToBlacklist
-}
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 {
id: number
videoId: number
createdAt: Date
+ updatedAt: Date
+ name: string
+ uuid: string
+ description: string
+ duration: number
+ views: number
+ likes: number
+ dislikes: number
+ nsfw: boolean
}