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