]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/helpers/custom-validators/videos.ts
Refractor user quota SQL queries
[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
22 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
23
24 function isVideoCategoryValid (value: any) {
25 return value === null || VIDEO_CATEGORIES[ value ] !== undefined
26 }
27
28 function isVideoStateValid (value: any) {
29 return exists(value) && VIDEO_STATES[ value ] !== undefined
30 }
31
32 function isVideoLicenceValid (value: any) {
33 return value === null || VIDEO_LICENCES[ value ] !== undefined
34 }
35
36 function isVideoLanguageValid (value: any) {
37 return value === null ||
38 (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
39 }
40
41 function isVideoDurationValid (value: string) {
42 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
43 }
44
45 function isVideoTruncatedDescriptionValid (value: string) {
46 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
47 }
48
49 function isVideoDescriptionValid (value: string) {
50 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
51 }
52
53 function isVideoSupportValid (value: string) {
54 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
55 }
56
57 function isVideoNameValid (value: string) {
58 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
59 }
60
61 function isVideoTagValid (tag: string) {
62 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
63 }
64
65 function 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
73 function isVideoViewsValid (value: string) {
74 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
75 }
76
77 function isVideoRatingTypeValid (value: string) {
78 return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
79 }
80
81 const videoFileTypes = Object.keys(VIDEO_MIMETYPE_EXT).map(m => `(${m})`)
82 const videoFileTypesRegex = videoFileTypes.join('|')
83
84 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
85 return isFileValid(files, videoFileTypesRegex, 'videofile', null)
86 }
87
88 const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
89 .map(v => v.replace('.', ''))
90 .join('|')
91 const videoImageTypesRegex = `image/(${videoImageTypes})`
92
93 function 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
97 function isVideoPrivacyValid (value: number) {
98 return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
99 }
100
101 function isScheduleVideoUpdatePrivacyValid (value: number) {
102 return validator.isInt(value + '') &&
103 (
104 value === VideoPrivacy.UNLISTED ||
105 value === VideoPrivacy.PUBLIC
106 )
107 }
108
109 function isVideoFileInfoHashValid (value: string | null | undefined) {
110 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
111 }
112
113 function isVideoFileResolutionValid (value: string) {
114 return exists(value) && validator.isInt(value + '')
115 }
116
117 function isVideoFPSResolutionValid (value: string) {
118 return value === null || validator.isInt(value + '')
119 }
120
121 function isVideoFileSizeValid (value: string) {
122 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
123 }
124
125 function isVideoMagnetUriValid (value: string) {
126 if (!exists(value)) return false
127
128 const parsed = magnetUtil.decode(value)
129 return parsed && isVideoFileInfoHashValid(parsed.infoHash)
130 }
131
132 function 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
155 async 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
176 async 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
206 export {
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 }