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