]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/helpers/custom-validators/videos.ts
remove confirm modal for asset injection in edit-custom-config (#1219)
[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, VideoPrivacy, VideoRateType } from '../../../shared'
7 import {
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'
16 import { VideoModel } from '../../models/video/video'
17 import { exists, isArray, 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'
22
23 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
24
25 function isVideoCategoryValid (value: any) {
26 return value === null || VIDEO_CATEGORIES[ value ] !== undefined
27 }
28
29 function isVideoStateValid (value: any) {
30 return exists(value) && VIDEO_STATES[ value ] !== undefined
31 }
32
33 function isVideoLicenceValid (value: any) {
34 return value === null || VIDEO_LICENCES[ value ] !== undefined
35 }
36
37 function isVideoLanguageValid (value: any) {
38 return value === null ||
39 (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
40 }
41
42 function isVideoDurationValid (value: string) {
43 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
44 }
45
46 function isVideoTruncatedDescriptionValid (value: string) {
47 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
48 }
49
50 function isVideoDescriptionValid (value: string) {
51 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
52 }
53
54 function isVideoSupportValid (value: string) {
55 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
56 }
57
58 function isVideoNameValid (value: string) {
59 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
60 }
61
62 function isVideoTagValid (tag: string) {
63 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
64 }
65
66 function 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
74 function isVideoViewsValid (value: string) {
75 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
76 }
77
78 function isVideoRatingTypeValid (value: string) {
79 return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
80 }
81
82 const videoFileTypes = Object.keys(VIDEO_MIMETYPE_EXT).map(m => `(${m})`)
83 const videoFileTypesRegex = videoFileTypes.join('|')
84
85 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
86 return isFileValid(files, videoFileTypesRegex, 'videofile', null)
87 }
88
89 const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
90 .map(v => v.replace('.', ''))
91 .join('|')
92 const videoImageTypesRegex = `image/(${videoImageTypes})`
93
94 function 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
98 function isVideoPrivacyValid (value: number) {
99 return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
100 }
101
102 function isScheduleVideoUpdatePrivacyValid (value: number) {
103 return validator.isInt(value + '') &&
104 (
105 value === VideoPrivacy.UNLISTED ||
106 value === VideoPrivacy.PUBLIC
107 )
108 }
109
110 function isVideoFileInfoHashValid (value: string | null | undefined) {
111 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
112 }
113
114 function isVideoFileResolutionValid (value: string) {
115 return exists(value) && validator.isInt(value + '')
116 }
117
118 function isVideoFPSResolutionValid (value: string) {
119 return value === null || validator.isInt(value + '')
120 }
121
122 function isVideoFileSizeValid (value: string) {
123 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
124 }
125
126 function isVideoMagnetUriValid (value: string) {
127 if (!exists(value)) return false
128
129 const parsed = magnetUtil.decode(value)
130 return parsed && isVideoFileInfoHashValid(parsed.infoHash)
131 }
132
133 function 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
156 async function isVideoExist (id: string, res: Response, fetchType: VideoFetchType = 'all') {
157 const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined
158
159 const video = await fetchVideo(id, fetchType, userId)
160
161 if (video === null) {
162 res.status(404)
163 .json({ error: 'Video not found' })
164 .end()
165
166 return false
167 }
168
169 if (fetchType !== 'none') res.locals.video = video
170 return true
171 }
172
173 async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
174 if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
175 const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
176 if (videoChannel === null) {
177 res.status(400)
178 .json({ error: 'Unknown video `video channel` on this instance.' })
179 .end()
180
181 return false
182 }
183
184 res.locals.videoChannel = videoChannel
185 return true
186 }
187
188 const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
189 if (videoChannel === null) {
190 res.status(400)
191 .json({ error: 'Unknown video `video channel` for this account.' })
192 .end()
193
194 return false
195 }
196
197 res.locals.videoChannel = videoChannel
198 return true
199 }
200
201 // ---------------------------------------------------------------------------
202
203 export {
204 isVideoCategoryValid,
205 checkUserCanManageVideo,
206 isVideoLicenceValid,
207 isVideoLanguageValid,
208 isVideoTruncatedDescriptionValid,
209 isVideoDescriptionValid,
210 isVideoFileInfoHashValid,
211 isVideoNameValid,
212 isVideoTagsValid,
213 isVideoFPSResolutionValid,
214 isScheduleVideoUpdatePrivacyValid,
215 isVideoFile,
216 isVideoMagnetUriValid,
217 isVideoStateValid,
218 isVideoViewsValid,
219 isVideoRatingTypeValid,
220 isVideoDurationValid,
221 isVideoTagValid,
222 isVideoPrivacyValid,
223 isVideoFileResolutionValid,
224 isVideoFileSizeValid,
225 isVideoExist,
226 isVideoImage,
227 isVideoChannelOfAccountExist,
228 isVideoSupportValid
229 }