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