1 import { Response } from 'express'
2 import 'express-validator'
3 import { values } from 'lodash'
5 import * as validator from 'validator'
6 import { UserRight, VideoFilter, VideoPrivacy, VideoRateType } from '../../../shared'
8 CONSTRAINTS_FIELDS, MIMETYPES,
14 } from '../../initializers/constants'
15 import { VideoModel } from '../../models/video/video'
16 import { exists, isArray, isDateValid, isFileValid } from './misc'
17 import { VideoChannelModel } from '../../models/video/video-channel'
18 import { UserModel } from '../../models/account/user'
19 import * as magnetUtil from 'magnet-uri'
20 import { fetchVideo, VideoFetchType } from '../video'
22 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
24 function isVideoFilterValid (filter: VideoFilter) {
25 return filter === 'local' || filter === 'all-local'
28 function isVideoCategoryValid (value: any) {
29 return value === null || VIDEO_CATEGORIES[ value ] !== undefined
32 function isVideoStateValid (value: any) {
33 return exists(value) && VIDEO_STATES[ value ] !== undefined
36 function isVideoLicenceValid (value: any) {
37 return value === null || VIDEO_LICENCES[ value ] !== undefined
40 function isVideoLanguageValid (value: any) {
41 return value === null ||
42 (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
45 function isVideoDurationValid (value: string) {
46 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
49 function isVideoTruncatedDescriptionValid (value: string) {
50 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
53 function isVideoDescriptionValid (value: string) {
54 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
57 function isVideoSupportValid (value: string) {
58 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
61 function isVideoNameValid (value: string) {
62 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
65 function isVideoTagValid (tag: string) {
66 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
69 function isVideoTagsValid (tags: string[]) {
70 return tags === null || (
72 validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
73 tags.every(tag => isVideoTagValid(tag))
77 function isVideoViewsValid (value: string) {
78 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
81 function isVideoRatingTypeValid (value: string) {
82 return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
85 function isVideoFileExtnameValid (value: string) {
86 return exists(value) && MIMETYPES.VIDEO.EXT_MIMETYPE[value] !== undefined
89 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
90 const videoFileTypesRegex = Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT)
94 return isFileValid(files, videoFileTypesRegex, 'videofile', null)
97 const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
98 .map(v => v.replace('.', ''))
100 const videoImageTypesRegex = `image/(${videoImageTypes})`
102 function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) {
103 return isFileValid(files, videoImageTypesRegex, field, CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max, true)
106 function isVideoPrivacyValid (value: number) {
107 return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
110 function isScheduleVideoUpdatePrivacyValid (value: number) {
111 return validator.isInt(value + '') &&
113 value === VideoPrivacy.UNLISTED ||
114 value === VideoPrivacy.PUBLIC
118 function isVideoOriginallyPublishedAtValid (value: string | null) {
119 return value === null || isDateValid(value)
122 function isVideoFileInfoHashValid (value: string | null | undefined) {
123 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
126 function isVideoFileResolutionValid (value: string) {
127 return exists(value) && validator.isInt(value + '')
130 function isVideoFPSResolutionValid (value: string) {
131 return value === null || validator.isInt(value + '')
134 function isVideoFileSizeValid (value: string) {
135 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
138 function isVideoMagnetUriValid (value: string) {
139 if (!exists(value)) return false
141 const parsed = magnetUtil.decode(value)
142 return parsed && isVideoFileInfoHashValid(parsed.infoHash)
145 function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: UserRight, res: Response) {
146 // Retrieve the user who did the request
147 if (video.isOwned() === false) {
149 .json({ error: 'Cannot manage a video of another server.' })
154 // Check if the user can delete the video
155 // The user can delete it if he has the right
156 // Or if s/he is the video's account
157 const account = video.VideoChannel.Account
158 if (user.hasRight(right) === false && account.userId !== user.id) {
160 .json({ error: 'Cannot manage a video of another user.' })
168 async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') {
169 const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined
171 const video = await fetchVideo(id, fetchType, userId)
173 if (video === null) {
175 .json({ error: 'Video not found' })
181 if (fetchType !== 'none') res.locals.video = video
185 async function doesVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
186 if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
187 const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
188 if (videoChannel === null) {
190 .json({ error: 'Unknown video `video channel` on this instance.' })
196 res.locals.videoChannel = videoChannel
200 const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
201 if (videoChannel === null) {
203 .json({ error: 'Unknown video `video channel` for this account.' })
209 res.locals.videoChannel = videoChannel
213 // ---------------------------------------------------------------------------
216 isVideoCategoryValid,
217 checkUserCanManageVideo,
219 isVideoLanguageValid,
220 isVideoTruncatedDescriptionValid,
221 isVideoDescriptionValid,
222 isVideoFileInfoHashValid,
225 isVideoFPSResolutionValid,
226 isScheduleVideoUpdatePrivacyValid,
227 isVideoOriginallyPublishedAtValid,
229 isVideoMagnetUriValid,
232 isVideoRatingTypeValid,
233 isVideoFileExtnameValid,
234 isVideoDurationValid,
237 isVideoFileResolutionValid,
238 isVideoFileSizeValid,
241 doesVideoChannelOfAccountExist,