]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/helpers/custom-validators/videos.ts
Merge branch 'develop' into cli-wrapper
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / videos.ts
... / ...
CommitLineData
1import { Response } from 'express'
2import 'express-validator'
3import { values } from 'lodash'
4import 'multer'
5import * as validator from 'validator'
6import { UserRight, VideoPrivacy, VideoRateType } from '../../../shared'
7import {
8 CONSTRAINTS_FIELDS,
9 VIDEO_CATEGORIES,
10 VIDEO_LICENCES,
11 VIDEO_MIMETYPE_EXT,
12 VIDEO_PRIVACIES,
13 VIDEO_RATE_TYPES,
14 VIDEO_STATES
15} from '../../initializers'
16import { VideoModel } from '../../models/video/video'
17import { exists, isArray, isFileValid } from './misc'
18import { VideoChannelModel } from '../../models/video/video-channel'
19import { UserModel } from '../../models/account/user'
20import * as magnetUtil from 'magnet-uri'
21import { fetchVideo, VideoFetchType } from '../video'
22
23const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
24
25function isVideoCategoryValid (value: any) {
26 return value === null || VIDEO_CATEGORIES[ value ] !== undefined
27}
28
29function isVideoStateValid (value: any) {
30 return exists(value) && VIDEO_STATES[ value ] !== undefined
31}
32
33function isVideoLicenceValid (value: any) {
34 return value === null || VIDEO_LICENCES[ value ] !== undefined
35}
36
37function isVideoLanguageValid (value: any) {
38 return value === null ||
39 (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
40}
41
42function isVideoDurationValid (value: string) {
43 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
44}
45
46function isVideoTruncatedDescriptionValid (value: string) {
47 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
48}
49
50function isVideoDescriptionValid (value: string) {
51 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
52}
53
54function isVideoSupportValid (value: string) {
55 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
56}
57
58function isVideoNameValid (value: string) {
59 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
60}
61
62function isVideoTagValid (tag: string) {
63 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
64}
65
66function isVideoTagsValid (tags: string[]) {
67 return tags === null || (
68 isArray(tags) &&
69 validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
70 tags.every(tag => isVideoTagValid(tag))
71 )
72}
73
74function isVideoViewsValid (value: string) {
75 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
76}
77
78function isVideoRatingTypeValid (value: string) {
79 return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
80}
81
82const videoFileTypes = Object.keys(VIDEO_MIMETYPE_EXT).map(m => `(${m})`)
83const videoFileTypesRegex = videoFileTypes.join('|')
84
85function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
86 return isFileValid(files, videoFileTypesRegex, 'videofile', null)
87}
88
89const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
90 .map(v => v.replace('.', ''))
91 .join('|')
92const videoImageTypesRegex = `image/(${videoImageTypes})`
93
94function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) {
95 return isFileValid(files, videoImageTypesRegex, field, CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max, true)
96}
97
98function isVideoPrivacyValid (value: number) {
99 return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
100}
101
102function isScheduleVideoUpdatePrivacyValid (value: number) {
103 return validator.isInt(value + '') &&
104 (
105 value === VideoPrivacy.UNLISTED ||
106 value === VideoPrivacy.PUBLIC
107 )
108}
109
110function isVideoFileInfoHashValid (value: string | null | undefined) {
111 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
112}
113
114function isVideoFileResolutionValid (value: string) {
115 return exists(value) && validator.isInt(value + '')
116}
117
118function isVideoFPSResolutionValid (value: string) {
119 return value === null || validator.isInt(value + '')
120}
121
122function isVideoFileSizeValid (value: string) {
123 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
124}
125
126function isVideoMagnetUriValid (value: string) {
127 if (!exists(value)) return false
128
129 const parsed = magnetUtil.decode(value)
130 return parsed && isVideoFileInfoHashValid(parsed.infoHash)
131}
132
133function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: UserRight, res: Response) {
134 // Retrieve the user who did the request
135 if (video.isOwned() === false) {
136 res.status(403)
137 .json({ error: 'Cannot manage a video of another server.' })
138 .end()
139 return false
140 }
141
142 // Check if the user can delete the video
143 // The user can delete it if he has the right
144 // Or if s/he is the video's account
145 const account = video.VideoChannel.Account
146 if (user.hasRight(right) === false && account.userId !== user.id) {
147 res.status(403)
148 .json({ error: 'Cannot manage a video of another user.' })
149 .end()
150 return false
151 }
152
153 return true
154}
155
156async function isVideoExist (id: string, res: Response, fetchType: VideoFetchType = 'all') {
157 const video = await fetchVideo(id, fetchType)
158
159 if (video === null) {
160 res.status(404)
161 .json({ error: 'Video not found' })
162 .end()
163
164 return false
165 }
166
167 if (fetchType !== 'none') res.locals.video = video
168 return true
169}
170
171async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
172 if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
173 const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
174 if (videoChannel === null) {
175 res.status(400)
176 .json({ error: 'Unknown video `video channel` on this instance.' })
177 .end()
178
179 return false
180 }
181
182 res.locals.videoChannel = videoChannel
183 return true
184 }
185
186 const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
187 if (videoChannel === null) {
188 res.status(400)
189 .json({ error: 'Unknown video `video channel` for this account.' })
190 .end()
191
192 return false
193 }
194
195 res.locals.videoChannel = videoChannel
196 return true
197}
198
199// ---------------------------------------------------------------------------
200
201export {
202 isVideoCategoryValid,
203 checkUserCanManageVideo,
204 isVideoLicenceValid,
205 isVideoLanguageValid,
206 isVideoTruncatedDescriptionValid,
207 isVideoDescriptionValid,
208 isVideoFileInfoHashValid,
209 isVideoNameValid,
210 isVideoTagsValid,
211 isVideoFPSResolutionValid,
212 isScheduleVideoUpdatePrivacyValid,
213 isVideoFile,
214 isVideoMagnetUriValid,
215 isVideoStateValid,
216 isVideoViewsValid,
217 isVideoRatingTypeValid,
218 isVideoDurationValid,
219 isVideoTagValid,
220 isVideoPrivacyValid,
221 isVideoFileResolutionValid,
222 isVideoFileSizeValid,
223 isVideoExist,
224 isVideoImage,
225 isVideoChannelOfAccountExist,
226 isVideoSupportValid
227}