1 import { values } from 'lodash'
2 import * as validator from 'validator'
3 import * as Promise from 'bluebird'
4 import * as express from 'express'
5 import 'express-validator'
16 } from '../../initializers'
17 import { isUserUsernameValid } from './users'
18 import { isArray, exists } from './misc'
19 import { VideoInstance } from '../../models'
20 import { logger } from '../../helpers'
21 import { VideoRateType } from '../../../shared'
23 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
24 const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
25 const VIDEO_EVENTS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_EVENTS
27 function isVideoCategoryValid (value: number) {
28 return VIDEO_CATEGORIES[value] !== undefined
31 // Maybe we don't know the remote category, but that doesn't matter
32 function isRemoteVideoCategoryValid (value: string) {
33 return validator.isInt('' + value)
36 function isVideoLicenceValid (value: number) {
37 return VIDEO_LICENCES[value] !== undefined
40 function isVideoPrivacyValid (value: string) {
41 return VIDEO_PRIVACIES[value] !== undefined
44 // Maybe we don't know the remote privacy setting, but that doesn't matter
45 function isRemoteVideoPrivacyValid (value: string) {
46 return validator.isInt('' + value)
49 // Maybe we don't know the remote licence, but that doesn't matter
50 function isRemoteVideoLicenceValid (value: string) {
51 return validator.isInt('' + value)
54 function isVideoLanguageValid (value: number) {
55 return value === null || VIDEO_LANGUAGES[value] !== undefined
58 // Maybe we don't know the remote language, but that doesn't matter
59 function isRemoteVideoLanguageValid (value: string) {
60 return validator.isInt('' + value)
63 function isVideoNSFWValid (value: any) {
64 return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
67 function isVideoTruncatedDescriptionValid (value: string) {
68 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
71 function isVideoDescriptionValid (value: string) {
72 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
75 function isVideoDurationValid (value: string) {
76 // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
77 return exists(value) &&
78 typeof value === 'string' &&
79 value.startsWith('PT') &&
80 value.endsWith('S') &&
81 validator.isInt(value.replace(/[^0-9]+/, ''), VIDEOS_CONSTRAINTS_FIELDS.DURATION)
84 function isVideoNameValid (value: string) {
85 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
88 function isVideoTagValid (tag: string) {
89 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
92 function isVideoTagsValid (tags: string[]) {
93 return isArray(tags) &&
94 validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
95 tags.every(tag => isVideoTagValid(tag))
98 function isVideoThumbnailValid (value: string) {
99 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL)
102 function isVideoThumbnailDataValid (value: string) {
103 return exists(value) && validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA)
106 function isVideoAbuseReasonValid (value: string) {
107 return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
110 function isVideoAbuseReporterUsernameValid (value: string) {
111 return isUserUsernameValid(value)
114 function isVideoViewsValid (value: string) {
115 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
118 function isVideoLikesValid (value: string) {
119 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.LIKES)
122 function isVideoDislikesValid (value: string) {
123 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DISLIKES)
126 function isVideoEventCountValid (value: string) {
127 return exists(value) && validator.isInt(value + '', VIDEO_EVENTS_CONSTRAINTS_FIELDS.COUNT)
130 function isVideoRatingTypeValid (value: string) {
131 return values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
134 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
136 if (!files) return false
137 if (isArray(files)) return false
139 // Should have videofile file
140 const videofile = files['videofile']
141 if (!videofile || videofile.length === 0) return false
143 // The file should exist
144 const file = videofile[0]
145 if (!file || !file.originalname) return false
147 return new RegExp('^video/(webm|mp4|ogg)$', 'i').test(file.mimetype)
150 function isVideoFileSizeValid (value: string) {
151 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
154 function isVideoFileResolutionValid (value: string) {
155 return exists(value) && validator.isInt(value + '')
158 function isVideoFileExtnameValid (value: string) {
159 return VIDEOS_CONSTRAINTS_FIELDS.EXTNAME.indexOf(value) !== -1
162 function isVideoFileInfoHashValid (value: string) {
163 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
166 function checkVideoExists (id: string, res: express.Response, callback: () => void) {
167 let promise: Promise<VideoInstance>
168 if (validator.isInt(id)) {
169 promise = db.Video.loadAndPopulateAuthorAndPodAndTags(+id)
171 promise = db.Video.loadByUUIDAndPopulateAuthorAndPodAndTags(id)
174 promise.then(video => {
176 return res.status(404)
177 .json({ error: 'Video not found' })
181 res.locals.video = video
185 logger.error('Error in video request validator.', err)
186 return res.sendStatus(500)
190 // ---------------------------------------------------------------------------
193 isVideoCategoryValid,
195 isVideoLanguageValid,
197 isVideoTruncatedDescriptionValid,
198 isVideoDescriptionValid,
199 isVideoDurationValid,
200 isVideoFileInfoHashValid,
203 isVideoThumbnailValid,
204 isVideoThumbnailDataValid,
205 isVideoFileExtnameValid,
206 isVideoAbuseReasonValid,
207 isVideoAbuseReporterUsernameValid,
211 isVideoRatingTypeValid,
212 isVideoDislikesValid,
213 isVideoEventCountValid,
214 isVideoFileSizeValid,
216 isRemoteVideoPrivacyValid,
217 isVideoFileResolutionValid,
220 isRemoteVideoCategoryValid,
221 isRemoteVideoLicenceValid,
222 isRemoteVideoLanguageValid