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'
15 } from '../../initializers/constants'
16 import { VideoModel } from '../../models/video/video'
17 import { exists, isArray, isDateValid, isFileValid } from './misc'
18 import { VideoChannelModel } from '../../models/video/video-channel'
19 import { UserModel } from '../../models/account/user'
20 import * as magnetUtil from 'magnet-uri'
21 import { fetchVideo, VideoFetchType } from '../video'
23 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
25 function isVideoFilterValid (filter: VideoFilter) {
26 return filter === 'local' || filter === 'all-local'
29 function isVideoCategoryValid (value: any) {
30 return value === null || VIDEO_CATEGORIES[ value ] !== undefined
33 function isVideoStateValid (value: any) {
34 return exists(value) && VIDEO_STATES[ value ] !== undefined
37 function isVideoLicenceValid (value: any) {
38 return value === null || VIDEO_LICENCES[ value ] !== undefined
41 function isVideoLanguageValid (value: any) {
42 return value === null ||
43 (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
46 function isVideoDurationValid (value: string) {
47 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
50 function isVideoTruncatedDescriptionValid (value: string) {
51 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
54 function isVideoDescriptionValid (value: string) {
55 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
58 function isVideoSupportValid (value: string) {
59 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
62 function isVideoNameValid (value: string) {
63 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
66 function isVideoTagValid (tag: string) {
67 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
70 function isVideoTagsValid (tags: string[]) {
71 return tags === null || (
73 validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
74 tags.every(tag => isVideoTagValid(tag))
78 function isVideoViewsValid (value: string) {
79 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
82 function isVideoRatingTypeValid (value: string) {
83 return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
86 function isVideoFileExtnameValid (value: string) {
87 return exists(value) && MIMETYPES.VIDEO.EXT_MIMETYPE[value] !== undefined
90 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
91 const videoFileTypesRegex = Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT)
95 return isFileValid(files, videoFileTypesRegex, 'videofile', null)
98 const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
99 .map(v => v.replace('.', ''))
101 const videoImageTypesRegex = `image/(${videoImageTypes})`
103 function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) {
104 return isFileValid(files, videoImageTypesRegex, field, CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max, true)
107 function isVideoPrivacyValid (value: number) {
108 return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
111 function isScheduleVideoUpdatePrivacyValid (value: number) {
112 return validator.isInt(value + '') &&
114 value === VideoPrivacy.UNLISTED ||
115 value === VideoPrivacy.PUBLIC
119 function isVideoOriginallyPublishedAtValid (value: string | null) {
120 return value === null || isDateValid(value)
123 function isVideoFileInfoHashValid (value: string | null | undefined) {
124 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
127 function isVideoFileResolutionValid (value: string) {
128 return exists(value) && validator.isInt(value + '')
131 function isVideoFPSResolutionValid (value: string) {
132 return value === null || validator.isInt(value + '')
135 function isVideoFileSizeValid (value: string) {
136 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
139 function isVideoMagnetUriValid (value: string) {
140 if (!exists(value)) return false
142 const parsed = magnetUtil.decode(value)
143 return parsed && isVideoFileInfoHashValid(parsed.infoHash)
146 function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: UserRight, res: Response) {
147 // Retrieve the user who did the request
148 if (video.isOwned() === false) {
150 .json({ error: 'Cannot manage a video of another server.' })
155 // Check if the user can delete the video
156 // The user can delete it if he has the right
157 // Or if s/he is the video's account
158 const account = video.VideoChannel.Account
159 if (user.hasRight(right) === false && account.userId !== user.id) {
161 .json({ error: 'Cannot manage a video of another user.' })
169 async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') {
170 const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined
172 const video = await fetchVideo(id, fetchType, userId)
174 if (video === null) {
176 .json({ error: 'Video not found' })
182 if (fetchType !== 'none') res.locals.video = video
186 async function doesVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
187 if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
188 const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
189 if (videoChannel === null) {
191 .json({ error: 'Unknown video `video channel` on this instance.' })
197 res.locals.videoChannel = videoChannel
201 const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
202 if (videoChannel === null) {
204 .json({ error: 'Unknown video `video channel` for this account.' })
210 res.locals.videoChannel = videoChannel
214 // ---------------------------------------------------------------------------
217 isVideoCategoryValid,
218 checkUserCanManageVideo,
220 isVideoLanguageValid,
221 isVideoTruncatedDescriptionValid,
222 isVideoDescriptionValid,
223 isVideoFileInfoHashValid,
226 isVideoFPSResolutionValid,
227 isScheduleVideoUpdatePrivacyValid,
228 isVideoOriginallyPublishedAtValid,
230 isVideoMagnetUriValid,
233 isVideoRatingTypeValid,
234 isVideoFileExtnameValid,
235 isVideoDurationValid,
238 isVideoFileResolutionValid,
239 isVideoFileSizeValid,
242 doesVideoChannelOfAccountExist,