aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/middlewares/validators/videos
diff options
context:
space:
mode:
Diffstat (limited to 'server/middlewares/validators/videos')
-rw-r--r--server/middlewares/validators/videos/index.ts2
-rw-r--r--server/middlewares/validators/videos/video-blacklist.ts25
-rw-r--r--server/middlewares/validators/videos/video-captions.ts23
-rw-r--r--server/middlewares/validators/videos/video-channels.ts67
-rw-r--r--server/middlewares/validators/videos/video-comments.ts67
-rw-r--r--server/middlewares/validators/videos/video-imports.ts35
-rw-r--r--server/middlewares/validators/videos/video-live.ts91
-rw-r--r--server/middlewares/validators/videos/video-ownership-changes.ts121
-rw-r--r--server/middlewares/validators/videos/video-playlists.ts113
-rw-r--r--server/middlewares/validators/videos/video-rates.ts20
-rw-r--r--server/middlewares/validators/videos/video-shares.ts13
-rw-r--r--server/middlewares/validators/videos/video-watch.ts17
-rw-r--r--server/middlewares/validators/videos/videos.ts218
13 files changed, 475 insertions, 337 deletions
diff --git a/server/middlewares/validators/videos/index.ts b/server/middlewares/validators/videos/index.ts
index 1eabada0a..369c2c9b6 100644
--- a/server/middlewares/validators/videos/index.ts
+++ b/server/middlewares/validators/videos/index.ts
@@ -3,6 +3,8 @@ export * from './video-captions'
3export * from './video-channels' 3export * from './video-channels'
4export * from './video-comments' 4export * from './video-comments'
5export * from './video-imports' 5export * from './video-imports'
6export * from './video-live'
7export * from './video-ownership-changes'
6export * from './video-watch' 8export * from './video-watch'
7export * from './video-rates' 9export * from './video-rates'
8export * from './video-shares' 10export * from './video-shares'
diff --git a/server/middlewares/validators/videos/video-blacklist.ts b/server/middlewares/validators/videos/video-blacklist.ts
index 88c788a43..21141d84d 100644
--- a/server/middlewares/validators/videos/video-blacklist.ts
+++ b/server/middlewares/validators/videos/video-blacklist.ts
@@ -1,14 +1,13 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param, query } from 'express-validator' 2import { body, query } from 'express-validator'
3import { isBooleanValid, isIdOrUUIDValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc' 3import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
4import { isBooleanValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc'
4import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../../helpers/custom-validators/video-blacklist' 5import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../../helpers/custom-validators/video-blacklist'
5import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
6import { doesVideoBlacklistExist, doesVideoExist } from '../../../helpers/middlewares' 7import { areValidationErrors, doesVideoBlacklistExist, doesVideoExist, isValidVideoIdParam } from '../shared'
7import { areValidationErrors } from '../utils'
8import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
9 8
10const videosBlacklistRemoveValidator = [ 9const videosBlacklistRemoveValidator = [
11 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 10 isValidVideoIdParam('videoId'),
12 11
13 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 12 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
14 logger.debug('Checking blacklistRemove parameters.', { parameters: req.params }) 13 logger.debug('Checking blacklistRemove parameters.', { parameters: req.params })
@@ -22,7 +21,8 @@ const videosBlacklistRemoveValidator = [
22] 21]
23 22
24const videosBlacklistAddValidator = [ 23const videosBlacklistAddValidator = [
25 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 24 isValidVideoIdParam('videoId'),
25
26 body('unfederate') 26 body('unfederate')
27 .optional() 27 .optional()
28 .customSanitizer(toBooleanOrNull) 28 .customSanitizer(toBooleanOrNull)
@@ -39,10 +39,10 @@ const videosBlacklistAddValidator = [
39 39
40 const video = res.locals.videoAll 40 const video = res.locals.videoAll
41 if (req.body.unfederate === true && video.remote === true) { 41 if (req.body.unfederate === true && video.remote === true) {
42 return res 42 return res.fail({
43 .status(HttpStatusCode.CONFLICT_409) 43 status: HttpStatusCode.CONFLICT_409,
44 .send({ error: 'You cannot unfederate a remote video.' }) 44 message: 'You cannot unfederate a remote video.'
45 .end() 45 })
46 } 46 }
47 47
48 return next() 48 return next()
@@ -50,7 +50,8 @@ const videosBlacklistAddValidator = [
50] 50]
51 51
52const videosBlacklistUpdateValidator = [ 52const videosBlacklistUpdateValidator = [
53 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 53 isValidVideoIdParam('videoId'),
54
54 body('reason') 55 body('reason')
55 .optional() 56 .optional()
56 .custom(isVideoBlacklistReasonValid).withMessage('Should have a valid reason'), 57 .custom(isVideoBlacklistReasonValid).withMessage('Should have a valid reason'),
diff --git a/server/middlewares/validators/videos/video-captions.ts b/server/middlewares/validators/videos/video-captions.ts
index 872d9c2ab..2946f3e15 100644
--- a/server/middlewares/validators/videos/video-captions.ts
+++ b/server/middlewares/validators/videos/video-captions.ts
@@ -1,17 +1,18 @@
1import * as express from 'express' 1import * as express from 'express'
2import { areValidationErrors } from '../utils'
3import { isIdOrUUIDValid } from '../../../helpers/custom-validators/misc'
4import { body, param } from 'express-validator' 2import { body, param } from 'express-validator'
5import { CONSTRAINTS_FIELDS, MIMETYPES } from '../../../initializers/constants'
6import { UserRight } from '../../../../shared' 3import { UserRight } from '../../../../shared'
7import { logger } from '../../../helpers/logger'
8import { isVideoCaptionFile, isVideoCaptionLanguageValid } from '../../../helpers/custom-validators/video-captions' 4import { isVideoCaptionFile, isVideoCaptionLanguageValid } from '../../../helpers/custom-validators/video-captions'
9import { cleanUpReqFiles } from '../../../helpers/express-utils' 5import { cleanUpReqFiles } from '../../../helpers/express-utils'
10import { checkUserCanManageVideo, doesVideoCaptionExist, doesVideoExist } from '../../../helpers/middlewares' 6import { logger } from '../../../helpers/logger'
7import { CONSTRAINTS_FIELDS, MIMETYPES } from '../../../initializers/constants'
8import { areValidationErrors, checkUserCanManageVideo, doesVideoCaptionExist, doesVideoExist, isValidVideoIdParam } from '../shared'
11 9
12const addVideoCaptionValidator = [ 10const addVideoCaptionValidator = [
13 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), 11 isValidVideoIdParam('videoId'),
14 param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'), 12
13 param('captionLanguage')
14 .custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'),
15
15 body('captionfile') 16 body('captionfile')
16 .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile')) 17 .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile'))
17 .withMessage( 18 .withMessage(
@@ -35,8 +36,10 @@ const addVideoCaptionValidator = [
35] 36]
36 37
37const deleteVideoCaptionValidator = [ 38const deleteVideoCaptionValidator = [
38 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), 39 isValidVideoIdParam('videoId'),
39 param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'), 40
41 param('captionLanguage')
42 .custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'),
40 43
41 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 44 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
42 logger.debug('Checking deleteVideoCaption parameters', { parameters: req.params }) 45 logger.debug('Checking deleteVideoCaption parameters', { parameters: req.params })
@@ -54,7 +57,7 @@ const deleteVideoCaptionValidator = [
54] 57]
55 58
56const listVideoCaptionsValidator = [ 59const listVideoCaptionsValidator = [
57 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'), 60 isValidVideoIdParam('videoId'),
58 61
59 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 62 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
60 logger.debug('Checking listVideoCaptions parameters', { parameters: req.params }) 63 logger.debug('Checking listVideoCaptions parameters', { parameters: req.params })
diff --git a/server/middlewares/validators/videos/video-channels.ts b/server/middlewares/validators/videos/video-channels.ts
index 2463d281c..e7df185e4 100644
--- a/server/middlewares/validators/videos/video-channels.ts
+++ b/server/middlewares/validators/videos/video-channels.ts
@@ -3,6 +3,7 @@ import { body, param, query } from 'express-validator'
3import { VIDEO_CHANNELS } from '@server/initializers/constants' 3import { VIDEO_CHANNELS } from '@server/initializers/constants'
4import { MChannelAccountDefault, MUser } from '@server/types/models' 4import { MChannelAccountDefault, MUser } from '@server/types/models'
5import { UserRight } from '../../../../shared' 5import { UserRight } from '../../../../shared'
6import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
6import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor' 7import { isActorPreferredUsernameValid } from '../../../helpers/custom-validators/activitypub/actor'
7import { isBooleanValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc' 8import { isBooleanValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc'
8import { 9import {
@@ -11,11 +12,9 @@ import {
11 isVideoChannelSupportValid 12 isVideoChannelSupportValid
12} from '../../../helpers/custom-validators/video-channels' 13} from '../../../helpers/custom-validators/video-channels'
13import { logger } from '../../../helpers/logger' 14import { logger } from '../../../helpers/logger'
14import { doesLocalVideoChannelNameExist, doesVideoChannelNameWithHostExist } from '../../../helpers/middlewares' 15import { ActorModel } from '../../../models/actor/actor'
15import { ActorModel } from '../../../models/activitypub/actor'
16import { VideoChannelModel } from '../../../models/video/video-channel' 16import { VideoChannelModel } from '../../../models/video/video-channel'
17import { areValidationErrors } from '../utils' 17import { areValidationErrors, doesLocalVideoChannelNameExist, doesVideoChannelNameWithHostExist } from '../shared'
18import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
19 18
20const videoChannelsAddValidator = [ 19const videoChannelsAddValidator = [
21 body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'), 20 body('name').custom(isActorPreferredUsernameValid).withMessage('Should have a valid channel name'),
@@ -30,17 +29,16 @@ const videoChannelsAddValidator = [
30 29
31 const actor = await ActorModel.loadLocalByName(req.body.name) 30 const actor = await ActorModel.loadLocalByName(req.body.name)
32 if (actor) { 31 if (actor) {
33 res.status(HttpStatusCode.CONFLICT_409) 32 res.fail({
34 .send({ error: 'Another actor (account/channel) with this name on this instance already exists or has already existed.' }) 33 status: HttpStatusCode.CONFLICT_409,
35 .end() 34 message: 'Another actor (account/channel) with this name on this instance already exists or has already existed.'
35 })
36 return false 36 return false
37 } 37 }
38 38
39 const count = await VideoChannelModel.countByAccount(res.locals.oauth.token.User.Account.id) 39 const count = await VideoChannelModel.countByAccount(res.locals.oauth.token.User.Account.id)
40 if (count >= VIDEO_CHANNELS.MAX_PER_USER) { 40 if (count >= VIDEO_CHANNELS.MAX_PER_USER) {
41 res.status(HttpStatusCode.BAD_REQUEST_400) 41 res.fail({ message: `You cannot create more than ${VIDEO_CHANNELS.MAX_PER_USER} channels` })
42 .send({ error: `You cannot create more than ${VIDEO_CHANNELS.MAX_PER_USER} channels` })
43 .end()
44 return false 42 return false
45 } 43 }
46 44
@@ -71,13 +69,17 @@ const videoChannelsUpdateValidator = [
71 69
72 // We need to make additional checks 70 // We need to make additional checks
73 if (res.locals.videoChannel.Actor.isOwned() === false) { 71 if (res.locals.videoChannel.Actor.isOwned() === false) {
74 return res.status(HttpStatusCode.FORBIDDEN_403) 72 return res.fail({
75 .json({ error: 'Cannot update video channel of another server' }) 73 status: HttpStatusCode.FORBIDDEN_403,
74 message: 'Cannot update video channel of another server'
75 })
76 } 76 }
77 77
78 if (res.locals.videoChannel.Account.userId !== res.locals.oauth.token.User.id) { 78 if (res.locals.videoChannel.Account.userId !== res.locals.oauth.token.User.id) {
79 return res.status(HttpStatusCode.FORBIDDEN_403) 79 return res.fail({
80 .json({ error: 'Cannot update video channel of another user' }) 80 status: HttpStatusCode.FORBIDDEN_403,
81 message: 'Cannot update video channel of another user'
82 })
81 } 83 }
82 84
83 return next() 85 return next()
@@ -139,6 +141,18 @@ const videoChannelStatsValidator = [
139 } 141 }
140] 142]
141 143
144const videoChannelsListValidator = [
145 query('search').optional().not().isEmpty().withMessage('Should have a valid search'),
146
147 (req: express.Request, res: express.Response, next: express.NextFunction) => {
148 logger.debug('Checking video channels search query', { parameters: req.query })
149
150 if (areValidationErrors(req, res)) return
151
152 return next()
153 }
154]
155
142// --------------------------------------------------------------------------- 156// ---------------------------------------------------------------------------
143 157
144export { 158export {
@@ -146,6 +160,7 @@ export {
146 videoChannelsUpdateValidator, 160 videoChannelsUpdateValidator,
147 videoChannelsRemoveValidator, 161 videoChannelsRemoveValidator,
148 videoChannelsNameWithHostValidator, 162 videoChannelsNameWithHostValidator,
163 videoChannelsListValidator,
149 localVideoChannelValidator, 164 localVideoChannelValidator,
150 videoChannelStatsValidator 165 videoChannelStatsValidator
151} 166}
@@ -154,10 +169,10 @@ export {
154 169
155function checkUserCanDeleteVideoChannel (user: MUser, videoChannel: MChannelAccountDefault, res: express.Response) { 170function checkUserCanDeleteVideoChannel (user: MUser, videoChannel: MChannelAccountDefault, res: express.Response) {
156 if (videoChannel.Actor.isOwned() === false) { 171 if (videoChannel.Actor.isOwned() === false) {
157 res.status(HttpStatusCode.FORBIDDEN_403) 172 res.fail({
158 .json({ error: 'Cannot remove video channel of another server.' }) 173 status: HttpStatusCode.FORBIDDEN_403,
159 .end() 174 message: 'Cannot remove video channel of another server.'
160 175 })
161 return false 176 return false
162 } 177 }
163 178
@@ -165,10 +180,10 @@ function checkUserCanDeleteVideoChannel (user: MUser, videoChannel: MChannelAcco
165 // The user can delete it if s/he is an admin 180 // The user can delete it if s/he is an admin
166 // Or if s/he is the video channel's account 181 // Or if s/he is the video channel's account
167 if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_CHANNEL) === false && videoChannel.Account.userId !== user.id) { 182 if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_CHANNEL) === false && videoChannel.Account.userId !== user.id) {
168 res.status(HttpStatusCode.FORBIDDEN_403) 183 res.fail({
169 .json({ error: 'Cannot remove video channel of another user' }) 184 status: HttpStatusCode.FORBIDDEN_403,
170 .end() 185 message: 'Cannot remove video channel of another user'
171 186 })
172 return false 187 return false
173 } 188 }
174 189
@@ -179,10 +194,10 @@ async function checkVideoChannelIsNotTheLastOne (res: express.Response) {
179 const count = await VideoChannelModel.countByAccount(res.locals.oauth.token.User.Account.id) 194 const count = await VideoChannelModel.countByAccount(res.locals.oauth.token.User.Account.id)
180 195
181 if (count <= 1) { 196 if (count <= 1) {
182 res.status(HttpStatusCode.CONFLICT_409) 197 res.fail({
183 .json({ error: 'Cannot remove the last channel of this user' }) 198 status: HttpStatusCode.CONFLICT_409,
184 .end() 199 message: 'Cannot remove the last channel of this user'
185 200 })
186 return false 201 return false
187 } 202 }
188 203
diff --git a/server/middlewares/validators/videos/video-comments.ts b/server/middlewares/validators/videos/video-comments.ts
index 1afacfed8..885506ebe 100644
--- a/server/middlewares/validators/videos/video-comments.ts
+++ b/server/middlewares/validators/videos/video-comments.ts
@@ -2,19 +2,14 @@ import * as express from 'express'
2import { body, param, query } from 'express-validator' 2import { body, param, query } from 'express-validator'
3import { MUserAccountUrl } from '@server/types/models' 3import { MUserAccountUrl } from '@server/types/models'
4import { UserRight } from '../../../../shared' 4import { UserRight } from '../../../../shared'
5import { exists, isBooleanValid, isIdOrUUIDValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc' 5import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
6import { 6import { exists, isBooleanValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc'
7 doesVideoCommentExist, 7import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments'
8 doesVideoCommentThreadExist,
9 isValidVideoCommentText
10} from '../../../helpers/custom-validators/video-comments'
11import { logger } from '../../../helpers/logger' 8import { logger } from '../../../helpers/logger'
12import { doesVideoExist } from '../../../helpers/middlewares'
13import { AcceptResult, isLocalVideoCommentReplyAccepted, isLocalVideoThreadAccepted } from '../../../lib/moderation' 9import { AcceptResult, isLocalVideoCommentReplyAccepted, isLocalVideoThreadAccepted } from '../../../lib/moderation'
14import { Hooks } from '../../../lib/plugins/hooks' 10import { Hooks } from '../../../lib/plugins/hooks'
15import { MCommentOwnerVideoReply, MVideo, MVideoFullLight } from '../../../types/models/video' 11import { MCommentOwnerVideoReply, MVideo, MVideoFullLight } from '../../../types/models/video'
16import { areValidationErrors } from '../utils' 12import { areValidationErrors, doesVideoCommentExist, doesVideoCommentThreadExist, doesVideoExist, isValidVideoIdParam } from '../shared'
17import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
18 13
19const listVideoCommentsValidator = [ 14const listVideoCommentsValidator = [
20 query('isLocal') 15 query('isLocal')
@@ -45,7 +40,7 @@ const listVideoCommentsValidator = [
45] 40]
46 41
47const listVideoCommentThreadsValidator = [ 42const listVideoCommentThreadsValidator = [
48 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 43 isValidVideoIdParam('videoId'),
49 44
50 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 45 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
51 logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params }) 46 logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params })
@@ -58,8 +53,10 @@ const listVideoCommentThreadsValidator = [
58] 53]
59 54
60const listVideoThreadCommentsValidator = [ 55const listVideoThreadCommentsValidator = [
61 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 56 isValidVideoIdParam('videoId'),
62 param('threadId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'), 57
58 param('threadId')
59 .custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'),
63 60
64 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 61 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
65 logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params }) 62 logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params })
@@ -73,8 +70,10 @@ const listVideoThreadCommentsValidator = [
73] 70]
74 71
75const addVideoCommentThreadValidator = [ 72const addVideoCommentThreadValidator = [
76 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 73 isValidVideoIdParam('videoId'),
77 body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'), 74
75 body('text')
76 .custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
78 77
79 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 78 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
80 logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params, body: req.body }) 79 logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params, body: req.body })
@@ -89,8 +88,10 @@ const addVideoCommentThreadValidator = [
89] 88]
90 89
91const addVideoCommentReplyValidator = [ 90const addVideoCommentReplyValidator = [
92 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 91 isValidVideoIdParam('videoId'),
92
93 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'), 93 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
94
94 body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'), 95 body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
95 96
96 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 97 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
@@ -107,8 +108,10 @@ const addVideoCommentReplyValidator = [
107] 108]
108 109
109const videoCommentGetValidator = [ 110const videoCommentGetValidator = [
110 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 111 isValidVideoIdParam('videoId'),
111 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'), 112
113 param('commentId')
114 .custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
112 115
113 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 116 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
114 logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params }) 117 logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
@@ -122,7 +125,8 @@ const videoCommentGetValidator = [
122] 125]
123 126
124const removeVideoCommentValidator = [ 127const removeVideoCommentValidator = [
125 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 128 isValidVideoIdParam('videoId'),
129
126 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'), 130 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
127 131
128 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 132 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
@@ -155,9 +159,10 @@ export {
155 159
156function isVideoCommentsEnabled (video: MVideo, res: express.Response) { 160function isVideoCommentsEnabled (video: MVideo, res: express.Response) {
157 if (video.commentsEnabled !== true) { 161 if (video.commentsEnabled !== true) {
158 res.status(HttpStatusCode.CONFLICT_409) 162 res.fail({
159 .json({ error: 'Video comments are disabled for this video.' }) 163 status: HttpStatusCode.CONFLICT_409,
160 164 message: 'Video comments are disabled for this video.'
165 })
161 return false 166 return false
162 } 167 }
163 168
@@ -166,9 +171,10 @@ function isVideoCommentsEnabled (video: MVideo, res: express.Response) {
166 171
167function checkUserCanDeleteVideoComment (user: MUserAccountUrl, videoComment: MCommentOwnerVideoReply, res: express.Response) { 172function checkUserCanDeleteVideoComment (user: MUserAccountUrl, videoComment: MCommentOwnerVideoReply, res: express.Response) {
168 if (videoComment.isDeleted()) { 173 if (videoComment.isDeleted()) {
169 res.status(HttpStatusCode.CONFLICT_409) 174 res.fail({
170 .json({ error: 'This comment is already deleted' }) 175 status: HttpStatusCode.CONFLICT_409,
171 176 message: 'This comment is already deleted'
177 })
172 return false 178 return false
173 } 179 }
174 180
@@ -179,9 +185,10 @@ function checkUserCanDeleteVideoComment (user: MUserAccountUrl, videoComment: MC
179 videoComment.accountId !== userAccount.id && // Not the comment owner 185 videoComment.accountId !== userAccount.id && // Not the comment owner
180 videoComment.Video.VideoChannel.accountId !== userAccount.id // Not the video owner 186 videoComment.Video.VideoChannel.accountId !== userAccount.id // Not the video owner
181 ) { 187 ) {
182 res.status(HttpStatusCode.FORBIDDEN_403) 188 res.fail({
183 .json({ error: 'Cannot remove video comment of another user' }) 189 status: HttpStatusCode.FORBIDDEN_403,
184 190 message: 'Cannot remove video comment of another user'
191 })
185 return false 192 return false
186 } 193 }
187 194
@@ -215,9 +222,11 @@ async function isVideoCommentAccepted (req: express.Request, res: express.Respon
215 222
216 if (!acceptedResult || acceptedResult.accepted !== true) { 223 if (!acceptedResult || acceptedResult.accepted !== true) {
217 logger.info('Refused local comment.', { acceptedResult, acceptParameters }) 224 logger.info('Refused local comment.', { acceptedResult, acceptParameters })
218 res.status(HttpStatusCode.FORBIDDEN_403)
219 .json({ error: acceptedResult?.errorMessage || 'Refused local comment' })
220 225
226 res.fail({
227 status: HttpStatusCode.FORBIDDEN_403,
228 message: acceptedResult?.errorMessage || 'Refused local comment'
229 })
221 return false 230 return false
222 } 231 }
223 232
diff --git a/server/middlewares/validators/videos/video-imports.ts b/server/middlewares/validators/videos/video-imports.ts
index c53af3861..85dc647ce 100644
--- a/server/middlewares/validators/videos/video-imports.ts
+++ b/server/middlewares/validators/videos/video-imports.ts
@@ -2,18 +2,17 @@ import * as express from 'express'
2import { body } from 'express-validator' 2import { body } from 'express-validator'
3import { isPreImportVideoAccepted } from '@server/lib/moderation' 3import { isPreImportVideoAccepted } from '@server/lib/moderation'
4import { Hooks } from '@server/lib/plugins/hooks' 4import { Hooks } from '@server/lib/plugins/hooks'
5import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
5import { VideoImportCreate } from '@shared/models/videos/import/video-import-create.model' 6import { VideoImportCreate } from '@shared/models/videos/import/video-import-create.model'
6import { isIdValid, toIntOrNull } from '../../../helpers/custom-validators/misc' 7import { isIdValid, toIntOrNull } from '../../../helpers/custom-validators/misc'
7import { isVideoImportTargetUrlValid, isVideoImportTorrentFile } from '../../../helpers/custom-validators/video-imports' 8import { isVideoImportTargetUrlValid, isVideoImportTorrentFile } from '../../../helpers/custom-validators/video-imports'
8import { isVideoMagnetUriValid, isVideoNameValid } from '../../../helpers/custom-validators/videos' 9import { isVideoMagnetUriValid, isVideoNameValid } from '../../../helpers/custom-validators/videos'
9import { cleanUpReqFiles } from '../../../helpers/express-utils' 10import { cleanUpReqFiles } from '../../../helpers/express-utils'
10import { logger } from '../../../helpers/logger' 11import { logger } from '../../../helpers/logger'
11import { doesVideoChannelOfAccountExist } from '../../../helpers/middlewares'
12import { CONFIG } from '../../../initializers/config' 12import { CONFIG } from '../../../initializers/config'
13import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' 13import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
14import { areValidationErrors } from '../utils' 14import { areValidationErrors, doesVideoChannelOfAccountExist } from '../shared'
15import { getCommonVideoEditAttributes } from './videos' 15import { getCommonVideoEditAttributes } from './videos'
16import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
17 16
18const videoImportAddValidator = getCommonVideoEditAttributes().concat([ 17const videoImportAddValidator = getCommonVideoEditAttributes().concat([
19 body('channelId') 18 body('channelId')
@@ -33,7 +32,9 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([
33 ), 32 ),
34 body('name') 33 body('name')
35 .optional() 34 .optional()
36 .custom(isVideoNameValid).withMessage('Should have a valid name'), 35 .custom(isVideoNameValid).withMessage(
36 `Should have a video name between ${CONSTRAINTS_FIELDS.VIDEOS.NAME.min} and ${CONSTRAINTS_FIELDS.VIDEOS.NAME.max} characters long`
37 ),
37 38
38 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 39 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
39 logger.debug('Checking videoImportAddValidator parameters', { parameters: req.body }) 40 logger.debug('Checking videoImportAddValidator parameters', { parameters: req.body })
@@ -45,16 +46,20 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([
45 46
46 if (CONFIG.IMPORT.VIDEOS.HTTP.ENABLED !== true && req.body.targetUrl) { 47 if (CONFIG.IMPORT.VIDEOS.HTTP.ENABLED !== true && req.body.targetUrl) {
47 cleanUpReqFiles(req) 48 cleanUpReqFiles(req)
48 return res.status(HttpStatusCode.CONFLICT_409) 49
49 .json({ error: 'HTTP import is not enabled on this instance.' }) 50 return res.fail({
50 .end() 51 status: HttpStatusCode.CONFLICT_409,
52 message: 'HTTP import is not enabled on this instance.'
53 })
51 } 54 }
52 55
53 if (CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED !== true && (req.body.magnetUri || torrentFile)) { 56 if (CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED !== true && (req.body.magnetUri || torrentFile)) {
54 cleanUpReqFiles(req) 57 cleanUpReqFiles(req)
55 return res.status(HttpStatusCode.CONFLICT_409) 58
56 .json({ error: 'Torrent/magnet URI import is not enabled on this instance.' }) 59 return res.fail({
57 .end() 60 status: HttpStatusCode.CONFLICT_409,
61 message: 'Torrent/magnet URI import is not enabled on this instance.'
62 })
58 } 63 }
59 64
60 if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) 65 if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req)
@@ -63,9 +68,7 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([
63 if (!req.body.targetUrl && !req.body.magnetUri && !torrentFile) { 68 if (!req.body.targetUrl && !req.body.magnetUri && !torrentFile) {
64 cleanUpReqFiles(req) 69 cleanUpReqFiles(req)
65 70
66 return res.status(HttpStatusCode.BAD_REQUEST_400) 71 return res.fail({ message: 'Should have a magnetUri or a targetUrl or a torrent file.' })
67 .json({ error: 'Should have a magnetUri or a targetUrl or a torrent file.' })
68 .end()
69 } 72 }
70 73
71 if (!await isImportAccepted(req, res)) return cleanUpReqFiles(req) 74 if (!await isImportAccepted(req, res)) return cleanUpReqFiles(req)
@@ -101,9 +104,11 @@ async function isImportAccepted (req: express.Request, res: express.Response) {
101 104
102 if (!acceptedResult || acceptedResult.accepted !== true) { 105 if (!acceptedResult || acceptedResult.accepted !== true) {
103 logger.info('Refused to import video.', { acceptedResult, acceptParameters }) 106 logger.info('Refused to import video.', { acceptedResult, acceptParameters })
104 res.status(HttpStatusCode.FORBIDDEN_403)
105 .json({ error: acceptedResult.errorMessage || 'Refused to import video' })
106 107
108 res.fail({
109 status: HttpStatusCode.FORBIDDEN_403,
110 message: acceptedResult.errorMessage || 'Refused to import video'
111 })
107 return false 112 return false
108 } 113 }
109 114
diff --git a/server/middlewares/validators/videos/video-live.ts b/server/middlewares/validators/videos/video-live.ts
index 3a73e1272..7cfb935e3 100644
--- a/server/middlewares/validators/videos/video-live.ts
+++ b/server/middlewares/validators/videos/video-live.ts
@@ -1,22 +1,28 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param } from 'express-validator' 2import { body } from 'express-validator'
3import { checkUserCanManageVideo, doesVideoChannelOfAccountExist, doesVideoExist } from '@server/helpers/middlewares/videos' 3import { CONSTRAINTS_FIELDS } from '@server/initializers/constants'
4import { isLocalLiveVideoAccepted } from '@server/lib/moderation'
5import { Hooks } from '@server/lib/plugins/hooks'
6import { VideoModel } from '@server/models/video/video'
4import { VideoLiveModel } from '@server/models/video/video-live' 7import { VideoLiveModel } from '@server/models/video/video-live'
8import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
5import { ServerErrorCode, UserRight, VideoState } from '@shared/models' 9import { ServerErrorCode, UserRight, VideoState } from '@shared/models'
6import { isBooleanValid, isIdOrUUIDValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc' 10import { isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../../helpers/custom-validators/misc'
7import { isVideoNameValid } from '../../../helpers/custom-validators/videos' 11import { isVideoNameValid } from '../../../helpers/custom-validators/videos'
8import { cleanUpReqFiles } from '../../../helpers/express-utils' 12import { cleanUpReqFiles } from '../../../helpers/express-utils'
9import { logger } from '../../../helpers/logger' 13import { logger } from '../../../helpers/logger'
10import { CONFIG } from '../../../initializers/config' 14import { CONFIG } from '../../../initializers/config'
11import { areValidationErrors } from '../utils' 15import {
16 areValidationErrors,
17 checkUserCanManageVideo,
18 doesVideoChannelOfAccountExist,
19 doesVideoExist,
20 isValidVideoIdParam
21} from '../shared'
12import { getCommonVideoEditAttributes } from './videos' 22import { getCommonVideoEditAttributes } from './videos'
13import { VideoModel } from '@server/models/video/video'
14import { Hooks } from '@server/lib/plugins/hooks'
15import { isLocalLiveVideoAccepted } from '@server/lib/moderation'
16import { HttpStatusCode } from '@shared/core-utils/miscs/http-error-codes'
17 23
18const videoLiveGetValidator = [ 24const videoLiveGetValidator = [
19 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'), 25 isValidVideoIdParam('videoId'),
20 26
21 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 27 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
22 logger.debug('Checking videoLiveGetValidator parameters', { parameters: req.params, user: res.locals.oauth.token.User.username }) 28 logger.debug('Checking videoLiveGetValidator parameters', { parameters: req.params, user: res.locals.oauth.token.User.username })
@@ -29,7 +35,12 @@ const videoLiveGetValidator = [
29 if (!checkUserCanManageVideo(user, res.locals.videoAll, UserRight.GET_ANY_LIVE, res, false)) return 35 if (!checkUserCanManageVideo(user, res.locals.videoAll, UserRight.GET_ANY_LIVE, res, false)) return
30 36
31 const videoLive = await VideoLiveModel.loadByVideoId(res.locals.videoAll.id) 37 const videoLive = await VideoLiveModel.loadByVideoId(res.locals.videoAll.id)
32 if (!videoLive) return res.sendStatus(HttpStatusCode.NOT_FOUND_404) 38 if (!videoLive) {
39 return res.fail({
40 status: HttpStatusCode.NOT_FOUND_404,
41 message: 'Live video not found'
42 })
43 }
33 44
34 res.locals.videoLive = videoLive 45 res.locals.videoLive = videoLive
35 46
@@ -43,7 +54,9 @@ const videoLiveAddValidator = getCommonVideoEditAttributes().concat([
43 .custom(isIdValid).withMessage('Should have correct video channel id'), 54 .custom(isIdValid).withMessage('Should have correct video channel id'),
44 55
45 body('name') 56 body('name')
46 .custom(isVideoNameValid).withMessage('Should have a valid name'), 57 .custom(isVideoNameValid).withMessage(
58 `Should have a video name between ${CONSTRAINTS_FIELDS.VIDEOS.NAME.min} and ${CONSTRAINTS_FIELDS.VIDEOS.NAME.max} characters long`
59 ),
47 60
48 body('saveReplay') 61 body('saveReplay')
49 .optional() 62 .optional()
@@ -63,22 +76,27 @@ const videoLiveAddValidator = getCommonVideoEditAttributes().concat([
63 if (CONFIG.LIVE.ENABLED !== true) { 76 if (CONFIG.LIVE.ENABLED !== true) {
64 cleanUpReqFiles(req) 77 cleanUpReqFiles(req)
65 78
66 return res.status(HttpStatusCode.FORBIDDEN_403) 79 return res.fail({
67 .json({ error: 'Live is not enabled on this instance' }) 80 status: HttpStatusCode.FORBIDDEN_403,
81 message: 'Live is not enabled on this instance',
82 type: ServerErrorCode.LIVE_NOT_ENABLED
83 })
68 } 84 }
69 85
70 if (CONFIG.LIVE.ALLOW_REPLAY !== true && req.body.saveReplay === true) { 86 if (CONFIG.LIVE.ALLOW_REPLAY !== true && req.body.saveReplay === true) {
71 cleanUpReqFiles(req) 87 cleanUpReqFiles(req)
72 88
73 return res.status(HttpStatusCode.FORBIDDEN_403) 89 return res.fail({
74 .json({ error: 'Saving live replay is not allowed instance' }) 90 status: HttpStatusCode.FORBIDDEN_403,
91 message: 'Saving live replay is not enabled on this instance',
92 type: ServerErrorCode.LIVE_NOT_ALLOWING_REPLAY
93 })
75 } 94 }
76 95
77 if (req.body.permanentLive && req.body.saveReplay) { 96 if (req.body.permanentLive && req.body.saveReplay) {
78 cleanUpReqFiles(req) 97 cleanUpReqFiles(req)
79 98
80 return res.status(HttpStatusCode.BAD_REQUEST_400) 99 return res.fail({ message: 'Cannot set this live as permanent while saving its replay' })
81 .json({ error: 'Cannot set this live as permanent while saving its replay' })
82 } 100 }
83 101
84 const user = res.locals.oauth.token.User 102 const user = res.locals.oauth.token.User
@@ -90,11 +108,11 @@ const videoLiveAddValidator = getCommonVideoEditAttributes().concat([
90 if (totalInstanceLives >= CONFIG.LIVE.MAX_INSTANCE_LIVES) { 108 if (totalInstanceLives >= CONFIG.LIVE.MAX_INSTANCE_LIVES) {
91 cleanUpReqFiles(req) 109 cleanUpReqFiles(req)
92 110
93 return res.status(HttpStatusCode.FORBIDDEN_403) 111 return res.fail({
94 .json({ 112 status: HttpStatusCode.FORBIDDEN_403,
95 code: ServerErrorCode.MAX_INSTANCE_LIVES_LIMIT_REACHED, 113 message: 'Cannot create this live because the max instance lives limit is reached.',
96 error: 'Cannot create this live because the max instance lives limit is reached.' 114 type: ServerErrorCode.MAX_INSTANCE_LIVES_LIMIT_REACHED
97 }) 115 })
98 } 116 }
99 } 117 }
100 118
@@ -104,11 +122,11 @@ const videoLiveAddValidator = getCommonVideoEditAttributes().concat([
104 if (totalUserLives >= CONFIG.LIVE.MAX_USER_LIVES) { 122 if (totalUserLives >= CONFIG.LIVE.MAX_USER_LIVES) {
105 cleanUpReqFiles(req) 123 cleanUpReqFiles(req)
106 124
107 return res.status(HttpStatusCode.FORBIDDEN_403) 125 return res.fail({
108 .json({ 126 status: HttpStatusCode.FORBIDDEN_403,
109 code: ServerErrorCode.MAX_USER_LIVES_LIMIT_REACHED, 127 message: 'Cannot create this live because the max user lives limit is reached.',
110 error: 'Cannot create this live because the max user lives limit is reached.' 128 type: ServerErrorCode.MAX_USER_LIVES_LIMIT_REACHED
111 }) 129 })
112 } 130 }
113 } 131 }
114 132
@@ -130,18 +148,18 @@ const videoLiveUpdateValidator = [
130 if (areValidationErrors(req, res)) return 148 if (areValidationErrors(req, res)) return
131 149
132 if (req.body.permanentLive && req.body.saveReplay) { 150 if (req.body.permanentLive && req.body.saveReplay) {
133 return res.status(HttpStatusCode.BAD_REQUEST_400) 151 return res.fail({ message: 'Cannot set this live as permanent while saving its replay' })
134 .json({ error: 'Cannot set this live as permanent while saving its replay' })
135 } 152 }
136 153
137 if (CONFIG.LIVE.ALLOW_REPLAY !== true && req.body.saveReplay === true) { 154 if (CONFIG.LIVE.ALLOW_REPLAY !== true && req.body.saveReplay === true) {
138 return res.status(HttpStatusCode.FORBIDDEN_403) 155 return res.fail({
139 .json({ error: 'Saving live replay is not allowed instance' }) 156 status: HttpStatusCode.FORBIDDEN_403,
157 message: 'Saving live replay is not allowed instance'
158 })
140 } 159 }
141 160
142 if (res.locals.videoAll.state !== VideoState.WAITING_FOR_LIVE) { 161 if (res.locals.videoAll.state !== VideoState.WAITING_FOR_LIVE) {
143 return res.status(HttpStatusCode.BAD_REQUEST_400) 162 return res.fail({ message: 'Cannot update a live that has already started' })
144 .json({ error: 'Cannot update a live that has already started' })
145 } 163 }
146 164
147 // Check the user can manage the live 165 // Check the user can manage the live
@@ -177,9 +195,10 @@ async function isLiveVideoAccepted (req: express.Request, res: express.Response)
177 if (!acceptedResult || acceptedResult.accepted !== true) { 195 if (!acceptedResult || acceptedResult.accepted !== true) {
178 logger.info('Refused local live video.', { acceptedResult, acceptParameters }) 196 logger.info('Refused local live video.', { acceptedResult, acceptParameters })
179 197
180 res.status(HttpStatusCode.FORBIDDEN_403) 198 res.fail({
181 .json({ error: acceptedResult.errorMessage || 'Refused local live video' }) 199 status: HttpStatusCode.FORBIDDEN_403,
182 200 message: acceptedResult.errorMessage || 'Refused local live video'
201 })
183 return false 202 return false
184 } 203 }
185 204
diff --git a/server/middlewares/validators/videos/video-ownership-changes.ts b/server/middlewares/validators/videos/video-ownership-changes.ts
new file mode 100644
index 000000000..54ac46c99
--- /dev/null
+++ b/server/middlewares/validators/videos/video-ownership-changes.ts
@@ -0,0 +1,121 @@
1import * as express from 'express'
2import { param } from 'express-validator'
3import { isIdValid } from '@server/helpers/custom-validators/misc'
4import { checkUserCanTerminateOwnershipChange } from '@server/helpers/custom-validators/video-ownership'
5import { logger } from '@server/helpers/logger'
6import { isAbleToUploadVideo } from '@server/lib/user'
7import { AccountModel } from '@server/models/account/account'
8import { MVideoWithAllFiles } from '@server/types/models'
9import { HttpStatusCode } from '@shared/core-utils'
10import { ServerErrorCode, UserRight, VideoChangeOwnershipAccept, VideoChangeOwnershipStatus, VideoState } from '@shared/models'
11import {
12 areValidationErrors,
13 checkUserCanManageVideo,
14 doesChangeVideoOwnershipExist,
15 doesVideoChannelOfAccountExist,
16 doesVideoExist,
17 isValidVideoIdParam
18} from '../shared'
19
20const videosChangeOwnershipValidator = [
21 isValidVideoIdParam('videoId'),
22
23 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
24 logger.debug('Checking changeOwnership parameters', { parameters: req.params })
25
26 if (areValidationErrors(req, res)) return
27 if (!await doesVideoExist(req.params.videoId, res)) return
28
29 // Check if the user who did the request is able to change the ownership of the video
30 if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.videoAll, UserRight.CHANGE_VIDEO_OWNERSHIP, res)) return
31
32 const nextOwner = await AccountModel.loadLocalByName(req.body.username)
33 if (!nextOwner) {
34 res.fail({ message: 'Changing video ownership to a remote account is not supported yet' })
35 return
36 }
37
38 res.locals.nextOwner = nextOwner
39 return next()
40 }
41]
42
43const videosTerminateChangeOwnershipValidator = [
44 param('id')
45 .custom(isIdValid).withMessage('Should have a valid id'),
46
47 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
48 logger.debug('Checking changeOwnership parameters', { parameters: req.params })
49
50 if (areValidationErrors(req, res)) return
51 if (!await doesChangeVideoOwnershipExist(req.params.id, res)) return
52
53 // Check if the user who did the request is able to change the ownership of the video
54 if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return
55
56 const videoChangeOwnership = res.locals.videoChangeOwnership
57
58 if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) {
59 res.fail({
60 status: HttpStatusCode.FORBIDDEN_403,
61 message: 'Ownership already accepted or refused'
62 })
63 return
64 }
65
66 return next()
67 }
68]
69
70const videosAcceptChangeOwnershipValidator = [
71 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
72 const body = req.body as VideoChangeOwnershipAccept
73 if (!await doesVideoChannelOfAccountExist(body.channelId, res.locals.oauth.token.User, res)) return
74
75 const videoChangeOwnership = res.locals.videoChangeOwnership
76
77 const video = videoChangeOwnership.Video
78
79 if (!await checkCanAccept(video, res)) return
80
81 return next()
82 }
83]
84
85export {
86 videosChangeOwnershipValidator,
87 videosTerminateChangeOwnershipValidator,
88 videosAcceptChangeOwnershipValidator
89}
90
91// ---------------------------------------------------------------------------
92
93async function checkCanAccept (video: MVideoWithAllFiles, res: express.Response): Promise<boolean> {
94 if (video.isLive) {
95
96 if (video.state !== VideoState.WAITING_FOR_LIVE) {
97 res.fail({
98 status: HttpStatusCode.BAD_REQUEST_400,
99 message: 'You can accept an ownership change of a published live.'
100 })
101
102 return false
103 }
104
105 return true
106 }
107
108 const user = res.locals.oauth.token.User
109
110 if (!await isAbleToUploadVideo(user.id, video.getMaxQualityFile().size)) {
111 res.fail({
112 status: HttpStatusCode.PAYLOAD_TOO_LARGE_413,
113 message: 'The user video quota is exceeded with this video.',
114 type: ServerErrorCode.QUOTA_REACHED
115 })
116
117 return false
118 }
119
120 return true
121}
diff --git a/server/middlewares/validators/videos/video-playlists.ts b/server/middlewares/validators/videos/video-playlists.ts
index c872d045e..5ee7ee0ce 100644
--- a/server/middlewares/validators/videos/video-playlists.ts
+++ b/server/middlewares/validators/videos/video-playlists.ts
@@ -11,6 +11,7 @@ import {
11 isIdOrUUIDValid, 11 isIdOrUUIDValid,
12 isIdValid, 12 isIdValid,
13 isUUIDValid, 13 isUUIDValid,
14 toCompleteUUID,
14 toIntArray, 15 toIntArray,
15 toIntOrNull, 16 toIntOrNull,
16 toValueOrNull 17 toValueOrNull
@@ -25,12 +26,18 @@ import {
25import { isVideoImage } from '../../../helpers/custom-validators/videos' 26import { isVideoImage } from '../../../helpers/custom-validators/videos'
26import { cleanUpReqFiles } from '../../../helpers/express-utils' 27import { cleanUpReqFiles } from '../../../helpers/express-utils'
27import { logger } from '../../../helpers/logger' 28import { logger } from '../../../helpers/logger'
28import { doesVideoChannelIdExist, doesVideoExist, doesVideoPlaylistExist, VideoPlaylistFetchType } from '../../../helpers/middlewares'
29import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' 29import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
30import { VideoPlaylistElementModel } from '../../../models/video/video-playlist-element' 30import { VideoPlaylistElementModel } from '../../../models/video/video-playlist-element'
31import { MVideoPlaylist } from '../../../types/models/video/video-playlist' 31import { MVideoPlaylist } from '../../../types/models/video/video-playlist'
32import { authenticatePromiseIfNeeded } from '../../auth' 32import { authenticatePromiseIfNeeded } from '../../auth'
33import { areValidationErrors } from '../utils' 33import {
34 areValidationErrors,
35 doesVideoChannelIdExist,
36 doesVideoExist,
37 doesVideoPlaylistExist,
38 isValidPlaylistIdParam,
39 VideoPlaylistFetchType
40} from '../shared'
34 41
35const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([ 42const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
36 body('displayName') 43 body('displayName')
@@ -44,10 +51,13 @@ const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
44 const body: VideoPlaylistCreate = req.body 51 const body: VideoPlaylistCreate = req.body
45 if (body.videoChannelId && !await doesVideoChannelIdExist(body.videoChannelId, res)) return cleanUpReqFiles(req) 52 if (body.videoChannelId && !await doesVideoChannelIdExist(body.videoChannelId, res)) return cleanUpReqFiles(req)
46 53
47 if (body.privacy === VideoPlaylistPrivacy.PUBLIC && !body.videoChannelId) { 54 if (
55 !body.videoChannelId &&
56 (body.privacy === VideoPlaylistPrivacy.PUBLIC || body.privacy === VideoPlaylistPrivacy.UNLISTED)
57 ) {
48 cleanUpReqFiles(req) 58 cleanUpReqFiles(req)
49 return res.status(HttpStatusCode.BAD_REQUEST_400) 59
50 .json({ error: 'Cannot set "public" a playlist that is not assigned to a channel.' }) 60 return res.fail({ message: 'Cannot set "public" or "unlisted" a playlist that is not assigned to a channel.' })
51 } 61 }
52 62
53 return next() 63 return next()
@@ -55,8 +65,7 @@ const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
55]) 65])
56 66
57const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([ 67const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
58 param('playlistId') 68 isValidPlaylistIdParam('playlistId'),
59 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
60 69
61 body('displayName') 70 body('displayName')
62 .optional() 71 .optional()
@@ -85,14 +94,14 @@ const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
85 ) 94 )
86 ) { 95 ) {
87 cleanUpReqFiles(req) 96 cleanUpReqFiles(req)
88 return res.status(HttpStatusCode.BAD_REQUEST_400) 97
89 .json({ error: 'Cannot set "public" a playlist that is not assigned to a channel.' }) 98 return res.fail({ message: 'Cannot set "public" a playlist that is not assigned to a channel.' })
90 } 99 }
91 100
92 if (videoPlaylist.type === VideoPlaylistType.WATCH_LATER) { 101 if (videoPlaylist.type === VideoPlaylistType.WATCH_LATER) {
93 cleanUpReqFiles(req) 102 cleanUpReqFiles(req)
94 return res.status(HttpStatusCode.BAD_REQUEST_400) 103
95 .json({ error: 'Cannot update a watch later playlist.' }) 104 return res.fail({ message: 'Cannot update a watch later playlist.' })
96 } 105 }
97 106
98 if (body.videoChannelId && !await doesVideoChannelIdExist(body.videoChannelId, res)) return cleanUpReqFiles(req) 107 if (body.videoChannelId && !await doesVideoChannelIdExist(body.videoChannelId, res)) return cleanUpReqFiles(req)
@@ -102,8 +111,7 @@ const videoPlaylistsUpdateValidator = getCommonPlaylistEditAttributes().concat([
102]) 111])
103 112
104const videoPlaylistsDeleteValidator = [ 113const videoPlaylistsDeleteValidator = [
105 param('playlistId') 114 isValidPlaylistIdParam('playlistId'),
106 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
107 115
108 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 116 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
109 logger.debug('Checking videoPlaylistsDeleteValidator parameters', { parameters: req.params }) 117 logger.debug('Checking videoPlaylistsDeleteValidator parameters', { parameters: req.params })
@@ -114,8 +122,7 @@ const videoPlaylistsDeleteValidator = [
114 122
115 const videoPlaylist = getPlaylist(res) 123 const videoPlaylist = getPlaylist(res)
116 if (videoPlaylist.type === VideoPlaylistType.WATCH_LATER) { 124 if (videoPlaylist.type === VideoPlaylistType.WATCH_LATER) {
117 return res.status(HttpStatusCode.BAD_REQUEST_400) 125 return res.fail({ message: 'Cannot delete a watch later playlist.' })
118 .json({ error: 'Cannot delete a watch later playlist.' })
119 } 126 }
120 127
121 if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, videoPlaylist, UserRight.REMOVE_ANY_VIDEO_PLAYLIST, res)) { 128 if (!checkUserCanManageVideoPlaylist(res.locals.oauth.token.User, videoPlaylist, UserRight.REMOVE_ANY_VIDEO_PLAYLIST, res)) {
@@ -128,8 +135,7 @@ const videoPlaylistsDeleteValidator = [
128 135
129const videoPlaylistsGetValidator = (fetchType: VideoPlaylistFetchType) => { 136const videoPlaylistsGetValidator = (fetchType: VideoPlaylistFetchType) => {
130 return [ 137 return [
131 param('playlistId') 138 isValidPlaylistIdParam('playlistId'),
132 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
133 139
134 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 140 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
135 logger.debug('Checking videoPlaylistsGetValidator parameters', { parameters: req.params }) 141 logger.debug('Checking videoPlaylistsGetValidator parameters', { parameters: req.params })
@@ -144,7 +150,10 @@ const videoPlaylistsGetValidator = (fetchType: VideoPlaylistFetchType) => {
144 if (videoPlaylist.privacy === VideoPlaylistPrivacy.UNLISTED) { 150 if (videoPlaylist.privacy === VideoPlaylistPrivacy.UNLISTED) {
145 if (isUUIDValid(req.params.playlistId)) return next() 151 if (isUUIDValid(req.params.playlistId)) return next()
146 152
147 return res.status(HttpStatusCode.NOT_FOUND_404).end() 153 return res.fail({
154 status: HttpStatusCode.NOT_FOUND_404,
155 message: 'Playlist not found'
156 })
148 } 157 }
149 158
150 if (videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) { 159 if (videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) {
@@ -156,8 +165,10 @@ const videoPlaylistsGetValidator = (fetchType: VideoPlaylistFetchType) => {
156 !user || 165 !user ||
157 (videoPlaylist.OwnerAccount.id !== user.Account.id && !user.hasRight(UserRight.UPDATE_ANY_VIDEO_PLAYLIST)) 166 (videoPlaylist.OwnerAccount.id !== user.Account.id && !user.hasRight(UserRight.UPDATE_ANY_VIDEO_PLAYLIST))
158 ) { 167 ) {
159 return res.status(HttpStatusCode.FORBIDDEN_403) 168 return res.fail({
160 .json({ error: 'Cannot get this private video playlist.' }) 169 status: HttpStatusCode.FORBIDDEN_403,
170 message: 'Cannot get this private video playlist.'
171 })
161 } 172 }
162 173
163 return next() 174 return next()
@@ -181,9 +192,10 @@ const videoPlaylistsSearchValidator = [
181] 192]
182 193
183const videoPlaylistsAddVideoValidator = [ 194const videoPlaylistsAddVideoValidator = [
184 param('playlistId') 195 isValidPlaylistIdParam('playlistId'),
185 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'), 196
186 body('videoId') 197 body('videoId')
198 .customSanitizer(toCompleteUUID)
187 .custom(isIdOrUUIDValid).withMessage('Should have a valid video id/uuid'), 199 .custom(isIdOrUUIDValid).withMessage('Should have a valid video id/uuid'),
188 body('startTimestamp') 200 body('startTimestamp')
189 .optional() 201 .optional()
@@ -211,9 +223,9 @@ const videoPlaylistsAddVideoValidator = [
211] 223]
212 224
213const videoPlaylistsUpdateOrRemoveVideoValidator = [ 225const videoPlaylistsUpdateOrRemoveVideoValidator = [
214 param('playlistId') 226 isValidPlaylistIdParam('playlistId'),
215 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
216 param('playlistElementId') 227 param('playlistElementId')
228 .customSanitizer(toCompleteUUID)
217 .custom(isIdValid).withMessage('Should have an element id/uuid'), 229 .custom(isIdValid).withMessage('Should have an element id/uuid'),
218 body('startTimestamp') 230 body('startTimestamp')
219 .optional() 231 .optional()
@@ -233,10 +245,10 @@ const videoPlaylistsUpdateOrRemoveVideoValidator = [
233 245
234 const videoPlaylistElement = await VideoPlaylistElementModel.loadById(req.params.playlistElementId) 246 const videoPlaylistElement = await VideoPlaylistElementModel.loadById(req.params.playlistElementId)
235 if (!videoPlaylistElement) { 247 if (!videoPlaylistElement) {
236 res.status(HttpStatusCode.NOT_FOUND_404) 248 res.fail({
237 .json({ error: 'Video playlist element not found' }) 249 status: HttpStatusCode.NOT_FOUND_404,
238 .end() 250 message: 'Video playlist element not found'
239 251 })
240 return 252 return
241 } 253 }
242 res.locals.videoPlaylistElement = videoPlaylistElement 254 res.locals.videoPlaylistElement = videoPlaylistElement
@@ -248,8 +260,7 @@ const videoPlaylistsUpdateOrRemoveVideoValidator = [
248] 260]
249 261
250const videoPlaylistElementAPGetValidator = [ 262const videoPlaylistElementAPGetValidator = [
251 param('playlistId') 263 isValidPlaylistIdParam('playlistId'),
252 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
253 param('playlistElementId') 264 param('playlistElementId')
254 .custom(isIdValid).withMessage('Should have an playlist element id'), 265 .custom(isIdValid).withMessage('Should have an playlist element id'),
255 266
@@ -263,15 +274,18 @@ const videoPlaylistElementAPGetValidator = [
263 274
264 const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndElementIdForAP(playlistId, playlistElementId) 275 const videoPlaylistElement = await VideoPlaylistElementModel.loadByPlaylistAndElementIdForAP(playlistId, playlistElementId)
265 if (!videoPlaylistElement) { 276 if (!videoPlaylistElement) {
266 res.status(HttpStatusCode.NOT_FOUND_404) 277 res.fail({
267 .json({ error: 'Video playlist element not found' }) 278 status: HttpStatusCode.NOT_FOUND_404,
268 .end() 279 message: 'Video playlist element not found'
269 280 })
270 return 281 return
271 } 282 }
272 283
273 if (videoPlaylistElement.VideoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) { 284 if (videoPlaylistElement.VideoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) {
274 return res.status(HttpStatusCode.FORBIDDEN_403).end() 285 return res.fail({
286 status: HttpStatusCode.FORBIDDEN_403,
287 message: 'Cannot get this private video playlist.'
288 })
275 } 289 }
276 290
277 res.locals.videoPlaylistElementAP = videoPlaylistElement 291 res.locals.videoPlaylistElementAP = videoPlaylistElement
@@ -281,8 +295,7 @@ const videoPlaylistElementAPGetValidator = [
281] 295]
282 296
283const videoPlaylistsReorderVideosValidator = [ 297const videoPlaylistsReorderVideosValidator = [
284 param('playlistId') 298 isValidPlaylistIdParam('playlistId'),
285 .custom(isIdOrUUIDValid).withMessage('Should have a valid playlist id/uuid'),
286 body('startPosition') 299 body('startPosition')
287 .isInt({ min: 1 }).withMessage('Should have a valid start position'), 300 .isInt({ min: 1 }).withMessage('Should have a valid start position'),
288 body('insertAfterPosition') 301 body('insertAfterPosition')
@@ -307,18 +320,12 @@ const videoPlaylistsReorderVideosValidator = [
307 const reorderLength: number = req.body.reorderLength 320 const reorderLength: number = req.body.reorderLength
308 321
309 if (startPosition >= nextPosition || insertAfterPosition >= nextPosition) { 322 if (startPosition >= nextPosition || insertAfterPosition >= nextPosition) {
310 res.status(HttpStatusCode.BAD_REQUEST_400) 323 res.fail({ message: `Start position or insert after position exceed the playlist limits (max: ${nextPosition - 1})` })
311 .json({ error: `Start position or insert after position exceed the playlist limits (max: ${nextPosition - 1})` })
312 .end()
313
314 return 324 return
315 } 325 }
316 326
317 if (reorderLength && reorderLength + startPosition > nextPosition) { 327 if (reorderLength && reorderLength + startPosition > nextPosition) {
318 res.status(HttpStatusCode.BAD_REQUEST_400) 328 res.fail({ message: `Reorder length with this start position exceeds the playlist limits (max: ${nextPosition - startPosition})` })
319 .json({ error: `Reorder length with this start position exceeds the playlist limits (max: ${nextPosition - startPosition})` })
320 .end()
321
322 return 329 return
323 } 330 }
324 331
@@ -401,10 +408,10 @@ function getCommonPlaylistEditAttributes () {
401 408
402function checkUserCanManageVideoPlaylist (user: MUserAccountId, videoPlaylist: MVideoPlaylist, right: UserRight, res: express.Response) { 409function checkUserCanManageVideoPlaylist (user: MUserAccountId, videoPlaylist: MVideoPlaylist, right: UserRight, res: express.Response) {
403 if (videoPlaylist.isOwned() === false) { 410 if (videoPlaylist.isOwned() === false) {
404 res.status(HttpStatusCode.FORBIDDEN_403) 411 res.fail({
405 .json({ error: 'Cannot manage video playlist of another server.' }) 412 status: HttpStatusCode.FORBIDDEN_403,
406 .end() 413 message: 'Cannot manage video playlist of another server.'
407 414 })
408 return false 415 return false
409 } 416 }
410 417
@@ -412,10 +419,10 @@ function checkUserCanManageVideoPlaylist (user: MUserAccountId, videoPlaylist: M
412 // The user can delete it if s/he is an admin 419 // The user can delete it if s/he is an admin
413 // Or if s/he is the video playlist's owner 420 // Or if s/he is the video playlist's owner
414 if (user.hasRight(right) === false && videoPlaylist.ownerAccountId !== user.Account.id) { 421 if (user.hasRight(right) === false && videoPlaylist.ownerAccountId !== user.Account.id) {
415 res.status(HttpStatusCode.FORBIDDEN_403) 422 res.fail({
416 .json({ error: 'Cannot manage video playlist of another user' }) 423 status: HttpStatusCode.FORBIDDEN_403,
417 .end() 424 message: 'Cannot manage video playlist of another user'
418 425 })
419 return false 426 return false
420 } 427 }
421 428
diff --git a/server/middlewares/validators/videos/video-rates.ts b/server/middlewares/validators/videos/video-rates.ts
index 01bdef25f..5d5dfb222 100644
--- a/server/middlewares/validators/videos/video-rates.ts
+++ b/server/middlewares/validators/videos/video-rates.ts
@@ -1,18 +1,18 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param, query } from 'express-validator' 2import { body, param, query } from 'express-validator'
3import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' 3import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
4import { VideoRateType } from '../../../../shared/models/videos'
5import { isAccountNameValid } from '../../../helpers/custom-validators/accounts'
6import { isIdValid } from '../../../helpers/custom-validators/misc'
4import { isRatingValid } from '../../../helpers/custom-validators/video-rates' 7import { isRatingValid } from '../../../helpers/custom-validators/video-rates'
5import { isVideoRatingTypeValid } from '../../../helpers/custom-validators/videos' 8import { isVideoRatingTypeValid } from '../../../helpers/custom-validators/videos'
6import { logger } from '../../../helpers/logger' 9import { logger } from '../../../helpers/logger'
7import { areValidationErrors } from '../utils'
8import { AccountVideoRateModel } from '../../../models/account/account-video-rate' 10import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
9import { VideoRateType } from '../../../../shared/models/videos' 11import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared'
10import { isAccountNameValid } from '../../../helpers/custom-validators/accounts'
11import { doesVideoExist } from '../../../helpers/middlewares'
12import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
13 12
14const videoUpdateRateValidator = [ 13const videoUpdateRateValidator = [
15 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 14 isValidVideoIdParam('id'),
15
16 body('rating').custom(isVideoRatingTypeValid).withMessage('Should have a valid rate type'), 16 body('rating').custom(isVideoRatingTypeValid).withMessage('Should have a valid rate type'),
17 17
18 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 18 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
@@ -37,8 +37,10 @@ const getAccountVideoRateValidatorFactory = function (rateType: VideoRateType) {
37 37
38 const rate = await AccountVideoRateModel.loadLocalAndPopulateVideo(rateType, req.params.name, +req.params.videoId) 38 const rate = await AccountVideoRateModel.loadLocalAndPopulateVideo(rateType, req.params.name, +req.params.videoId)
39 if (!rate) { 39 if (!rate) {
40 return res.status(HttpStatusCode.NOT_FOUND_404) 40 return res.fail({
41 .json({ error: 'Video rate not found' }) 41 status: HttpStatusCode.NOT_FOUND_404,
42 message: 'Video rate not found'
43 })
42 } 44 }
43 45
44 res.locals.accountVideoRate = rate 46 res.locals.accountVideoRate = rate
diff --git a/server/middlewares/validators/videos/video-shares.ts b/server/middlewares/validators/videos/video-shares.ts
index f0d8e0c36..7e54b6fc0 100644
--- a/server/middlewares/validators/videos/video-shares.ts
+++ b/server/middlewares/validators/videos/video-shares.ts
@@ -1,15 +1,16 @@
1import * as express from 'express' 1import * as express from 'express'
2import { param } from 'express-validator' 2import { param } from 'express-validator'
3import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc' 3import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
4import { isIdValid } from '../../../helpers/custom-validators/misc'
4import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
5import { VideoShareModel } from '../../../models/video/video-share' 6import { VideoShareModel } from '../../../models/video/video-share'
6import { areValidationErrors } from '../utils' 7import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared'
7import { doesVideoExist } from '../../../helpers/middlewares'
8import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
9 8
10const videosShareValidator = [ 9const videosShareValidator = [
11 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 10 isValidVideoIdParam('id'),
12 param('actorId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid actor id'), 11
12 param('actorId')
13 .custom(isIdValid).not().isEmpty().withMessage('Should have a valid actor id'),
13 14
14 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 15 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
15 logger.debug('Checking videoShare parameters', { parameters: req.params }) 16 logger.debug('Checking videoShare parameters', { parameters: req.params })
diff --git a/server/middlewares/validators/videos/video-watch.ts b/server/middlewares/validators/videos/video-watch.ts
index 29ce0dab6..43306f7cd 100644
--- a/server/middlewares/validators/videos/video-watch.ts
+++ b/server/middlewares/validators/videos/video-watch.ts
@@ -1,13 +1,13 @@
1import { body, param } from 'express-validator'
2import * as express from 'express' 1import * as express from 'express'
3import { isIdOrUUIDValid, toIntOrNull } from '../../../helpers/custom-validators/misc' 2import { body } from 'express-validator'
4import { areValidationErrors } from '../utils'
5import { logger } from '../../../helpers/logger'
6import { doesVideoExist } from '../../../helpers/middlewares'
7import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 3import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
4import { toIntOrNull } from '../../../helpers/custom-validators/misc'
5import { logger } from '../../../helpers/logger'
6import { areValidationErrors, doesVideoExist, isValidVideoIdParam } from '../shared'
8 7
9const videoWatchingValidator = [ 8const videoWatchingValidator = [
10 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 9 isValidVideoIdParam('videoId'),
10
11 body('currentTime') 11 body('currentTime')
12 .customSanitizer(toIntOrNull) 12 .customSanitizer(toIntOrNull)
13 .isInt().withMessage('Should have correct current time'), 13 .isInt().withMessage('Should have correct current time'),
@@ -21,7 +21,10 @@ const videoWatchingValidator = [
21 const user = res.locals.oauth.token.User 21 const user = res.locals.oauth.token.User
22 if (user.videosHistoryEnabled === false) { 22 if (user.videosHistoryEnabled === false) {
23 logger.warn('Cannot set videos to watch by user %d: videos history is disabled.', user.id) 23 logger.warn('Cannot set videos to watch by user %d: videos history is disabled.', user.id)
24 return res.status(HttpStatusCode.CONFLICT_409).end() 24 return res.fail({
25 status: HttpStatusCode.CONFLICT_409,
26 message: 'Video history is disabled'
27 })
25 } 28 }
26 29
27 return next() 30 return next()
diff --git a/server/middlewares/validators/videos/videos.ts b/server/middlewares/validators/videos/videos.ts
index d26bcd4a6..49e10e2b5 100644
--- a/server/middlewares/validators/videos/videos.ts
+++ b/server/middlewares/validators/videos/videos.ts
@@ -4,16 +4,14 @@ import { getResumableUploadPath } from '@server/helpers/upload'
4import { isAbleToUploadVideo } from '@server/lib/user' 4import { isAbleToUploadVideo } from '@server/lib/user'
5import { getServerActor } from '@server/models/application/application' 5import { getServerActor } from '@server/models/application/application'
6import { ExpressPromiseHandler } from '@server/types/express' 6import { ExpressPromiseHandler } from '@server/types/express'
7import { MUserAccountId, MVideoWithRights } from '@server/types/models' 7import { MUserAccountId, MVideoFullLight } from '@server/types/models'
8import { ServerErrorCode, UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared' 8import { ServerErrorCode, UserRight, VideoPrivacy } from '../../../../shared'
9import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' 9import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
10import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/video-change-ownership-accept.model'
11import { 10import {
12 exists, 11 exists,
13 isBooleanValid, 12 isBooleanValid,
14 isDateValid, 13 isDateValid,
15 isFileFieldValid, 14 isFileFieldValid,
16 isIdOrUUIDValid,
17 isIdValid, 15 isIdValid,
18 isUUIDValid, 16 isUUIDValid,
19 toArray, 17 toArray,
@@ -22,7 +20,6 @@ import {
22 toValueOrNull 20 toValueOrNull
23} from '../../../helpers/custom-validators/misc' 21} from '../../../helpers/custom-validators/misc'
24import { isBooleanBothQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search' 22import { isBooleanBothQueryValid, isNumberArray, isStringArray } from '../../../helpers/custom-validators/search'
25import { checkUserCanTerminateOwnershipChange, doesChangeVideoOwnershipExist } from '../../../helpers/custom-validators/video-ownership'
26import { 23import {
27 isScheduleVideoUpdatePrivacyValid, 24 isScheduleVideoUpdatePrivacyValid,
28 isVideoCategoryValid, 25 isVideoCategoryValid,
@@ -42,22 +39,22 @@ import {
42import { cleanUpReqFiles } from '../../../helpers/express-utils' 39import { cleanUpReqFiles } from '../../../helpers/express-utils'
43import { getDurationFromVideoFile } from '../../../helpers/ffprobe-utils' 40import { getDurationFromVideoFile } from '../../../helpers/ffprobe-utils'
44import { logger } from '../../../helpers/logger' 41import { logger } from '../../../helpers/logger'
45import {
46 checkUserCanManageVideo,
47 doesVideoChannelOfAccountExist,
48 doesVideoExist,
49 doesVideoFileOfVideoExist
50} from '../../../helpers/middlewares'
51import { deleteFileAndCatch } from '../../../helpers/utils' 42import { deleteFileAndCatch } from '../../../helpers/utils'
52import { getVideoWithAttributes } from '../../../helpers/video' 43import { getVideoWithAttributes } from '../../../helpers/video'
53import { CONFIG } from '../../../initializers/config' 44import { CONFIG } from '../../../initializers/config'
54import { CONSTRAINTS_FIELDS, OVERVIEWS } from '../../../initializers/constants' 45import { CONSTRAINTS_FIELDS, OVERVIEWS } from '../../../initializers/constants'
55import { isLocalVideoAccepted } from '../../../lib/moderation' 46import { isLocalVideoAccepted } from '../../../lib/moderation'
56import { Hooks } from '../../../lib/plugins/hooks' 47import { Hooks } from '../../../lib/plugins/hooks'
57import { AccountModel } from '../../../models/account/account'
58import { VideoModel } from '../../../models/video/video' 48import { VideoModel } from '../../../models/video/video'
59import { authenticatePromiseIfNeeded } from '../../auth' 49import { authenticatePromiseIfNeeded } from '../../auth'
60import { areValidationErrors } from '../utils' 50import {
51 areValidationErrors,
52 checkUserCanManageVideo,
53 doesVideoChannelOfAccountExist,
54 doesVideoExist,
55 doesVideoFileOfVideoExist,
56 isValidVideoIdParam
57} from '../shared'
61 58
62const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([ 59const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([
63 body('videofile') 60 body('videofile')
@@ -65,8 +62,9 @@ const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([
65 .withMessage('Should have a file'), 62 .withMessage('Should have a file'),
66 body('name') 63 body('name')
67 .trim() 64 .trim()
68 .custom(isVideoNameValid) 65 .custom(isVideoNameValid).withMessage(
69 .withMessage('Should have a valid name'), 66 `Should have a video name between ${CONSTRAINTS_FIELDS.VIDEOS.NAME.min} and ${CONSTRAINTS_FIELDS.VIDEOS.NAME.max} characters long`
67 ),
70 body('channelId') 68 body('channelId')
71 .customSanitizer(toIntOrNull) 69 .customSanitizer(toIntOrNull)
72 .custom(isIdValid).withMessage('Should have correct video channel id'), 70 .custom(isIdValid).withMessage('Should have correct video channel id'),
@@ -87,9 +85,11 @@ const videosAddLegacyValidator = getCommonVideoEditAttributes().concat([
87 if (!videoFile.duration) await addDurationToVideo(videoFile) 85 if (!videoFile.duration) await addDurationToVideo(videoFile)
88 } catch (err) { 86 } catch (err) {
89 logger.error('Invalid input file in videosAddLegacyValidator.', { err }) 87 logger.error('Invalid input file in videosAddLegacyValidator.', { err })
90 res.status(HttpStatusCode.UNPROCESSABLE_ENTITY_422)
91 .json({ error: 'Video file unreadable.' })
92 88
89 res.fail({
90 status: HttpStatusCode.UNPROCESSABLE_ENTITY_422,
91 message: 'Video file unreadable.'
92 })
93 return cleanUpReqFiles(req) 93 return cleanUpReqFiles(req)
94 } 94 }
95 95
@@ -117,9 +117,11 @@ const videosAddResumableValidator = [
117 if (!file.duration) await addDurationToVideo(file) 117 if (!file.duration) await addDurationToVideo(file)
118 } catch (err) { 118 } catch (err) {
119 logger.error('Invalid input file in videosAddResumableValidator.', { err }) 119 logger.error('Invalid input file in videosAddResumableValidator.', { err })
120 res.status(HttpStatusCode.UNPROCESSABLE_ENTITY_422)
121 .json({ error: 'Video file unreadable.' })
122 120
121 res.fail({
122 status: HttpStatusCode.UNPROCESSABLE_ENTITY_422,
123 message: 'Video file unreadable.'
124 })
123 return cleanup() 125 return cleanup()
124 } 126 }
125 127
@@ -146,8 +148,9 @@ const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([
146 .withMessage('Should have a valid filename'), 148 .withMessage('Should have a valid filename'),
147 body('name') 149 body('name')
148 .trim() 150 .trim()
149 .custom(isVideoNameValid) 151 .custom(isVideoNameValid).withMessage(
150 .withMessage('Should have a valid name'), 152 `Should have a video name between ${CONSTRAINTS_FIELDS.VIDEOS.NAME.min} and ${CONSTRAINTS_FIELDS.VIDEOS.NAME.max} characters long`
153 ),
151 body('channelId') 154 body('channelId')
152 .customSanitizer(toIntOrNull) 155 .customSanitizer(toIntOrNull)
153 .custom(isIdValid).withMessage('Should have correct video channel id'), 156 .custom(isIdValid).withMessage('Should have correct video channel id'),
@@ -192,11 +195,14 @@ const videosAddResumableInitValidator = getCommonVideoEditAttributes().concat([
192]) 195])
193 196
194const videosUpdateValidator = getCommonVideoEditAttributes().concat([ 197const videosUpdateValidator = getCommonVideoEditAttributes().concat([
195 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 198 isValidVideoIdParam('id'),
199
196 body('name') 200 body('name')
197 .optional() 201 .optional()
198 .trim() 202 .trim()
199 .custom(isVideoNameValid).withMessage('Should have a valid name'), 203 .custom(isVideoNameValid).withMessage(
204 `Should have a video name between ${CONSTRAINTS_FIELDS.VIDEOS.NAME.min} and ${CONSTRAINTS_FIELDS.VIDEOS.NAME.max} characters long`
205 ),
200 body('channelId') 206 body('channelId')
201 .optional() 207 .optional()
202 .customSanitizer(toIntOrNull) 208 .customSanitizer(toIntOrNull)
@@ -238,20 +244,22 @@ async function checkVideoFollowConstraints (req: express.Request, res: express.R
238 const serverActor = await getServerActor() 244 const serverActor = await getServerActor()
239 if (await VideoModel.checkVideoHasInstanceFollow(video.id, serverActor.id) === true) return next() 245 if (await VideoModel.checkVideoHasInstanceFollow(video.id, serverActor.id) === true) return next()
240 246
241 return res.status(HttpStatusCode.FORBIDDEN_403) 247 return res.fail({
242 .json({ 248 status: HttpStatusCode.FORBIDDEN_403,
243 errorCode: ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS, 249 message: 'Cannot get this video regarding follow constraints',
244 error: 'Cannot get this video regarding follow constraints.', 250 type: ServerErrorCode.DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS,
245 originUrl: video.url 251 data: {
246 }) 252 originUrl: video.url
253 }
254 })
247} 255}
248 256
249const videosCustomGetValidator = ( 257const videosCustomGetValidator = (
250 fetchType: 'all' | 'only-video' | 'only-video-with-rights' | 'only-immutable-attributes', 258 fetchType: 'for-api' | 'all' | 'only-video' | 'only-immutable-attributes',
251 authenticateInQuery = false 259 authenticateInQuery = false
252) => { 260) => {
253 return [ 261 return [
254 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 262 isValidVideoIdParam('id'),
255 263
256 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 264 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
257 logger.debug('Checking videosGet parameters', { parameters: req.params }) 265 logger.debug('Checking videosGet parameters', { parameters: req.params })
@@ -262,7 +270,7 @@ const videosCustomGetValidator = (
262 // Controllers does not need to check video rights 270 // Controllers does not need to check video rights
263 if (fetchType === 'only-immutable-attributes') return next() 271 if (fetchType === 'only-immutable-attributes') return next()
264 272
265 const video = getVideoWithAttributes(res) as MVideoWithRights 273 const video = getVideoWithAttributes(res) as MVideoFullLight
266 274
267 // Video private or blacklisted 275 // Video private or blacklisted
268 if (video.requiresAuth()) { 276 if (video.requiresAuth()) {
@@ -270,10 +278,12 @@ const videosCustomGetValidator = (
270 278
271 const user = res.locals.oauth ? res.locals.oauth.token.User : null 279 const user = res.locals.oauth ? res.locals.oauth.token.User : null
272 280
273 // Only the owner or a user that have blacklist rights can see the video 281 // Only the owner or a user that have blocklist rights can see the video
274 if (!user || !user.canGetVideo(video)) { 282 if (!user || !user.canGetVideo(video)) {
275 return res.status(HttpStatusCode.FORBIDDEN_403) 283 return res.fail({
276 .json({ error: 'Cannot get this private/internal or blacklisted video.' }) 284 status: HttpStatusCode.FORBIDDEN_403,
285 message: 'Cannot get this private/internal or blocklisted video'
286 })
277 } 287 }
278 288
279 return next() 289 return next()
@@ -287,7 +297,10 @@ const videosCustomGetValidator = (
287 if (isUUIDValid(req.params.id)) return next() 297 if (isUUIDValid(req.params.id)) return next()
288 298
289 // Don't leak this unlisted video 299 // Don't leak this unlisted video
290 return res.status(HttpStatusCode.NOT_FOUND_404).end() 300 return res.fail({
301 status: HttpStatusCode.NOT_FOUND_404,
302 message: 'Video not found'
303 })
291 } 304 }
292 } 305 }
293 ] 306 ]
@@ -297,8 +310,10 @@ const videosGetValidator = videosCustomGetValidator('all')
297const videosDownloadValidator = videosCustomGetValidator('all', true) 310const videosDownloadValidator = videosCustomGetValidator('all', true)
298 311
299const videoFileMetadataGetValidator = getCommonVideoEditAttributes().concat([ 312const videoFileMetadataGetValidator = getCommonVideoEditAttributes().concat([
300 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 313 isValidVideoIdParam('id'),
301 param('videoFileId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid videoFileId'), 314
315 param('videoFileId')
316 .custom(isIdValid).not().isEmpty().withMessage('Should have a valid videoFileId'),
302 317
303 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 318 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
304 logger.debug('Checking videoFileMetadataGet parameters', { parameters: req.params }) 319 logger.debug('Checking videoFileMetadataGet parameters', { parameters: req.params })
@@ -311,7 +326,7 @@ const videoFileMetadataGetValidator = getCommonVideoEditAttributes().concat([
311]) 326])
312 327
313const videosRemoveValidator = [ 328const videosRemoveValidator = [
314 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'), 329 isValidVideoIdParam('id'),
315 330
316 async (req: express.Request, res: express.Response, next: express.NextFunction) => { 331 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
317 logger.debug('Checking videosRemove parameters', { parameters: req.params }) 332 logger.debug('Checking videosRemove parameters', { parameters: req.params })
@@ -326,74 +341,6 @@ const videosRemoveValidator = [
326 } 341 }
327] 342]
328 343
329const videosChangeOwnershipValidator = [
330 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
331
332 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
333 logger.debug('Checking changeOwnership parameters', { parameters: req.params })
334
335 if (areValidationErrors(req, res)) return
336 if (!await doesVideoExist(req.params.videoId, res)) return
337
338 // Check if the user who did the request is able to change the ownership of the video
339 if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.videoAll, UserRight.CHANGE_VIDEO_OWNERSHIP, res)) return
340
341 const nextOwner = await AccountModel.loadLocalByName(req.body.username)
342 if (!nextOwner) {
343 res.status(HttpStatusCode.BAD_REQUEST_400)
344 .json({ error: 'Changing video ownership to a remote account is not supported yet' })
345
346 return
347 }
348 res.locals.nextOwner = nextOwner
349
350 return next()
351 }
352]
353
354const videosTerminateChangeOwnershipValidator = [
355 param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
356
357 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
358 logger.debug('Checking changeOwnership parameters', { parameters: req.params })
359
360 if (areValidationErrors(req, res)) return
361 if (!await doesChangeVideoOwnershipExist(req.params.id, res)) return
362
363 // Check if the user who did the request is able to change the ownership of the video
364 if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return
365
366 const videoChangeOwnership = res.locals.videoChangeOwnership
367
368 if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) {
369 res.status(HttpStatusCode.FORBIDDEN_403)
370 .json({ error: 'Ownership already accepted or refused' })
371 return
372 }
373
374 return next()
375 }
376]
377
378const videosAcceptChangeOwnershipValidator = [
379 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
380 const body = req.body as VideoChangeOwnershipAccept
381 if (!await doesVideoChannelOfAccountExist(body.channelId, res.locals.oauth.token.User, res)) return
382
383 const user = res.locals.oauth.token.User
384 const videoChangeOwnership = res.locals.videoChangeOwnership
385 const isAble = await isAbleToUploadVideo(user.id, videoChangeOwnership.Video.getMaxQualityFile().size)
386 if (isAble === false) {
387 res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413)
388 .json({ error: 'The user video quota is exceeded with this video.' })
389
390 return
391 }
392
393 return next()
394 }
395]
396
397const videosOverviewValidator = [ 344const videosOverviewValidator = [
398 query('page') 345 query('page')
399 .optional() 346 .optional()
@@ -455,7 +402,11 @@ function getCommonVideoEditAttributes () {
455 body('tags') 402 body('tags')
456 .optional() 403 .optional()
457 .customSanitizer(toValueOrNull) 404 .customSanitizer(toValueOrNull)
458 .custom(isVideoTagsValid).withMessage('Should have correct tags'), 405 .custom(isVideoTagsValid)
406 .withMessage(
407 `Should have an array of up to ${CONSTRAINTS_FIELDS.VIDEOS.TAGS.max} tags between ` +
408 `${CONSTRAINTS_FIELDS.VIDEOS.TAG.min} and ${CONSTRAINTS_FIELDS.VIDEOS.TAG.max} characters each`
409 ),
459 body('commentsEnabled') 410 body('commentsEnabled')
460 .optional() 411 .optional()
461 .customSanitizer(toBooleanOrNull) 412 .customSanitizer(toBooleanOrNull)
@@ -473,7 +424,7 @@ function getCommonVideoEditAttributes () {
473 .customSanitizer(toValueOrNull), 424 .customSanitizer(toValueOrNull),
474 body('scheduleUpdate.updateAt') 425 body('scheduleUpdate.updateAt')
475 .optional() 426 .optional()
476 .custom(isDateValid).withMessage('Should have a valid schedule update date'), 427 .custom(isDateValid).withMessage('Should have a schedule update date that conforms to ISO 8601'),
477 body('scheduleUpdate.privacy') 428 body('scheduleUpdate.privacy')
478 .optional() 429 .optional()
479 .customSanitizer(toIntOrNull) 430 .customSanitizer(toIntOrNull)
@@ -530,9 +481,10 @@ const commonVideosFiltersValidator = [
530 (req.query.filter === 'all-local' || req.query.filter === 'all') && 481 (req.query.filter === 'all-local' || req.query.filter === 'all') &&
531 (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false) 482 (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) === false)
532 ) { 483 ) {
533 res.status(HttpStatusCode.UNAUTHORIZED_401) 484 res.fail({
534 .json({ error: 'You are not allowed to see all local videos.' }) 485 status: HttpStatusCode.UNAUTHORIZED_401,
535 486 message: 'You are not allowed to see all local videos.'
487 })
536 return 488 return
537 } 489 }
538 490
@@ -555,10 +507,6 @@ export {
555 videosCustomGetValidator, 507 videosCustomGetValidator,
556 videosRemoveValidator, 508 videosRemoveValidator,
557 509
558 videosChangeOwnershipValidator,
559 videosTerminateChangeOwnershipValidator,
560 videosAcceptChangeOwnershipValidator,
561
562 getCommonVideoEditAttributes, 510 getCommonVideoEditAttributes,
563 511
564 commonVideosFiltersValidator, 512 commonVideosFiltersValidator,
@@ -573,9 +521,7 @@ function areErrorsInScheduleUpdate (req: express.Request, res: express.Response)
573 if (!req.body.scheduleUpdate.updateAt) { 521 if (!req.body.scheduleUpdate.updateAt) {
574 logger.warn('Invalid parameters: scheduleUpdate.updateAt is mandatory.') 522 logger.warn('Invalid parameters: scheduleUpdate.updateAt is mandatory.')
575 523
576 res.status(HttpStatusCode.BAD_REQUEST_400) 524 res.fail({ message: 'Schedule update at is mandatory.' })
577 .json({ error: 'Schedule update at is mandatory.' })
578
579 return true 525 return true
580 } 526 }
581 } 527 }
@@ -597,26 +543,29 @@ async function commonVideoChecksPass (parameters: {
597 if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return false 543 if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return false
598 544
599 if (!isVideoFileMimeTypeValid(files)) { 545 if (!isVideoFileMimeTypeValid(files)) {
600 res.status(HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415) 546 res.fail({
601 .json({ 547 status: HttpStatusCode.UNSUPPORTED_MEDIA_TYPE_415,
602 error: 'This file is not supported. Please, make sure it is of the following type: ' + 548 message: 'This file is not supported. Please, make sure it is of the following type: ' +
603 CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ') 549 CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ')
604 }) 550 })
605
606 return false 551 return false
607 } 552 }
608 553
609 if (!isVideoFileSizeValid(videoFileSize.toString())) { 554 if (!isVideoFileSizeValid(videoFileSize.toString())) {
610 res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413) 555 res.fail({
611 .json({ error: 'This file is too large. It exceeds the maximum file size authorized.' }) 556 status: HttpStatusCode.PAYLOAD_TOO_LARGE_413,
612 557 message: 'This file is too large. It exceeds the maximum file size authorized.',
558 type: ServerErrorCode.MAX_FILE_SIZE_REACHED
559 })
613 return false 560 return false
614 } 561 }
615 562
616 if (await isAbleToUploadVideo(user.id, videoFileSize) === false) { 563 if (await isAbleToUploadVideo(user.id, videoFileSize) === false) {
617 res.status(HttpStatusCode.PAYLOAD_TOO_LARGE_413) 564 res.fail({
618 .json({ error: 'The user video quota is exceeded with this video.' }) 565 status: HttpStatusCode.PAYLOAD_TOO_LARGE_413,
619 566 message: 'The user video quota is exceeded with this video.',
567 type: ServerErrorCode.QUOTA_REACHED
568 })
620 return false 569 return false
621 } 570 }
622 571
@@ -642,9 +591,10 @@ export async function isVideoAccepted (
642 591
643 if (!acceptedResult || acceptedResult.accepted !== true) { 592 if (!acceptedResult || acceptedResult.accepted !== true) {
644 logger.info('Refused local video.', { acceptedResult, acceptParameters }) 593 logger.info('Refused local video.', { acceptedResult, acceptParameters })
645 res.status(HttpStatusCode.FORBIDDEN_403) 594 res.fail({
646 .json({ error: acceptedResult.errorMessage || 'Refused local video' }) 595 status: HttpStatusCode.FORBIDDEN_403,
647 596 message: acceptedResult.errorMessage || 'Refused local video'
597 })
648 return false 598 return false
649 } 599 }
650 600