]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/helpers/custom-validators/videos.ts
Don't expose constants directly in initializers/
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / videos.ts
1 import { Response } from 'express'
2 import 'express-validator'
3 import { values } from 'lodash'
4 import 'multer'
5 import * as validator from 'validator'
6 import { UserRight, VideoFilter, VideoPrivacy, VideoRateType } from '../../../shared'
7 import {
8 CONSTRAINTS_FIELDS, MIMETYPES,
9 VIDEO_CATEGORIES,
10 VIDEO_LICENCES,
11 VIDEO_PRIVACIES,
12 VIDEO_RATE_TYPES,
13 VIDEO_STATES
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'
21
22 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
23
24 function isVideoFilterValid (filter: VideoFilter) {
25 return filter === 'local' || filter === 'all-local'
26 }
27
28 function isVideoCategoryValid (value: any) {
29 return value === null || VIDEO_CATEGORIES[ value ] !== undefined
30 }
31
32 function isVideoStateValid (value: any) {
33 return exists(value) && VIDEO_STATES[ value ] !== undefined
34 }
35
36 function isVideoLicenceValid (value: any) {
37 return value === null || VIDEO_LICENCES[ value ] !== undefined
38 }
39
40 function isVideoLanguageValid (value: any) {
41 return value === null ||
42 (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
43 }
44
45 function isVideoDurationValid (value: string) {
46 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
47 }
48
49 function isVideoTruncatedDescriptionValid (value: string) {
50 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
51 }
52
53 function isVideoDescriptionValid (value: string) {
54 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
55 }
56
57 function isVideoSupportValid (value: string) {
58 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
59 }
60
61 function isVideoNameValid (value: string) {
62 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
63 }
64
65 function isVideoTagValid (tag: string) {
66 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
67 }
68
69 function 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
77 function isVideoViewsValid (value: string) {
78 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
79 }
80
81 function isVideoRatingTypeValid (value: string) {
82 return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
83 }
84
85 function isVideoFileExtnameValid (value: string) {
86 return exists(value) && MIMETYPES.VIDEO.EXT_MIMETYPE[value] !== undefined
87 }
88
89 function 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
97 const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
98 .map(v => v.replace('.', ''))
99 .join('|')
100 const videoImageTypesRegex = `image/(${videoImageTypes})`
101
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)
104 }
105
106 function isVideoPrivacyValid (value: number) {
107 return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
108 }
109
110 function isScheduleVideoUpdatePrivacyValid (value: number) {
111 return validator.isInt(value + '') &&
112 (
113 value === VideoPrivacy.UNLISTED ||
114 value === VideoPrivacy.PUBLIC
115 )
116 }
117
118 function isVideoOriginallyPublishedAtValid (value: string | null) {
119 return value === null || isDateValid(value)
120 }
121
122 function isVideoFileInfoHashValid (value: string | null | undefined) {
123 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
124 }
125
126 function isVideoFileResolutionValid (value: string) {
127 return exists(value) && validator.isInt(value + '')
128 }
129
130 function isVideoFPSResolutionValid (value: string) {
131 return value === null || validator.isInt(value + '')
132 }
133
134 function isVideoFileSizeValid (value: string) {
135 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
136 }
137
138 function isVideoMagnetUriValid (value: string) {
139 if (!exists(value)) return false
140
141 const parsed = magnetUtil.decode(value)
142 return parsed && isVideoFileInfoHashValid(parsed.infoHash)
143 }
144
145 function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: UserRight, res: Response) {
146 // Retrieve the user who did the request
147 if (video.isOwned() === false) {
148 res.status(403)
149 .json({ error: 'Cannot manage a video of another server.' })
150 .end()
151 return false
152 }
153
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) {
159 res.status(403)
160 .json({ error: 'Cannot manage a video of another user.' })
161 .end()
162 return false
163 }
164
165 return true
166 }
167
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
170
171 const video = await fetchVideo(id, fetchType, userId)
172
173 if (video === null) {
174 res.status(404)
175 .json({ error: 'Video not found' })
176 .end()
177
178 return false
179 }
180
181 if (fetchType !== 'none') res.locals.video = video
182 return true
183 }
184
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) {
189 res.status(400)
190 .json({ error: 'Unknown video `video channel` on this instance.' })
191 .end()
192
193 return false
194 }
195
196 res.locals.videoChannel = videoChannel
197 return true
198 }
199
200 const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
201 if (videoChannel === null) {
202 res.status(400)
203 .json({ error: 'Unknown video `video channel` for this account.' })
204 .end()
205
206 return false
207 }
208
209 res.locals.videoChannel = videoChannel
210 return true
211 }
212
213 // ---------------------------------------------------------------------------
214
215 export {
216 isVideoCategoryValid,
217 checkUserCanManageVideo,
218 isVideoLicenceValid,
219 isVideoLanguageValid,
220 isVideoTruncatedDescriptionValid,
221 isVideoDescriptionValid,
222 isVideoFileInfoHashValid,
223 isVideoNameValid,
224 isVideoTagsValid,
225 isVideoFPSResolutionValid,
226 isScheduleVideoUpdatePrivacyValid,
227 isVideoOriginallyPublishedAtValid,
228 isVideoFile,
229 isVideoMagnetUriValid,
230 isVideoStateValid,
231 isVideoViewsValid,
232 isVideoRatingTypeValid,
233 isVideoFileExtnameValid,
234 isVideoDurationValid,
235 isVideoTagValid,
236 isVideoPrivacyValid,
237 isVideoFileResolutionValid,
238 isVideoFileSizeValid,
239 doesVideoExist,
240 isVideoImage,
241 doesVideoChannelOfAccountExist,
242 isVideoSupportValid,
243 isVideoFilterValid
244 }