diff options
Diffstat (limited to 'server')
22 files changed, 445 insertions, 71 deletions
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 88f047adc..e47b71f44 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -46,6 +46,7 @@ async function getConfig (req: express.Request, res: express.Response, next: exp | |||
46 | name: CONFIG.INSTANCE.NAME, | 46 | name: CONFIG.INSTANCE.NAME, |
47 | shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, | 47 | shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION, |
48 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, | 48 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, |
49 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | ||
49 | customizations: { | 50 | customizations: { |
50 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT, | 51 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT, |
51 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS | 52 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS |
@@ -128,6 +129,7 @@ async function updateCustomConfig (req: express.Request, res: express.Response, | |||
128 | toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota | 129 | toUpdateJSON.user['video_quota'] = toUpdate.user.videoQuota |
129 | toUpdateJSON.instance['default_client_route'] = toUpdate.instance.defaultClientRoute | 130 | toUpdateJSON.instance['default_client_route'] = toUpdate.instance.defaultClientRoute |
130 | toUpdateJSON.instance['short_description'] = toUpdate.instance.shortDescription | 131 | toUpdateJSON.instance['short_description'] = toUpdate.instance.shortDescription |
132 | toUpdateJSON.instance['default_nsfw_policy'] = toUpdate.instance.defaultNSFWPolicy | ||
131 | 133 | ||
132 | await writeFilePromise(CONFIG.CUSTOM_FILE, JSON.stringify(toUpdateJSON, undefined, 2)) | 134 | await writeFilePromise(CONFIG.CUSTOM_FILE, JSON.stringify(toUpdateJSON, undefined, 2)) |
133 | 135 | ||
@@ -153,6 +155,7 @@ function customConfig (): CustomConfig { | |||
153 | description: CONFIG.INSTANCE.DESCRIPTION, | 155 | description: CONFIG.INSTANCE.DESCRIPTION, |
154 | terms: CONFIG.INSTANCE.TERMS, | 156 | terms: CONFIG.INSTANCE.TERMS, |
155 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, | 157 | defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE, |
158 | defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | ||
156 | customizations: { | 159 | customizations: { |
157 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS, | 160 | css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS, |
158 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT | 161 | javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT |
diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts index 56cbf9448..6540adb1c 100644 --- a/server/controllers/api/users.ts +++ b/server/controllers/api/users.ts | |||
@@ -42,6 +42,7 @@ import { AccountVideoRateModel } from '../../models/account/account-video-rate' | |||
42 | import { UserModel } from '../../models/account/user' | 42 | import { UserModel } from '../../models/account/user' |
43 | import { OAuthTokenModel } from '../../models/oauth/oauth-token' | 43 | import { OAuthTokenModel } from '../../models/oauth/oauth-token' |
44 | import { VideoModel } from '../../models/video/video' | 44 | import { VideoModel } from '../../models/video/video' |
45 | import { VideoSortField } from '../../../client/src/app/shared/video/sort-field.type' | ||
45 | 46 | ||
46 | const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) | 47 | const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR }) |
47 | const loginRateLimiter = new RateLimit({ | 48 | const loginRateLimiter = new RateLimit({ |
@@ -161,7 +162,13 @@ export { | |||
161 | 162 | ||
162 | async function getUserVideos (req: express.Request, res: express.Response, next: express.NextFunction) { | 163 | async function getUserVideos (req: express.Request, res: express.Response, next: express.NextFunction) { |
163 | const user = res.locals.oauth.token.User as UserModel | 164 | const user = res.locals.oauth.token.User as UserModel |
164 | const resultList = await VideoModel.listAccountVideosForApi(user.Account.id ,req.query.start, req.query.count, req.query.sort) | 165 | const resultList = await VideoModel.listAccountVideosForApi( |
166 | user.Account.id, | ||
167 | req.query.start as number, | ||
168 | req.query.count as number, | ||
169 | req.query.sort as VideoSortField, | ||
170 | false // Display my NSFW videos | ||
171 | ) | ||
165 | 172 | ||
166 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 173 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
167 | } | 174 | } |
@@ -188,7 +195,7 @@ async function createUser (req: express.Request) { | |||
188 | username: body.username, | 195 | username: body.username, |
189 | password: body.password, | 196 | password: body.password, |
190 | email: body.email, | 197 | email: body.email, |
191 | displayNSFW: false, | 198 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
192 | autoPlayVideo: true, | 199 | autoPlayVideo: true, |
193 | role: body.role, | 200 | role: body.role, |
194 | videoQuota: body.videoQuota | 201 | videoQuota: body.videoQuota |
@@ -219,7 +226,7 @@ async function registerUser (req: express.Request) { | |||
219 | username: body.username, | 226 | username: body.username, |
220 | password: body.password, | 227 | password: body.password, |
221 | email: body.email, | 228 | email: body.email, |
222 | displayNSFW: false, | 229 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, |
223 | autoPlayVideo: true, | 230 | autoPlayVideo: true, |
224 | role: UserRole.USER, | 231 | role: UserRole.USER, |
225 | videoQuota: CONFIG.USER.VIDEO_QUOTA | 232 | videoQuota: CONFIG.USER.VIDEO_QUOTA |
@@ -286,7 +293,7 @@ async function updateMe (req: express.Request, res: express.Response, next: expr | |||
286 | 293 | ||
287 | if (body.password !== undefined) user.password = body.password | 294 | if (body.password !== undefined) user.password = body.password |
288 | if (body.email !== undefined) user.email = body.email | 295 | if (body.email !== undefined) user.email = body.email |
289 | if (body.displayNSFW !== undefined) user.displayNSFW = body.displayNSFW | 296 | if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy |
290 | if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo | 297 | if (body.autoPlayVideo !== undefined) user.autoPlayVideo = body.autoPlayVideo |
291 | 298 | ||
292 | await sequelizeTypescript.transaction(async t => { | 299 | await sequelizeTypescript.transaction(async t => { |
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index b4cd67158..6e8601fa1 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -19,13 +19,18 @@ import { | |||
19 | VIDEO_MIMETYPE_EXT, | 19 | VIDEO_MIMETYPE_EXT, |
20 | VIDEO_PRIVACIES | 20 | VIDEO_PRIVACIES |
21 | } from '../../../initializers' | 21 | } from '../../../initializers' |
22 | import { fetchRemoteVideoDescription, getVideoActivityPubUrl, shareVideoByServerAndChannel } from '../../../lib/activitypub' | 22 | import { |
23 | fetchRemoteVideoDescription, | ||
24 | getVideoActivityPubUrl, | ||
25 | shareVideoByServerAndChannel | ||
26 | } from '../../../lib/activitypub' | ||
23 | import { sendCreateVideo, sendCreateView, sendUpdateVideo } from '../../../lib/activitypub/send' | 27 | import { sendCreateVideo, sendCreateView, sendUpdateVideo } from '../../../lib/activitypub/send' |
24 | import { JobQueue } from '../../../lib/job-queue' | 28 | import { JobQueue } from '../../../lib/job-queue' |
25 | import { Redis } from '../../../lib/redis' | 29 | import { Redis } from '../../../lib/redis' |
26 | import { | 30 | import { |
27 | asyncMiddleware, | 31 | asyncMiddleware, |
28 | authenticate, | 32 | authenticate, |
33 | optionalAuthenticate, | ||
29 | paginationValidator, | 34 | paginationValidator, |
30 | setDefaultPagination, | 35 | setDefaultPagination, |
31 | setDefaultSort, | 36 | setDefaultSort, |
@@ -44,6 +49,9 @@ import { blacklistRouter } from './blacklist' | |||
44 | import { videoChannelRouter } from './channel' | 49 | import { videoChannelRouter } from './channel' |
45 | import { videoCommentRouter } from './comment' | 50 | import { videoCommentRouter } from './comment' |
46 | import { rateVideoRouter } from './rate' | 51 | import { rateVideoRouter } from './rate' |
52 | import { User } from '../../../../shared/models/users' | ||
53 | import { VideoFilter } from '../../../../shared/models/videos/video-query.type' | ||
54 | import { VideoSortField } from '../../../../client/src/app/shared/video/sort-field.type' | ||
47 | 55 | ||
48 | const videosRouter = express.Router() | 56 | const videosRouter = express.Router() |
49 | 57 | ||
@@ -81,6 +89,7 @@ videosRouter.get('/', | |||
81 | videosSortValidator, | 89 | videosSortValidator, |
82 | setDefaultSort, | 90 | setDefaultSort, |
83 | setDefaultPagination, | 91 | setDefaultPagination, |
92 | optionalAuthenticate, | ||
84 | asyncMiddleware(listVideos) | 93 | asyncMiddleware(listVideos) |
85 | ) | 94 | ) |
86 | videosRouter.get('/search', | 95 | videosRouter.get('/search', |
@@ -89,6 +98,7 @@ videosRouter.get('/search', | |||
89 | videosSortValidator, | 98 | videosSortValidator, |
90 | setDefaultSort, | 99 | setDefaultSort, |
91 | setDefaultPagination, | 100 | setDefaultPagination, |
101 | optionalAuthenticate, | ||
92 | asyncMiddleware(searchVideos) | 102 | asyncMiddleware(searchVideos) |
93 | ) | 103 | ) |
94 | videosRouter.put('/:id', | 104 | videosRouter.put('/:id', |
@@ -391,7 +401,13 @@ async function getVideoDescription (req: express.Request, res: express.Response) | |||
391 | } | 401 | } |
392 | 402 | ||
393 | async function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) { | 403 | async function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) { |
394 | const resultList = await VideoModel.listForApi(req.query.start, req.query.count, req.query.sort, req.query.filter) | 404 | const resultList = await VideoModel.listForApi( |
405 | req.query.start as number, | ||
406 | req.query.count as number, | ||
407 | req.query.sort as VideoSortField, | ||
408 | isNSFWHidden(res), | ||
409 | req.query.filter as VideoFilter | ||
410 | ) | ||
395 | 411 | ||
396 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 412 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
397 | } | 413 | } |
@@ -419,11 +435,21 @@ async function removeVideo (req: express.Request, res: express.Response) { | |||
419 | 435 | ||
420 | async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { | 436 | async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { |
421 | const resultList = await VideoModel.searchAndPopulateAccountAndServer( | 437 | const resultList = await VideoModel.searchAndPopulateAccountAndServer( |
422 | req.query.search, | 438 | req.query.search as string, |
423 | req.query.start, | 439 | req.query.start as number, |
424 | req.query.count, | 440 | req.query.count as number, |
425 | req.query.sort | 441 | req.query.sort as VideoSortField, |
442 | isNSFWHidden(res) | ||
426 | ) | 443 | ) |
427 | 444 | ||
428 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | 445 | return res.json(getFormattedObjects(resultList.data, resultList.total)) |
429 | } | 446 | } |
447 | |||
448 | function isNSFWHidden (res: express.Response) { | ||
449 | if (res.locals.oauth) { | ||
450 | const user: User = res.locals.oauth.token.User | ||
451 | if (user) return user.nsfwPolicy === 'do_not_list' | ||
452 | } | ||
453 | |||
454 | return CONFIG.INSTANCE.DEFAULT_NSFW_POLICY === 'do_not_list' | ||
455 | } | ||
diff --git a/server/controllers/feeds.ts b/server/controllers/feeds.ts index 3e384c48a..27ebecc40 100644 --- a/server/controllers/feeds.ts +++ b/server/controllers/feeds.ts | |||
@@ -6,6 +6,7 @@ import * as Feed from 'pfeed' | |||
6 | import { ResultList } from '../../shared/models' | 6 | import { ResultList } from '../../shared/models' |
7 | import { AccountModel } from '../models/account/account' | 7 | import { AccountModel } from '../models/account/account' |
8 | import { cacheRoute } from '../middlewares/cache' | 8 | import { cacheRoute } from '../middlewares/cache' |
9 | import { VideoSortField } from '../../client/src/app/shared/video/sort-field.type' | ||
9 | 10 | ||
10 | const feedsRouter = express.Router() | 11 | const feedsRouter = express.Router() |
11 | 12 | ||
@@ -31,20 +32,22 @@ async function generateFeed (req: express.Request, res: express.Response, next: | |||
31 | 32 | ||
32 | let resultList: ResultList<VideoModel> | 33 | let resultList: ResultList<VideoModel> |
33 | const account: AccountModel = res.locals.account | 34 | const account: AccountModel = res.locals.account |
35 | const hideNSFW = CONFIG.INSTANCE.DEFAULT_NSFW_POLICY === 'do_not_list' | ||
34 | 36 | ||
35 | if (account) { | 37 | if (account) { |
36 | resultList = await VideoModel.listAccountVideosForApi( | 38 | resultList = await VideoModel.listAccountVideosForApi( |
37 | account.id, | 39 | account.id, |
38 | start, | 40 | start, |
39 | FEEDS.COUNT, | 41 | FEEDS.COUNT, |
40 | req.query.sort, | 42 | req.query.sort as VideoSortField, |
41 | true | 43 | hideNSFW |
42 | ) | 44 | ) |
43 | } else { | 45 | } else { |
44 | resultList = await VideoModel.listForApi( | 46 | resultList = await VideoModel.listForApi( |
45 | start, | 47 | start, |
46 | FEEDS.COUNT, | 48 | FEEDS.COUNT, |
47 | req.query.sort, | 49 | req.query.sort as VideoSortField, |
50 | hideNSFW, | ||
48 | req.query.filter, | 51 | req.query.filter, |
49 | true | 52 | true |
50 | ) | 53 | ) |
diff --git a/server/helpers/custom-validators/users.ts b/server/helpers/custom-validators/users.ts index bbc7cc199..c0acb8218 100644 --- a/server/helpers/custom-validators/users.ts +++ b/server/helpers/custom-validators/users.ts | |||
@@ -1,9 +1,10 @@ | |||
1 | import 'express-validator' | 1 | import 'express-validator' |
2 | import * as validator from 'validator' | 2 | import * as validator from 'validator' |
3 | import { UserRole } from '../../../shared' | 3 | import { UserRole } from '../../../shared' |
4 | import { CONSTRAINTS_FIELDS } from '../../initializers' | 4 | import { CONSTRAINTS_FIELDS, NSFW_POLICY_TYPES } from '../../initializers' |
5 | 5 | ||
6 | import { exists, isFileValid } from './misc' | 6 | import { exists, isFileValid } from './misc' |
7 | import { values } from 'lodash' | ||
7 | 8 | ||
8 | const USERS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.USERS | 9 | const USERS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.USERS |
9 | 10 | ||
@@ -29,8 +30,9 @@ function isBoolean (value: any) { | |||
29 | return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value)) | 30 | return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value)) |
30 | } | 31 | } |
31 | 32 | ||
32 | function isUserDisplayNSFWValid (value: any) { | 33 | const nsfwPolicies = values(NSFW_POLICY_TYPES) |
33 | return isBoolean(value) | 34 | function isUserNSFWPolicyValid (value: any) { |
35 | return exists(value) && nsfwPolicies.indexOf(value) !== -1 | ||
34 | } | 36 | } |
35 | 37 | ||
36 | function isUserAutoPlayVideoValid (value: any) { | 38 | function isUserAutoPlayVideoValid (value: any) { |
@@ -56,7 +58,7 @@ export { | |||
56 | isUserRoleValid, | 58 | isUserRoleValid, |
57 | isUserVideoQuotaValid, | 59 | isUserVideoQuotaValid, |
58 | isUserUsernameValid, | 60 | isUserUsernameValid, |
59 | isUserDisplayNSFWValid, | 61 | isUserNSFWPolicyValid, |
60 | isUserAutoPlayVideoValid, | 62 | isUserAutoPlayVideoValid, |
61 | isUserDescriptionValid, | 63 | isUserDescriptionValid, |
62 | isAvatarFile | 64 | isAvatarFile |
diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts index 71f303963..739f623c6 100644 --- a/server/initializers/checker.ts +++ b/server/initializers/checker.ts | |||
@@ -5,12 +5,12 @@ import { ApplicationModel } from '../models/application/application' | |||
5 | import { OAuthClientModel } from '../models/oauth/oauth-client' | 5 | import { OAuthClientModel } from '../models/oauth/oauth-client' |
6 | 6 | ||
7 | // Some checks on configuration files | 7 | // Some checks on configuration files |
8 | // Return an error message, or null if everything is okay | ||
8 | function checkConfig () { | 9 | function checkConfig () { |
9 | if (config.has('webserver.host')) { | 10 | const defaultNSFWPolicy = config.get<string>('instance.default_nsfw_policy') |
10 | let errorMessage = '`host` config key was renamed to `hostname` but it seems you still have a `host` key in your configuration files!' | ||
11 | errorMessage += ' Please ensure to rename your `host` configuration to `hostname`.' | ||
12 | 11 | ||
13 | return errorMessage | 12 | if ([ 'do_not_list', 'blur', 'display' ].indexOf(defaultNSFWPolicy) === -1) { |
13 | return 'NSFW policy setting should be "do_not_list" or "blur" or "display" instead of ' + defaultNSFWPolicy | ||
14 | } | 14 | } |
15 | 15 | ||
16 | return null | 16 | return null |
@@ -28,7 +28,8 @@ function checkMissedConfig () { | |||
28 | 'log.level', | 28 | 'log.level', |
29 | 'user.video_quota', | 29 | 'user.video_quota', |
30 | 'cache.previews.size', 'admin.email', 'signup.enabled', 'signup.limit', 'transcoding.enabled', 'transcoding.threads', | 30 | 'cache.previews.size', 'admin.email', 'signup.enabled', 'signup.limit', 'transcoding.enabled', 'transcoding.threads', |
31 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route' | 31 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', |
32 | 'instance.default_nsfw_policy' | ||
32 | ] | 33 | ] |
33 | const miss: string[] = [] | 34 | const miss: string[] = [] |
34 | 35 | ||
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 5ee13389d..d1915586a 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -6,13 +6,14 @@ import { FollowState } from '../../shared/models/actors' | |||
6 | import { VideoPrivacy } from '../../shared/models/videos' | 6 | import { VideoPrivacy } from '../../shared/models/videos' |
7 | // Do not use barrels, remain constants as independent as possible | 7 | // Do not use barrels, remain constants as independent as possible |
8 | import { buildPath, isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' | 8 | import { buildPath, isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' |
9 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' | ||
9 | 10 | ||
10 | // Use a variable to reload the configuration if we need | 11 | // Use a variable to reload the configuration if we need |
11 | let config: IConfig = require('config') | 12 | let config: IConfig = require('config') |
12 | 13 | ||
13 | // --------------------------------------------------------------------------- | 14 | // --------------------------------------------------------------------------- |
14 | 15 | ||
15 | const LAST_MIGRATION_VERSION = 200 | 16 | const LAST_MIGRATION_VERSION = 205 |
16 | 17 | ||
17 | // --------------------------------------------------------------------------- | 18 | // --------------------------------------------------------------------------- |
18 | 19 | ||
@@ -167,6 +168,7 @@ const CONFIG = { | |||
167 | get DESCRIPTION () { return config.get<string>('instance.description') }, | 168 | get DESCRIPTION () { return config.get<string>('instance.description') }, |
168 | get TERMS () { return config.get<string>('instance.terms') }, | 169 | get TERMS () { return config.get<string>('instance.terms') }, |
169 | get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') }, | 170 | get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') }, |
171 | get DEFAULT_NSFW_POLICY () { return config.get<NSFWPolicyType>('instance.default_nsfw_policy') }, | ||
170 | CUSTOMIZATIONS: { | 172 | CUSTOMIZATIONS: { |
171 | get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') }, | 173 | get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') }, |
172 | get CSS () { return config.get<string>('instance.customizations.css') } | 174 | get CSS () { return config.get<string>('instance.customizations.css') } |
@@ -378,6 +380,12 @@ const BCRYPT_SALT_SIZE = 10 | |||
378 | 380 | ||
379 | const USER_PASSWORD_RESET_LIFETIME = 60000 * 5 // 5 minutes | 381 | const USER_PASSWORD_RESET_LIFETIME = 60000 * 5 // 5 minutes |
380 | 382 | ||
383 | const NSFW_POLICY_TYPES: { [ id: string]: NSFWPolicyType } = { | ||
384 | DO_NOT_LIST: 'do_not_list', | ||
385 | BLUR: 'blur', | ||
386 | DISPLAY: 'display' | ||
387 | } | ||
388 | |||
381 | // --------------------------------------------------------------------------- | 389 | // --------------------------------------------------------------------------- |
382 | 390 | ||
383 | // Express static paths (router) | 391 | // Express static paths (router) |
@@ -474,6 +482,7 @@ export { | |||
474 | PRIVATE_RSA_KEY_SIZE, | 482 | PRIVATE_RSA_KEY_SIZE, |
475 | SORTABLE_COLUMNS, | 483 | SORTABLE_COLUMNS, |
476 | FEEDS, | 484 | FEEDS, |
485 | NSFW_POLICY_TYPES, | ||
477 | STATIC_MAX_AGE, | 486 | STATIC_MAX_AGE, |
478 | STATIC_PATHS, | 487 | STATIC_PATHS, |
479 | ACTIVITY_PUB, | 488 | ACTIVITY_PUB, |
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index 09c6d5473..b0084b368 100644 --- a/server/initializers/installer.ts +++ b/server/initializers/installer.ts | |||
@@ -120,6 +120,7 @@ async function createOAuthAdminIfNotExist () { | |||
120 | email, | 120 | email, |
121 | password, | 121 | password, |
122 | role, | 122 | role, |
123 | nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY, | ||
123 | videoQuota: -1 | 124 | videoQuota: -1 |
124 | } | 125 | } |
125 | const user = new UserModel(userData) | 126 | const user = new UserModel(userData) |
diff --git a/server/initializers/migrations/0205-user-nsfw-policy.ts b/server/initializers/migrations/0205-user-nsfw-policy.ts new file mode 100644 index 000000000..d0f6e8962 --- /dev/null +++ b/server/initializers/migrations/0205-user-nsfw-policy.ts | |||
@@ -0,0 +1,46 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | async function up (utils: { | ||
4 | transaction: Sequelize.Transaction, | ||
5 | queryInterface: Sequelize.QueryInterface, | ||
6 | sequelize: Sequelize.Sequelize | ||
7 | }): Promise<void> { | ||
8 | |||
9 | { | ||
10 | const data = { | ||
11 | type: Sequelize.ENUM('do_not_list', 'blur', 'display'), | ||
12 | allowNull: true, | ||
13 | defaultValue: null | ||
14 | } | ||
15 | await utils.queryInterface.addColumn('user', 'nsfwPolicy', data) | ||
16 | } | ||
17 | |||
18 | { | ||
19 | const query = 'UPDATE "user" SET "nsfwPolicy" = \'do_not_list\'' | ||
20 | await utils.sequelize.query(query) | ||
21 | } | ||
22 | |||
23 | { | ||
24 | const query = 'UPDATE "user" SET "nsfwPolicy" = \'display\' WHERE "displayNSFW" = true' | ||
25 | await utils.sequelize.query(query) | ||
26 | } | ||
27 | |||
28 | { | ||
29 | const query = 'ALTER TABLE "user" ALTER COLUMN "nsfwPolicy" SET NOT NULL' | ||
30 | await utils.sequelize.query(query) | ||
31 | } | ||
32 | |||
33 | { | ||
34 | await utils.queryInterface.removeColumn('user', 'displayNSFW') | ||
35 | } | ||
36 | |||
37 | } | ||
38 | |||
39 | function down (options) { | ||
40 | throw new Error('Not implemented.') | ||
41 | } | ||
42 | |||
43 | export { | ||
44 | up, | ||
45 | down | ||
46 | } | ||
diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts index 41a3fb718..a6f28dd5b 100644 --- a/server/middlewares/oauth.ts +++ b/server/middlewares/oauth.ts | |||
@@ -2,6 +2,7 @@ import * as express from 'express' | |||
2 | import * as OAuthServer from 'express-oauth-server' | 2 | import * as OAuthServer from 'express-oauth-server' |
3 | import 'express-validator' | 3 | import 'express-validator' |
4 | import { OAUTH_LIFETIME } from '../initializers' | 4 | import { OAUTH_LIFETIME } from '../initializers' |
5 | import { logger } from '../helpers/logger' | ||
5 | 6 | ||
6 | const oAuthServer = new OAuthServer({ | 7 | const oAuthServer = new OAuthServer({ |
7 | useErrorHandler: true, | 8 | useErrorHandler: true, |
@@ -13,6 +14,8 @@ const oAuthServer = new OAuthServer({ | |||
13 | function authenticate (req: express.Request, res: express.Response, next: express.NextFunction) { | 14 | function authenticate (req: express.Request, res: express.Response, next: express.NextFunction) { |
14 | oAuthServer.authenticate()(req, res, err => { | 15 | oAuthServer.authenticate()(req, res, err => { |
15 | if (err) { | 16 | if (err) { |
17 | logger.warn('Cannot authenticate.', { err }) | ||
18 | |||
16 | return res.status(err.status) | 19 | return res.status(err.status) |
17 | .json({ | 20 | .json({ |
18 | error: 'Token is invalid.', | 21 | error: 'Token is invalid.', |
@@ -25,6 +28,12 @@ function authenticate (req: express.Request, res: express.Response, next: expres | |||
25 | }) | 28 | }) |
26 | } | 29 | } |
27 | 30 | ||
31 | function optionalAuthenticate (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
32 | if (req.header('authorization')) return authenticate(req, res, next) | ||
33 | |||
34 | return next() | ||
35 | } | ||
36 | |||
28 | function token (req: express.Request, res: express.Response, next: express.NextFunction) { | 37 | function token (req: express.Request, res: express.Response, next: express.NextFunction) { |
29 | return oAuthServer.token()(req, res, err => { | 38 | return oAuthServer.token()(req, res, err => { |
30 | if (err) { | 39 | if (err) { |
@@ -44,5 +53,6 @@ function token (req: express.Request, res: express.Response, next: express.NextF | |||
44 | 53 | ||
45 | export { | 54 | export { |
46 | authenticate, | 55 | authenticate, |
56 | optionalAuthenticate, | ||
47 | token | 57 | token |
48 | } | 58 | } |
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index ee6f6efa4..f58c0676c 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { body } from 'express-validator/check' | 2 | import { body } from 'express-validator/check' |
3 | import { isUserVideoQuotaValid } from '../../helpers/custom-validators/users' | 3 | import { isUserNSFWPolicyValid, isUserVideoQuotaValid } from '../../helpers/custom-validators/users' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../helpers/logger' |
5 | import { areValidationErrors } from './utils' | 5 | import { areValidationErrors } from './utils' |
6 | 6 | ||
@@ -9,6 +9,7 @@ const customConfigUpdateValidator = [ | |||
9 | body('instance.description').exists().withMessage('Should have a valid instance description'), | 9 | body('instance.description').exists().withMessage('Should have a valid instance description'), |
10 | body('instance.terms').exists().withMessage('Should have a valid instance terms'), | 10 | body('instance.terms').exists().withMessage('Should have a valid instance terms'), |
11 | body('instance.defaultClientRoute').exists().withMessage('Should have a valid instance default client route'), | 11 | body('instance.defaultClientRoute').exists().withMessage('Should have a valid instance default client route'), |
12 | body('instance.defaultNSFWPolicy').custom(isUserNSFWPolicyValid).withMessage('Should have a valid NSFW policy'), | ||
12 | body('instance.customizations.css').exists().withMessage('Should have a valid instance CSS customization'), | 13 | body('instance.customizations.css').exists().withMessage('Should have a valid instance CSS customization'), |
13 | body('instance.customizations.javascript').exists().withMessage('Should have a valid instance JavaScript customization'), | 14 | body('instance.customizations.javascript').exists().withMessage('Should have a valid instance JavaScript customization'), |
14 | body('cache.previews.size').isInt().withMessage('Should have a valid previews size'), | 15 | body('cache.previews.size').isInt().withMessage('Should have a valid previews size'), |
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 6ea3d0b6c..5dd8caa3f 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -8,7 +8,7 @@ import { | |||
8 | isAvatarFile, | 8 | isAvatarFile, |
9 | isUserAutoPlayVideoValid, | 9 | isUserAutoPlayVideoValid, |
10 | isUserDescriptionValid, | 10 | isUserDescriptionValid, |
11 | isUserDisplayNSFWValid, | 11 | isUserNSFWPolicyValid, |
12 | isUserPasswordValid, | 12 | isUserPasswordValid, |
13 | isUserRoleValid, | 13 | isUserRoleValid, |
14 | isUserUsernameValid, | 14 | isUserUsernameValid, |
@@ -101,7 +101,7 @@ const usersUpdateMeValidator = [ | |||
101 | body('description').optional().custom(isUserDescriptionValid).withMessage('Should have a valid description'), | 101 | body('description').optional().custom(isUserDescriptionValid).withMessage('Should have a valid description'), |
102 | body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'), | 102 | body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'), |
103 | body('email').optional().isEmail().withMessage('Should have a valid email attribute'), | 103 | body('email').optional().isEmail().withMessage('Should have a valid email attribute'), |
104 | body('displayNSFW').optional().custom(isUserDisplayNSFWValid).withMessage('Should have a valid display Not Safe For Work attribute'), | 104 | body('nsfwPolicy').optional().custom(isUserNSFWPolicyValid).withMessage('Should have a valid display Not Safe For Work policy'), |
105 | body('autoPlayVideo').optional().custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'), | 105 | body('autoPlayVideo').optional().custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'), |
106 | 106 | ||
107 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 107 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index 8afd246b2..56af2f30a 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -21,7 +21,7 @@ import { hasUserRight, USER_ROLE_LABELS, UserRight } from '../../../shared' | |||
21 | import { User, UserRole } from '../../../shared/models/users' | 21 | import { User, UserRole } from '../../../shared/models/users' |
22 | import { | 22 | import { |
23 | isUserAutoPlayVideoValid, | 23 | isUserAutoPlayVideoValid, |
24 | isUserDisplayNSFWValid, | 24 | isUserNSFWPolicyValid, |
25 | isUserPasswordValid, | 25 | isUserPasswordValid, |
26 | isUserRoleValid, | 26 | isUserRoleValid, |
27 | isUserUsernameValid, | 27 | isUserUsernameValid, |
@@ -32,6 +32,9 @@ import { OAuthTokenModel } from '../oauth/oauth-token' | |||
32 | import { getSort, throwIfNotValid } from '../utils' | 32 | import { getSort, throwIfNotValid } from '../utils' |
33 | import { VideoChannelModel } from '../video/video-channel' | 33 | import { VideoChannelModel } from '../video/video-channel' |
34 | import { AccountModel } from './account' | 34 | import { AccountModel } from './account' |
35 | import { NSFWPolicyType } from '../../../shared/models/videos/nsfw-policy.type' | ||
36 | import { values } from 'lodash' | ||
37 | import { NSFW_POLICY_TYPES } from '../../initializers' | ||
35 | 38 | ||
36 | @DefaultScope({ | 39 | @DefaultScope({ |
37 | include: [ | 40 | include: [ |
@@ -83,10 +86,9 @@ export class UserModel extends Model<UserModel> { | |||
83 | email: string | 86 | email: string |
84 | 87 | ||
85 | @AllowNull(false) | 88 | @AllowNull(false) |
86 | @Default(false) | 89 | @Is('UserNSFWPolicy', value => throwIfNotValid(value, isUserNSFWPolicyValid, 'NSFW policy')) |
87 | @Is('UserDisplayNSFW', value => throwIfNotValid(value, isUserDisplayNSFWValid, 'display NSFW boolean')) | 90 | @Column(DataType.ENUM(values(NSFW_POLICY_TYPES))) |
88 | @Column | 91 | nsfwPolicy: NSFWPolicyType |
89 | displayNSFW: boolean | ||
90 | 92 | ||
91 | @AllowNull(false) | 93 | @AllowNull(false) |
92 | @Default(true) | 94 | @Default(true) |
@@ -265,7 +267,7 @@ export class UserModel extends Model<UserModel> { | |||
265 | id: this.id, | 267 | id: this.id, |
266 | username: this.username, | 268 | username: this.username, |
267 | email: this.email, | 269 | email: this.email, |
268 | displayNSFW: this.displayNSFW, | 270 | nsfwPolicy: this.nsfwPolicy, |
269 | autoPlayVideo: this.autoPlayVideo, | 271 | autoPlayVideo: this.autoPlayVideo, |
270 | role: this.role, | 272 | role: this.role, |
271 | roleLabel: USER_ROLE_LABELS[ this.role ], | 273 | roleLabel: USER_ROLE_LABELS[ this.role ], |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index a7923b477..aef75d206 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -95,7 +95,7 @@ enum ScopeNames { | |||
95 | } | 95 | } |
96 | 96 | ||
97 | @Scopes({ | 97 | @Scopes({ |
98 | [ScopeNames.AVAILABLE_FOR_LIST]: (actorId: number, filter?: VideoFilter, withFiles?: boolean) => { | 98 | [ScopeNames.AVAILABLE_FOR_LIST]: (actorId: number, hideNSFW: boolean, filter?: VideoFilter, withFiles?: boolean) => { |
99 | const query: IFindOptions<VideoModel> = { | 99 | const query: IFindOptions<VideoModel> = { |
100 | where: { | 100 | where: { |
101 | id: { | 101 | id: { |
@@ -161,6 +161,11 @@ enum ScopeNames { | |||
161 | }) | 161 | }) |
162 | } | 162 | } |
163 | 163 | ||
164 | // Hide nsfw videos? | ||
165 | if (hideNSFW === true) { | ||
166 | query.where['nsfw'] = false | ||
167 | } | ||
168 | |||
164 | return query | 169 | return query |
165 | }, | 170 | }, |
166 | [ScopeNames.WITH_ACCOUNT_DETAILS]: { | 171 | [ScopeNames.WITH_ACCOUNT_DETAILS]: { |
@@ -640,7 +645,7 @@ export class VideoModel extends Model<VideoModel> { | |||
640 | }) | 645 | }) |
641 | } | 646 | } |
642 | 647 | ||
643 | static listAccountVideosForApi (accountId: number, start: number, count: number, sort: string, withFiles = false) { | 648 | static listAccountVideosForApi (accountId: number, start: number, count: number, sort: string, hideNSFW: boolean, withFiles = false) { |
644 | const query: IFindOptions<VideoModel> = { | 649 | const query: IFindOptions<VideoModel> = { |
645 | offset: start, | 650 | offset: start, |
646 | limit: count, | 651 | limit: count, |
@@ -669,6 +674,12 @@ export class VideoModel extends Model<VideoModel> { | |||
669 | }) | 674 | }) |
670 | } | 675 | } |
671 | 676 | ||
677 | if (hideNSFW === true) { | ||
678 | query.where = { | ||
679 | nsfw: false | ||
680 | } | ||
681 | } | ||
682 | |||
672 | return VideoModel.findAndCountAll(query).then(({ rows, count }) => { | 683 | return VideoModel.findAndCountAll(query).then(({ rows, count }) => { |
673 | return { | 684 | return { |
674 | data: rows, | 685 | data: rows, |
@@ -677,7 +688,7 @@ export class VideoModel extends Model<VideoModel> { | |||
677 | }) | 688 | }) |
678 | } | 689 | } |
679 | 690 | ||
680 | static async listForApi (start: number, count: number, sort: string, filter?: VideoFilter, withFiles = false) { | 691 | static async listForApi (start: number, count: number, sort: string, hideNSFW: boolean, filter?: VideoFilter, withFiles = false) { |
681 | const query = { | 692 | const query = { |
682 | offset: start, | 693 | offset: start, |
683 | limit: count, | 694 | limit: count, |
@@ -685,8 +696,7 @@ export class VideoModel extends Model<VideoModel> { | |||
685 | } | 696 | } |
686 | 697 | ||
687 | const serverActor = await getServerActor() | 698 | const serverActor = await getServerActor() |
688 | 699 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST, serverActor.id, hideNSFW, filter, withFiles ] }) | |
689 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST, serverActor.id, filter, withFiles ] }) | ||
690 | .findAndCountAll(query) | 700 | .findAndCountAll(query) |
691 | .then(({ rows, count }) => { | 701 | .then(({ rows, count }) => { |
692 | return { | 702 | return { |
@@ -696,7 +706,7 @@ export class VideoModel extends Model<VideoModel> { | |||
696 | }) | 706 | }) |
697 | } | 707 | } |
698 | 708 | ||
699 | static async searchAndPopulateAccountAndServer (value: string, start: number, count: number, sort: string) { | 709 | static async searchAndPopulateAccountAndServer (value: string, start: number, count: number, sort: string, hideNSFW: boolean) { |
700 | const query: IFindOptions<VideoModel> = { | 710 | const query: IFindOptions<VideoModel> = { |
701 | offset: start, | 711 | offset: start, |
702 | limit: count, | 712 | limit: count, |
@@ -724,7 +734,7 @@ export class VideoModel extends Model<VideoModel> { | |||
724 | 734 | ||
725 | const serverActor = await getServerActor() | 735 | const serverActor = await getServerActor() |
726 | 736 | ||
727 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST, serverActor.id ] }) | 737 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST, serverActor.id, hideNSFW ] }) |
728 | .findAndCountAll(query) | 738 | .findAndCountAll(query) |
729 | .then(({ rows, count }) => { | 739 | .then(({ rows, count }) => { |
730 | return { | 740 | return { |
@@ -874,6 +884,13 @@ export class VideoModel extends Model<VideoModel> { | |||
874 | return languageLabel | 884 | return languageLabel |
875 | } | 885 | } |
876 | 886 | ||
887 | private static getPrivacyLabel (id: number) { | ||
888 | let privacyLabel = VIDEO_PRIVACIES[id] | ||
889 | if (!privacyLabel) privacyLabel = 'Unknown' | ||
890 | |||
891 | return privacyLabel | ||
892 | } | ||
893 | |||
877 | getOriginalFile () { | 894 | getOriginalFile () { |
878 | if (Array.isArray(this.VideoFiles) === false) return undefined | 895 | if (Array.isArray(this.VideoFiles) === false) return undefined |
879 | 896 | ||
@@ -927,8 +944,11 @@ export class VideoModel extends Model<VideoModel> { | |||
927 | return join(CONFIG.STORAGE.VIDEOS_DIR, this.getVideoFilename(videoFile)) | 944 | return join(CONFIG.STORAGE.VIDEOS_DIR, this.getVideoFilename(videoFile)) |
928 | } | 945 | } |
929 | 946 | ||
930 | createTorrentAndSetInfoHash = async function (videoFile: VideoFileModel) { | 947 | async createTorrentAndSetInfoHash (videoFile: VideoFileModel) { |
931 | const options = { | 948 | const options = { |
949 | // Keep the extname, it's used by the client to stream the file inside a web browser | ||
950 | name: `${this.name} ${videoFile.resolution}p${videoFile.extname}`, | ||
951 | createdBy: 'PeerTube', | ||
932 | announceList: [ | 952 | announceList: [ |
933 | [ CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT + '/tracker/socket' ], | 953 | [ CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT + '/tracker/socket' ], |
934 | [ CONFIG.WEBSERVER.URL + '/tracker/announce' ] | 954 | [ CONFIG.WEBSERVER.URL + '/tracker/announce' ] |
@@ -980,6 +1000,10 @@ export class VideoModel extends Model<VideoModel> { | |||
980 | id: this.language, | 1000 | id: this.language, |
981 | label: VideoModel.getLanguageLabel(this.language) | 1001 | label: VideoModel.getLanguageLabel(this.language) |
982 | }, | 1002 | }, |
1003 | privacy: { | ||
1004 | id: this.privacy, | ||
1005 | label: VideoModel.getPrivacyLabel(this.privacy) | ||
1006 | }, | ||
983 | nsfw: this.nsfw, | 1007 | nsfw: this.nsfw, |
984 | description: this.getTruncatedDescription(), | 1008 | description: this.getTruncatedDescription(), |
985 | isLocal: this.isOwned(), | 1009 | isLocal: this.isOwned(), |
@@ -1006,15 +1030,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1006 | toFormattedDetailsJSON (): VideoDetails { | 1030 | toFormattedDetailsJSON (): VideoDetails { |
1007 | const formattedJson = this.toFormattedJSON() | 1031 | const formattedJson = this.toFormattedJSON() |
1008 | 1032 | ||
1009 | // Maybe our server is not up to date and there are new privacy settings since our version | ||
1010 | let privacyLabel = VIDEO_PRIVACIES[this.privacy] | ||
1011 | if (!privacyLabel) privacyLabel = 'Unknown' | ||
1012 | |||
1013 | const detailsJson = { | 1033 | const detailsJson = { |
1014 | privacy: { | ||
1015 | id: this.privacy, | ||
1016 | label: privacyLabel | ||
1017 | }, | ||
1018 | support: this.support, | 1034 | support: this.support, |
1019 | descriptionPath: this.getDescriptionPath(), | 1035 | descriptionPath: this.getDescriptionPath(), |
1020 | channel: this.VideoChannel.toFormattedJSON(), | 1036 | channel: this.VideoChannel.toFormattedJSON(), |
@@ -1227,7 +1243,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1227 | return peertubeTruncate(this.description, maxLength) | 1243 | return peertubeTruncate(this.description, maxLength) |
1228 | } | 1244 | } |
1229 | 1245 | ||
1230 | optimizeOriginalVideofile = async function () { | 1246 | async optimizeOriginalVideofile () { |
1231 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR | 1247 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR |
1232 | const newExtname = '.mp4' | 1248 | const newExtname = '.mp4' |
1233 | const inputVideoFile = this.getOriginalFile() | 1249 | const inputVideoFile = this.getOriginalFile() |
@@ -1264,7 +1280,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1264 | } | 1280 | } |
1265 | } | 1281 | } |
1266 | 1282 | ||
1267 | transcodeOriginalVideofile = async function (resolution: VideoResolution, isPortraitMode: boolean) { | 1283 | async transcodeOriginalVideofile (resolution: VideoResolution, isPortraitMode: boolean) { |
1268 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR | 1284 | const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR |
1269 | const extname = '.mp4' | 1285 | const extname = '.mp4' |
1270 | 1286 | ||
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index 3fe517fad..58b780f38 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -6,7 +6,7 @@ import { CustomConfig } from '../../../../shared/models/server/custom-config.mod | |||
6 | 6 | ||
7 | import { | 7 | import { |
8 | createUser, flushTests, killallServers, makeDeleteRequest, makeGetRequest, makePutBodyRequest, runServer, ServerInfo, | 8 | createUser, flushTests, killallServers, makeDeleteRequest, makeGetRequest, makePutBodyRequest, runServer, ServerInfo, |
9 | setAccessTokensToServers, userLogin | 9 | setAccessTokensToServers, userLogin, immutableAssign |
10 | } from '../../utils' | 10 | } from '../../utils' |
11 | 11 | ||
12 | describe('Test config API validators', function () { | 12 | describe('Test config API validators', function () { |
@@ -20,6 +20,7 @@ describe('Test config API validators', function () { | |||
20 | description: 'my super description', | 20 | description: 'my super description', |
21 | terms: 'my super terms', | 21 | terms: 'my super terms', |
22 | defaultClientRoute: '/videos/recently-added', | 22 | defaultClientRoute: '/videos/recently-added', |
23 | defaultNSFWPolicy: 'blur', | ||
23 | customizations: { | 24 | customizations: { |
24 | javascript: 'alert("coucou")', | 25 | javascript: 'alert("coucou")', |
25 | css: 'body { background-color: red; }' | 26 | css: 'body { background-color: red; }' |
@@ -122,6 +123,22 @@ describe('Test config API validators', function () { | |||
122 | }) | 123 | }) |
123 | }) | 124 | }) |
124 | 125 | ||
126 | it('Should fail with a bad default NSFW policy', async function () { | ||
127 | const newUpdateParams = immutableAssign(updateParams, { | ||
128 | instance: { | ||
129 | defaultNSFWPolicy: 'hello' | ||
130 | } | ||
131 | }) | ||
132 | |||
133 | await makePutBodyRequest({ | ||
134 | url: server.url, | ||
135 | path, | ||
136 | fields: newUpdateParams, | ||
137 | token: server.accessToken, | ||
138 | statusCodeExpected: 400 | ||
139 | }) | ||
140 | }) | ||
141 | |||
125 | it('Should success with the correct parameters', async function () { | 142 | it('Should success with the correct parameters', async function () { |
126 | await makePutBodyRequest({ | 143 | await makePutBodyRequest({ |
127 | url: server.url, | 144 | url: server.url, |
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts index a3e415b94..e8a6ffd19 100644 --- a/server/tests/api/check-params/users.ts +++ b/server/tests/api/check-params/users.ts | |||
@@ -231,9 +231,9 @@ describe('Test users API validators', function () { | |||
231 | await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields }) | 231 | await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields }) |
232 | }) | 232 | }) |
233 | 233 | ||
234 | it('Should fail with an invalid display NSFW attribute', async function () { | 234 | it('Should fail with an invalid NSFW policy attribute', async function () { |
235 | const fields = { | 235 | const fields = { |
236 | displayNSFW: -1 | 236 | nsfwPolicy: 'hello' |
237 | } | 237 | } |
238 | 238 | ||
239 | await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields }) | 239 | await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields }) |
@@ -266,7 +266,7 @@ describe('Test users API validators', function () { | |||
266 | it('Should succeed with the correct params', async function () { | 266 | it('Should succeed with the correct params', async function () { |
267 | const fields = { | 267 | const fields = { |
268 | password: 'my super password', | 268 | password: 'my super password', |
269 | displayNSFW: true, | 269 | nsfwPolicy: 'blur', |
270 | autoPlayVideo: false, | 270 | autoPlayVideo: false, |
271 | email: 'super_email@example.com' | 271 | email: 'super_email@example.com' |
272 | } | 272 | } |
diff --git a/server/tests/api/index-fast.ts b/server/tests/api/index-fast.ts index aa063b97a..2454ec2f9 100644 --- a/server/tests/api/index-fast.ts +++ b/server/tests/api/index-fast.ts | |||
@@ -7,6 +7,7 @@ import './videos/video-abuse' | |||
7 | import './videos/video-blacklist' | 7 | import './videos/video-blacklist' |
8 | import './videos/video-blacklist-management' | 8 | import './videos/video-blacklist-management' |
9 | import './videos/video-description' | 9 | import './videos/video-description' |
10 | import './videos/video-nsfw' | ||
10 | import './videos/video-privacy' | 11 | import './videos/video-privacy' |
11 | import './videos/services' | 12 | import './videos/services' |
12 | import './server/email' | 13 | import './server/email' |
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index e17588142..3f1b1532c 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -59,6 +59,7 @@ describe('Test config', function () { | |||
59 | expect(data.instance.description).to.equal('Welcome to this PeerTube instance!') | 59 | expect(data.instance.description).to.equal('Welcome to this PeerTube instance!') |
60 | expect(data.instance.terms).to.equal('No terms for now.') | 60 | expect(data.instance.terms).to.equal('No terms for now.') |
61 | expect(data.instance.defaultClientRoute).to.equal('/videos/trending') | 61 | expect(data.instance.defaultClientRoute).to.equal('/videos/trending') |
62 | expect(data.instance.defaultNSFWPolicy).to.equal('display') | ||
62 | expect(data.instance.customizations.css).to.be.empty | 63 | expect(data.instance.customizations.css).to.be.empty |
63 | expect(data.instance.customizations.javascript).to.be.empty | 64 | expect(data.instance.customizations.javascript).to.be.empty |
64 | expect(data.cache.previews.size).to.equal(1) | 65 | expect(data.cache.previews.size).to.equal(1) |
@@ -83,6 +84,7 @@ describe('Test config', function () { | |||
83 | description: 'my super description', | 84 | description: 'my super description', |
84 | terms: 'my super terms', | 85 | terms: 'my super terms', |
85 | defaultClientRoute: '/videos/recently-added', | 86 | defaultClientRoute: '/videos/recently-added', |
87 | defaultNSFWPolicy: 'blur' as 'blur', | ||
86 | customizations: { | 88 | customizations: { |
87 | javascript: 'alert("coucou")', | 89 | javascript: 'alert("coucou")', |
88 | css: 'body { background-color: red; }' | 90 | css: 'body { background-color: red; }' |
@@ -125,6 +127,7 @@ describe('Test config', function () { | |||
125 | expect(data.instance.description).to.equal('my super description') | 127 | expect(data.instance.description).to.equal('my super description') |
126 | expect(data.instance.terms).to.equal('my super terms') | 128 | expect(data.instance.terms).to.equal('my super terms') |
127 | expect(data.instance.defaultClientRoute).to.equal('/videos/recently-added') | 129 | expect(data.instance.defaultClientRoute).to.equal('/videos/recently-added') |
130 | expect(data.instance.defaultNSFWPolicy).to.equal('blur') | ||
128 | expect(data.instance.customizations.javascript).to.equal('alert("coucou")') | 131 | expect(data.instance.customizations.javascript).to.equal('alert("coucou")') |
129 | expect(data.instance.customizations.css).to.equal('body { background-color: red; }') | 132 | expect(data.instance.customizations.css).to.equal('body { background-color: red; }') |
130 | expect(data.cache.previews.size).to.equal(2) | 133 | expect(data.cache.previews.size).to.equal(2) |
@@ -156,6 +159,7 @@ describe('Test config', function () { | |||
156 | expect(data.instance.description).to.equal('my super description') | 159 | expect(data.instance.description).to.equal('my super description') |
157 | expect(data.instance.terms).to.equal('my super terms') | 160 | expect(data.instance.terms).to.equal('my super terms') |
158 | expect(data.instance.defaultClientRoute).to.equal('/videos/recently-added') | 161 | expect(data.instance.defaultClientRoute).to.equal('/videos/recently-added') |
162 | expect(data.instance.defaultNSFWPolicy).to.equal('blur') | ||
159 | expect(data.instance.customizations.javascript).to.equal('alert("coucou")') | 163 | expect(data.instance.customizations.javascript).to.equal('alert("coucou")') |
160 | expect(data.instance.customizations.css).to.equal('body { background-color: red; }') | 164 | expect(data.instance.customizations.css).to.equal('body { background-color: red; }') |
161 | expect(data.cache.previews.size).to.equal(2) | 165 | expect(data.cache.previews.size).to.equal(2) |
@@ -198,6 +202,7 @@ describe('Test config', function () { | |||
198 | expect(data.instance.description).to.equal('Welcome to this PeerTube instance!') | 202 | expect(data.instance.description).to.equal('Welcome to this PeerTube instance!') |
199 | expect(data.instance.terms).to.equal('No terms for now.') | 203 | expect(data.instance.terms).to.equal('No terms for now.') |
200 | expect(data.instance.defaultClientRoute).to.equal('/videos/trending') | 204 | expect(data.instance.defaultClientRoute).to.equal('/videos/trending') |
205 | expect(data.instance.defaultNSFWPolicy).to.equal('display') | ||
201 | expect(data.instance.customizations.css).to.be.empty | 206 | expect(data.instance.customizations.css).to.be.empty |
202 | expect(data.instance.customizations.javascript).to.be.empty | 207 | expect(data.instance.customizations.javascript).to.be.empty |
203 | expect(data.cache.previews.size).to.equal(1) | 208 | expect(data.cache.previews.size).to.equal(1) |
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts index b6ab4f660..1192ef9e4 100644 --- a/server/tests/api/users/users.ts +++ b/server/tests/api/users/users.ts | |||
@@ -168,7 +168,7 @@ describe('Test users', function () { | |||
168 | 168 | ||
169 | expect(user.username).to.equal('user_1') | 169 | expect(user.username).to.equal('user_1') |
170 | expect(user.email).to.equal('user_1@example.com') | 170 | expect(user.email).to.equal('user_1@example.com') |
171 | expect(user.displayNSFW).to.be.false | 171 | expect(user.nsfwPolicy).to.equal('display') |
172 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) | 172 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) |
173 | expect(user.roleLabel).to.equal('User') | 173 | expect(user.roleLabel).to.equal('User') |
174 | expect(user.id).to.be.a('number') | 174 | expect(user.id).to.be.a('number') |
@@ -215,12 +215,12 @@ describe('Test users', function () { | |||
215 | const user = users[ 0 ] | 215 | const user = users[ 0 ] |
216 | expect(user.username).to.equal('user_1') | 216 | expect(user.username).to.equal('user_1') |
217 | expect(user.email).to.equal('user_1@example.com') | 217 | expect(user.email).to.equal('user_1@example.com') |
218 | expect(user.displayNSFW).to.be.false | 218 | expect(user.nsfwPolicy).to.equal('display') |
219 | 219 | ||
220 | const rootUser = users[ 1 ] | 220 | const rootUser = users[ 1 ] |
221 | expect(rootUser.username).to.equal('root') | 221 | expect(rootUser.username).to.equal('root') |
222 | expect(rootUser.email).to.equal('admin1@example.com') | 222 | expect(rootUser.email).to.equal('admin1@example.com') |
223 | expect(rootUser.displayNSFW).to.be.false | 223 | expect(user.nsfwPolicy).to.equal('display') |
224 | 224 | ||
225 | userId = user.id | 225 | userId = user.id |
226 | }) | 226 | }) |
@@ -239,7 +239,7 @@ describe('Test users', function () { | |||
239 | expect(user.username).to.equal('root') | 239 | expect(user.username).to.equal('root') |
240 | expect(user.email).to.equal('admin1@example.com') | 240 | expect(user.email).to.equal('admin1@example.com') |
241 | expect(user.roleLabel).to.equal('Administrator') | 241 | expect(user.roleLabel).to.equal('Administrator') |
242 | expect(user.displayNSFW).to.be.false | 242 | expect(user.nsfwPolicy).to.equal('display') |
243 | }) | 243 | }) |
244 | 244 | ||
245 | it('Should list only the first user by username desc', async function () { | 245 | it('Should list only the first user by username desc', async function () { |
@@ -254,7 +254,7 @@ describe('Test users', function () { | |||
254 | const user = users[ 0 ] | 254 | const user = users[ 0 ] |
255 | expect(user.username).to.equal('user_1') | 255 | expect(user.username).to.equal('user_1') |
256 | expect(user.email).to.equal('user_1@example.com') | 256 | expect(user.email).to.equal('user_1@example.com') |
257 | expect(user.displayNSFW).to.be.false | 257 | expect(user.nsfwPolicy).to.equal('display') |
258 | }) | 258 | }) |
259 | 259 | ||
260 | it('Should list only the second user by createdAt desc', async function () { | 260 | it('Should list only the second user by createdAt desc', async function () { |
@@ -269,7 +269,7 @@ describe('Test users', function () { | |||
269 | const user = users[ 0 ] | 269 | const user = users[ 0 ] |
270 | expect(user.username).to.equal('user_1') | 270 | expect(user.username).to.equal('user_1') |
271 | expect(user.email).to.equal('user_1@example.com') | 271 | expect(user.email).to.equal('user_1@example.com') |
272 | expect(user.displayNSFW).to.be.false | 272 | expect(user.nsfwPolicy).to.equal('display') |
273 | }) | 273 | }) |
274 | 274 | ||
275 | it('Should list all the users by createdAt asc', async function () { | 275 | it('Should list all the users by createdAt asc', async function () { |
@@ -283,11 +283,11 @@ describe('Test users', function () { | |||
283 | 283 | ||
284 | expect(users[ 0 ].username).to.equal('root') | 284 | expect(users[ 0 ].username).to.equal('root') |
285 | expect(users[ 0 ].email).to.equal('admin1@example.com') | 285 | expect(users[ 0 ].email).to.equal('admin1@example.com') |
286 | expect(users[ 0 ].displayNSFW).to.be.false | 286 | expect(users[ 0 ].nsfwPolicy).to.equal('display') |
287 | 287 | ||
288 | expect(users[ 1 ].username).to.equal('user_1') | 288 | expect(users[ 1 ].username).to.equal('user_1') |
289 | expect(users[ 1 ].email).to.equal('user_1@example.com') | 289 | expect(users[ 1 ].email).to.equal('user_1@example.com') |
290 | expect(users[ 1 ].displayNSFW).to.be.false | 290 | expect(users[ 1 ].nsfwPolicy).to.equal('display') |
291 | }) | 291 | }) |
292 | 292 | ||
293 | it('Should update my password', async function () { | 293 | it('Should update my password', async function () { |
@@ -305,7 +305,7 @@ describe('Test users', function () { | |||
305 | await updateMyUser({ | 305 | await updateMyUser({ |
306 | url: server.url, | 306 | url: server.url, |
307 | accessToken: accessTokenUser, | 307 | accessToken: accessTokenUser, |
308 | displayNSFW: true | 308 | nsfwPolicy: 'do_not_list' |
309 | }) | 309 | }) |
310 | 310 | ||
311 | const res = await getMyUserInformation(server.url, accessTokenUser) | 311 | const res = await getMyUserInformation(server.url, accessTokenUser) |
@@ -313,7 +313,7 @@ describe('Test users', function () { | |||
313 | 313 | ||
314 | expect(user.username).to.equal('user_1') | 314 | expect(user.username).to.equal('user_1') |
315 | expect(user.email).to.equal('user_1@example.com') | 315 | expect(user.email).to.equal('user_1@example.com') |
316 | expect(user.displayNSFW).to.be.ok | 316 | expect(user.nsfwPolicy).to.equal('do_not_list') |
317 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) | 317 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) |
318 | expect(user.id).to.be.a('number') | 318 | expect(user.id).to.be.a('number') |
319 | expect(user.account.description).to.be.null | 319 | expect(user.account.description).to.be.null |
@@ -344,7 +344,7 @@ describe('Test users', function () { | |||
344 | 344 | ||
345 | expect(user.username).to.equal('user_1') | 345 | expect(user.username).to.equal('user_1') |
346 | expect(user.email).to.equal('updated@example.com') | 346 | expect(user.email).to.equal('updated@example.com') |
347 | expect(user.displayNSFW).to.be.ok | 347 | expect(user.nsfwPolicy).to.equal('do_not_list') |
348 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) | 348 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) |
349 | expect(user.id).to.be.a('number') | 349 | expect(user.id).to.be.a('number') |
350 | expect(user.account.description).to.be.null | 350 | expect(user.account.description).to.be.null |
@@ -377,7 +377,7 @@ describe('Test users', function () { | |||
377 | 377 | ||
378 | expect(user.username).to.equal('user_1') | 378 | expect(user.username).to.equal('user_1') |
379 | expect(user.email).to.equal('updated@example.com') | 379 | expect(user.email).to.equal('updated@example.com') |
380 | expect(user.displayNSFW).to.be.ok | 380 | expect(user.nsfwPolicy).to.equal('do_not_list') |
381 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) | 381 | expect(user.videoQuota).to.equal(2 * 1024 * 1024) |
382 | expect(user.id).to.be.a('number') | 382 | expect(user.id).to.be.a('number') |
383 | expect(user.account.description).to.equal('my super description updated') | 383 | expect(user.account.description).to.equal('my super description updated') |
@@ -398,7 +398,7 @@ describe('Test users', function () { | |||
398 | 398 | ||
399 | expect(user.username).to.equal('user_1') | 399 | expect(user.username).to.equal('user_1') |
400 | expect(user.email).to.equal('updated2@example.com') | 400 | expect(user.email).to.equal('updated2@example.com') |
401 | expect(user.displayNSFW).to.be.ok | 401 | expect(user.nsfwPolicy).to.equal('do_not_list') |
402 | expect(user.videoQuota).to.equal(42) | 402 | expect(user.videoQuota).to.equal(42) |
403 | expect(user.roleLabel).to.equal('Moderator') | 403 | expect(user.roleLabel).to.equal('Moderator') |
404 | expect(user.id).to.be.a('number') | 404 | expect(user.id).to.be.a('number') |
diff --git a/server/tests/api/videos/video-nsfw.ts b/server/tests/api/videos/video-nsfw.ts new file mode 100644 index 000000000..4e5ab11ce --- /dev/null +++ b/server/tests/api/videos/video-nsfw.ts | |||
@@ -0,0 +1,197 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | ||
2 | |||
3 | import * as chai from 'chai' | ||
4 | import 'mocha' | ||
5 | import { flushTests, getVideosList, killallServers, ServerInfo, setAccessTokensToServers, uploadVideo } from '../../utils/index' | ||
6 | import { userLogin } from '../../utils/users/login' | ||
7 | import { createUser } from '../../utils/users/users' | ||
8 | import { getMyVideos } from '../../utils/videos/videos' | ||
9 | import { | ||
10 | getConfig, getCustomConfig, | ||
11 | getMyUserInformation, | ||
12 | getVideosListWithToken, | ||
13 | runServer, | ||
14 | searchVideo, | ||
15 | searchVideoWithToken, updateCustomConfig, | ||
16 | updateMyUser | ||
17 | } from '../../utils' | ||
18 | import { ServerConfig } from '../../../../shared/models' | ||
19 | import { CustomConfig } from '../../../../shared/models/server/custom-config.model' | ||
20 | |||
21 | const expect = chai.expect | ||
22 | |||
23 | describe('Test video NSFW policy', function () { | ||
24 | let server: ServerInfo | ||
25 | let userAccessToken: string | ||
26 | let customConfig: CustomConfig | ||
27 | |||
28 | before(async function () { | ||
29 | this.timeout(50000) | ||
30 | |||
31 | await flushTests() | ||
32 | server = await runServer(1) | ||
33 | |||
34 | // Get the access tokens | ||
35 | await setAccessTokensToServers([ server ]) | ||
36 | |||
37 | { | ||
38 | const attributes = { name: 'nsfw', nsfw: true } | ||
39 | await uploadVideo(server.url, server.accessToken, attributes) | ||
40 | } | ||
41 | |||
42 | { | ||
43 | const attributes = { name: 'normal', nsfw: false } | ||
44 | await uploadVideo(server.url, server.accessToken, attributes) | ||
45 | } | ||
46 | |||
47 | { | ||
48 | const res = await getCustomConfig(server.url, server.accessToken) | ||
49 | customConfig = res.body | ||
50 | } | ||
51 | }) | ||
52 | |||
53 | describe('Instance default NSFW policy', function () { | ||
54 | it('Should display NSFW videos with display default NSFW policy', async function () { | ||
55 | const resConfig = await getConfig(server.url) | ||
56 | const serverConfig: ServerConfig = resConfig.body | ||
57 | expect(serverConfig.instance.defaultNSFWPolicy).to.equal('display') | ||
58 | |||
59 | for (const res of [ await getVideosList(server.url), await searchVideo(server.url, 'n') ]) { | ||
60 | expect(res.body.total).to.equal(2) | ||
61 | |||
62 | const videos = res.body.data | ||
63 | expect(videos).to.have.lengthOf(2) | ||
64 | expect(videos[ 0 ].name).to.equal('normal') | ||
65 | expect(videos[ 1 ].name).to.equal('nsfw') | ||
66 | } | ||
67 | }) | ||
68 | |||
69 | it('Should not display NSFW videos with do_not_list default NSFW policy', async function () { | ||
70 | customConfig.instance.defaultNSFWPolicy = 'do_not_list' | ||
71 | await updateCustomConfig(server.url, server.accessToken, customConfig) | ||
72 | |||
73 | const resConfig = await getConfig(server.url) | ||
74 | const serverConfig: ServerConfig = resConfig.body | ||
75 | expect(serverConfig.instance.defaultNSFWPolicy).to.equal('do_not_list') | ||
76 | |||
77 | for (const res of [ await getVideosList(server.url), await searchVideo(server.url, 'n') ]) { | ||
78 | expect(res.body.total).to.equal(1) | ||
79 | |||
80 | const videos = res.body.data | ||
81 | expect(videos).to.have.lengthOf(1) | ||
82 | expect(videos[ 0 ].name).to.equal('normal') | ||
83 | } | ||
84 | }) | ||
85 | |||
86 | it('Should display NSFW videos with blur default NSFW policy', async function () { | ||
87 | customConfig.instance.defaultNSFWPolicy = 'blur' | ||
88 | await updateCustomConfig(server.url, server.accessToken, customConfig) | ||
89 | |||
90 | const resConfig = await getConfig(server.url) | ||
91 | const serverConfig: ServerConfig = resConfig.body | ||
92 | expect(serverConfig.instance.defaultNSFWPolicy).to.equal('blur') | ||
93 | |||
94 | for (const res of [ await getVideosList(server.url), await searchVideo(server.url, 'n') ]) { | ||
95 | expect(res.body.total).to.equal(2) | ||
96 | |||
97 | const videos = res.body.data | ||
98 | expect(videos).to.have.lengthOf(2) | ||
99 | expect(videos[ 0 ].name).to.equal('normal') | ||
100 | expect(videos[ 1 ].name).to.equal('nsfw') | ||
101 | } | ||
102 | }) | ||
103 | }) | ||
104 | |||
105 | describe('User NSFW policy', function () { | ||
106 | |||
107 | it('Should create a user having the default nsfw policy', async function () { | ||
108 | const username = 'user1' | ||
109 | const password = 'my super password' | ||
110 | await createUser(server.url, server.accessToken, username, password) | ||
111 | |||
112 | userAccessToken = await userLogin(server, { username, password }) | ||
113 | |||
114 | const res = await getMyUserInformation(server.url, userAccessToken) | ||
115 | const user = res.body | ||
116 | |||
117 | expect(user.nsfwPolicy).to.equal('blur') | ||
118 | }) | ||
119 | |||
120 | it('Should display NSFW videos with blur user NSFW policy', async function () { | ||
121 | const results = [ | ||
122 | await getVideosListWithToken(server.url, userAccessToken), | ||
123 | await searchVideoWithToken(server.url, 'n', userAccessToken) | ||
124 | ] | ||
125 | |||
126 | for (const res of results) { | ||
127 | expect(res.body.total).to.equal(2) | ||
128 | |||
129 | const videos = res.body.data | ||
130 | expect(videos).to.have.lengthOf(2) | ||
131 | expect(videos[ 0 ].name).to.equal('normal') | ||
132 | expect(videos[ 1 ].name).to.equal('nsfw') | ||
133 | } | ||
134 | }) | ||
135 | |||
136 | it('Should display NSFW videos with display user NSFW policy', async function () { | ||
137 | await updateMyUser({ | ||
138 | url: server.url, | ||
139 | accessToken: server.accessToken, | ||
140 | nsfwPolicy: 'display' | ||
141 | }) | ||
142 | |||
143 | const results = [ | ||
144 | await getVideosListWithToken(server.url, server.accessToken), | ||
145 | await searchVideoWithToken(server.url, 'n', server.accessToken) | ||
146 | ] | ||
147 | |||
148 | for (const res of results) { | ||
149 | expect(res.body.total).to.equal(2) | ||
150 | |||
151 | const videos = res.body.data | ||
152 | expect(videos).to.have.lengthOf(2) | ||
153 | expect(videos[ 0 ].name).to.equal('normal') | ||
154 | expect(videos[ 1 ].name).to.equal('nsfw') | ||
155 | } | ||
156 | }) | ||
157 | |||
158 | it('Should not display NSFW videos with do_not_list user NSFW policy', async function () { | ||
159 | await updateMyUser({ | ||
160 | url: server.url, | ||
161 | accessToken: server.accessToken, | ||
162 | nsfwPolicy: 'do_not_list' | ||
163 | }) | ||
164 | |||
165 | const results = [ | ||
166 | await getVideosListWithToken(server.url, server.accessToken), | ||
167 | await searchVideoWithToken(server.url, 'n', server.accessToken) | ||
168 | ] | ||
169 | for (const res of results) { | ||
170 | expect(res.body.total).to.equal(1) | ||
171 | |||
172 | const videos = res.body.data | ||
173 | expect(videos).to.have.lengthOf(1) | ||
174 | expect(videos[ 0 ].name).to.equal('normal') | ||
175 | } | ||
176 | }) | ||
177 | |||
178 | it('Should be able to see my NSFW videos even with do_not_list user NSFW policy', async function () { | ||
179 | const res = await getMyVideos(server.url, server.accessToken, 0, 5) | ||
180 | expect(res.body.total).to.equal(2) | ||
181 | |||
182 | const videos = res.body.data | ||
183 | expect(videos).to.have.lengthOf(2) | ||
184 | expect(videos[ 0 ].name).to.equal('normal') | ||
185 | expect(videos[ 1 ].name).to.equal('nsfw') | ||
186 | }) | ||
187 | }) | ||
188 | |||
189 | after(async function () { | ||
190 | killallServers([ server ]) | ||
191 | |||
192 | // Keep the logs if the test failed | ||
193 | if (this['ok']) { | ||
194 | await flushTests() | ||
195 | } | ||
196 | }) | ||
197 | }) | ||
diff --git a/server/tests/utils/users/users.ts b/server/tests/utils/users/users.ts index daf731a14..fc6b26c50 100644 --- a/server/tests/utils/users/users.ts +++ b/server/tests/utils/users/users.ts | |||
@@ -3,6 +3,7 @@ import * as request from 'supertest' | |||
3 | import { makePostBodyRequest, makeUploadRequest, makePutBodyRequest } from '../' | 3 | import { makePostBodyRequest, makeUploadRequest, makePutBodyRequest } from '../' |
4 | 4 | ||
5 | import { UserRole } from '../../../../shared/index' | 5 | import { UserRole } from '../../../../shared/index' |
6 | import { NSFWPolicyType } from '../../../../shared/models/videos/nsfw-policy.type' | ||
6 | 7 | ||
7 | function createUser ( | 8 | function createUser ( |
8 | url: string, | 9 | url: string, |
@@ -128,7 +129,7 @@ function updateMyUser (options: { | |||
128 | url: string | 129 | url: string |
129 | accessToken: string, | 130 | accessToken: string, |
130 | newPassword?: string, | 131 | newPassword?: string, |
131 | displayNSFW?: boolean, | 132 | nsfwPolicy?: NSFWPolicyType, |
132 | email?: string, | 133 | email?: string, |
133 | autoPlayVideo?: boolean | 134 | autoPlayVideo?: boolean |
134 | description?: string | 135 | description?: string |
@@ -137,7 +138,7 @@ function updateMyUser (options: { | |||
137 | 138 | ||
138 | const toSend = {} | 139 | const toSend = {} |
139 | if (options.newPassword !== undefined && options.newPassword !== null) toSend['password'] = options.newPassword | 140 | if (options.newPassword !== undefined && options.newPassword !== null) toSend['password'] = options.newPassword |
140 | if (options.displayNSFW !== undefined && options.displayNSFW !== null) toSend['displayNSFW'] = options.displayNSFW | 141 | if (options.nsfwPolicy !== undefined && options.nsfwPolicy !== null) toSend['nsfwPolicy'] = options.nsfwPolicy |
141 | if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend['autoPlayVideo'] = options.autoPlayVideo | 142 | if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend['autoPlayVideo'] = options.autoPlayVideo |
142 | if (options.email !== undefined && options.email !== null) toSend['email'] = options.email | 143 | if (options.email !== undefined && options.email !== null) toSend['email'] = options.email |
143 | if (options.description !== undefined && options.description !== null) toSend['description'] = options.description | 144 | if (options.description !== undefined && options.description !== null) toSend['description'] = options.description |
diff --git a/server/tests/utils/videos/videos.ts b/server/tests/utils/videos/videos.ts index 01e7fa5a1..5e186147e 100644 --- a/server/tests/utils/videos/videos.ts +++ b/server/tests/utils/videos/videos.ts | |||
@@ -128,6 +128,18 @@ function getVideosList (url: string) { | |||
128 | .expect('Content-Type', /json/) | 128 | .expect('Content-Type', /json/) |
129 | } | 129 | } |
130 | 130 | ||
131 | function getVideosListWithToken (url: string, token: string) { | ||
132 | const path = '/api/v1/videos' | ||
133 | |||
134 | return request(url) | ||
135 | .get(path) | ||
136 | .set('Authorization', 'Bearer ' + token) | ||
137 | .query({ sort: 'name' }) | ||
138 | .set('Accept', 'application/json') | ||
139 | .expect(200) | ||
140 | .expect('Content-Type', /json/) | ||
141 | } | ||
142 | |||
131 | function getLocalVideos (url: string) { | 143 | function getLocalVideos (url: string) { |
132 | const path = '/api/v1/videos' | 144 | const path = '/api/v1/videos' |
133 | 145 | ||
@@ -202,6 +214,18 @@ function searchVideo (url: string, search: string) { | |||
202 | .expect('Content-Type', /json/) | 214 | .expect('Content-Type', /json/) |
203 | } | 215 | } |
204 | 216 | ||
217 | function searchVideoWithToken (url: string, search: string, token: string) { | ||
218 | const path = '/api/v1/videos' | ||
219 | const req = request(url) | ||
220 | .get(path + '/search') | ||
221 | .set('Authorization', 'Bearer ' + token) | ||
222 | .query({ search }) | ||
223 | .set('Accept', 'application/json') | ||
224 | |||
225 | return req.expect(200) | ||
226 | .expect('Content-Type', /json/) | ||
227 | } | ||
228 | |||
205 | function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) { | 229 | function searchVideoWithPagination (url: string, search: string, start: number, count: number, sort?: string) { |
206 | const path = '/api/v1/videos' | 230 | const path = '/api/v1/videos' |
207 | 231 | ||
@@ -418,6 +442,8 @@ async function completeVideoCheck ( | |||
418 | expect(video.licence.label).to.equal(VIDEO_LICENCES[attributes.licence] || 'Unknown') | 442 | expect(video.licence.label).to.equal(VIDEO_LICENCES[attributes.licence] || 'Unknown') |
419 | expect(video.language.id).to.equal(attributes.language) | 443 | expect(video.language.id).to.equal(attributes.language) |
420 | expect(video.language.label).to.equal(VIDEO_LANGUAGES[attributes.language] || 'Unknown') | 444 | expect(video.language.label).to.equal(VIDEO_LANGUAGES[attributes.language] || 'Unknown') |
445 | expect(video.privacy.id).to.deep.equal(attributes.privacy) | ||
446 | expect(video.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy]) | ||
421 | expect(video.nsfw).to.equal(attributes.nsfw) | 447 | expect(video.nsfw).to.equal(attributes.nsfw) |
422 | expect(video.description).to.equal(attributes.description) | 448 | expect(video.description).to.equal(attributes.description) |
423 | expect(video.account.host).to.equal(attributes.account.host) | 449 | expect(video.account.host).to.equal(attributes.account.host) |
@@ -435,8 +461,6 @@ async function completeVideoCheck ( | |||
435 | 461 | ||
436 | expect(videoDetails.files).to.have.lengthOf(attributes.files.length) | 462 | expect(videoDetails.files).to.have.lengthOf(attributes.files.length) |
437 | expect(videoDetails.tags).to.deep.equal(attributes.tags) | 463 | expect(videoDetails.tags).to.deep.equal(attributes.tags) |
438 | expect(videoDetails.privacy.id).to.deep.equal(attributes.privacy) | ||
439 | expect(videoDetails.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy]) | ||
440 | expect(videoDetails.account.name).to.equal(attributes.account.name) | 464 | expect(videoDetails.account.name).to.equal(attributes.account.name) |
441 | expect(videoDetails.account.host).to.equal(attributes.account.host) | 465 | expect(videoDetails.account.host).to.equal(attributes.account.host) |
442 | expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled) | 466 | expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled) |
@@ -490,6 +514,7 @@ export { | |||
490 | getVideoPrivacies, | 514 | getVideoPrivacies, |
491 | getVideoLanguages, | 515 | getVideoLanguages, |
492 | getMyVideos, | 516 | getMyVideos, |
517 | searchVideoWithToken, | ||
493 | getVideo, | 518 | getVideo, |
494 | getVideoWithToken, | 519 | getVideoWithToken, |
495 | getVideosList, | 520 | getVideosList, |
@@ -499,6 +524,7 @@ export { | |||
499 | searchVideo, | 524 | searchVideo, |
500 | searchVideoWithPagination, | 525 | searchVideoWithPagination, |
501 | searchVideoWithSort, | 526 | searchVideoWithSort, |
527 | getVideosListWithToken, | ||
502 | uploadVideo, | 528 | uploadVideo, |
503 | updateVideo, | 529 | updateVideo, |
504 | rateVideo, | 530 | rateVideo, |