]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/helpers/custom-validators/videos.ts
Add follow tabs
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / videos.ts
... / ...
CommitLineData
1import { values } from 'lodash'
2import * as validator from 'validator'
3import * as Promise from 'bluebird'
4import * as express from 'express'
5import 'express-validator'
6import 'multer'
7
8import {
9 CONSTRAINTS_FIELDS,
10 VIDEO_CATEGORIES,
11 VIDEO_LICENCES,
12 VIDEO_LANGUAGES,
13 VIDEO_RATE_TYPES,
14 VIDEO_PRIVACIES,
15 database as db
16} from '../../initializers'
17import { isUserUsernameValid } from './users'
18import { isArray, exists } from './misc'
19import { VideoInstance } from '../../models'
20import { logger } from '../../helpers'
21import { VideoRateType } from '../../../shared'
22import { isActivityPubUrlValid } from './activitypub/misc'
23
24const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
25const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
26const VIDEO_EVENTS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_EVENTS
27
28function isVideoCategoryValid (value: number) {
29 return VIDEO_CATEGORIES[value] !== undefined
30}
31
32// Maybe we don't know the remote category, but that doesn't matter
33function isRemoteVideoCategoryValid (value: string) {
34 return validator.isInt('' + value)
35}
36
37function isVideoUrlValid (value: string) {
38 return isActivityPubUrlValid(value)
39}
40
41function isVideoLicenceValid (value: number) {
42 return VIDEO_LICENCES[value] !== undefined
43}
44
45function isVideoPrivacyValid (value: string) {
46 return VIDEO_PRIVACIES[value] !== undefined
47}
48
49// Maybe we don't know the remote privacy setting, but that doesn't matter
50function isRemoteVideoPrivacyValid (value: string) {
51 return validator.isInt('' + value)
52}
53
54// Maybe we don't know the remote licence, but that doesn't matter
55function isRemoteVideoLicenceValid (value: string) {
56 return validator.isInt('' + value)
57}
58
59function isVideoLanguageValid (value: number) {
60 return value === null || VIDEO_LANGUAGES[value] !== undefined
61}
62
63// Maybe we don't know the remote language, but that doesn't matter
64function isRemoteVideoLanguageValid (value: string) {
65 return validator.isInt('' + value)
66}
67
68function isVideoNSFWValid (value: any) {
69 return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
70}
71
72function isVideoTruncatedDescriptionValid (value: string) {
73 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
74}
75
76function isVideoDescriptionValid (value: string) {
77 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
78}
79
80function isVideoDurationValid (value: string) {
81 // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
82 return exists(value) &&
83 typeof value === 'string' &&
84 value.startsWith('PT') &&
85 value.endsWith('S') &&
86 validator.isInt(value.replace(/[^0-9]+/, ''), VIDEOS_CONSTRAINTS_FIELDS.DURATION)
87}
88
89function isVideoNameValid (value: string) {
90 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
91}
92
93function isVideoTagValid (tag: string) {
94 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
95}
96
97function isVideoTagsValid (tags: string[]) {
98 return isArray(tags) &&
99 validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
100 tags.every(tag => isVideoTagValid(tag))
101}
102
103function isVideoThumbnailValid (value: string) {
104 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL)
105}
106
107function isVideoThumbnailDataValid (value: string) {
108 return exists(value) && validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA)
109}
110
111function isVideoAbuseReasonValid (value: string) {
112 return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
113}
114
115function isVideoAbuseReporterUsernameValid (value: string) {
116 return isUserUsernameValid(value)
117}
118
119function isVideoViewsValid (value: string) {
120 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
121}
122
123function isVideoLikesValid (value: string) {
124 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.LIKES)
125}
126
127function isVideoDislikesValid (value: string) {
128 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DISLIKES)
129}
130
131function isVideoEventCountValid (value: string) {
132 return exists(value) && validator.isInt(value + '', VIDEO_EVENTS_CONSTRAINTS_FIELDS.COUNT)
133}
134
135function isVideoRatingTypeValid (value: string) {
136 return values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
137}
138
139function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
140 // Should have files
141 if (!files) return false
142 if (isArray(files)) return false
143
144 // Should have videofile file
145 const videofile = files['videofile']
146 if (!videofile || videofile.length === 0) return false
147
148 // The file should exist
149 const file = videofile[0]
150 if (!file || !file.originalname) return false
151
152 return new RegExp('^video/(webm|mp4|ogg)$', 'i').test(file.mimetype)
153}
154
155function isVideoFileSizeValid (value: string) {
156 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
157}
158
159function isVideoFileResolutionValid (value: string) {
160 return exists(value) && validator.isInt(value + '')
161}
162
163function isVideoFileExtnameValid (value: string) {
164 return VIDEOS_CONSTRAINTS_FIELDS.EXTNAME.indexOf(value) !== -1
165}
166
167function isVideoFileInfoHashValid (value: string) {
168 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
169}
170
171function checkVideoExists (id: string, res: express.Response, callback: () => void) {
172 let promise: Promise<VideoInstance>
173 if (validator.isInt(id)) {
174 promise = db.Video.loadAndPopulateAccountAndPodAndTags(+id)
175 } else { // UUID
176 promise = db.Video.loadByUUIDAndPopulateAccountAndPodAndTags(id)
177 }
178
179 promise.then(video => {
180 if (!video) {
181 return res.status(404)
182 .json({ error: 'Video not found' })
183 .end()
184 }
185
186 res.locals.video = video
187 callback()
188 })
189 .catch(err => {
190 logger.error('Error in video request validator.', err)
191 return res.sendStatus(500)
192 })
193}
194
195// ---------------------------------------------------------------------------
196
197export {
198 isVideoCategoryValid,
199 isVideoLicenceValid,
200 isVideoLanguageValid,
201 isVideoNSFWValid,
202 isVideoTruncatedDescriptionValid,
203 isVideoDescriptionValid,
204 isVideoDurationValid,
205 isVideoFileInfoHashValid,
206 isVideoNameValid,
207 isVideoTagsValid,
208 isVideoThumbnailValid,
209 isVideoThumbnailDataValid,
210 isVideoFileExtnameValid,
211 isVideoAbuseReasonValid,
212 isVideoAbuseReporterUsernameValid,
213 isVideoFile,
214 isVideoViewsValid,
215 isVideoLikesValid,
216 isVideoRatingTypeValid,
217 isVideoDislikesValid,
218 isVideoEventCountValid,
219 isVideoFileSizeValid,
220 isVideoPrivacyValid,
221 isRemoteVideoPrivacyValid,
222 isVideoFileResolutionValid,
223 checkVideoExists,
224 isVideoTagValid,
225 isRemoteVideoCategoryValid,
226 isRemoteVideoLicenceValid,
227 isVideoUrlValid,
228 isRemoteVideoLanguageValid
229}