]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/helpers/custom-validators/videos.ts
Add ability to limit videos history size
[github/Chocobozzz/PeerTube.git] / server / helpers / custom-validators / videos.ts
CommitLineData
8d468a16 1import { Response } from 'express'
fdbda9e3 2import 'express-validator'
79d5caf9 3import { values } from 'lodash'
1840c2f7 4import 'multer'
79d5caf9 5import * as validator from 'validator'
1cd3facc 6import { UserRight, VideoFilter, VideoPrivacy, VideoRateType } from '../../../shared'
3fd3ab2d 7import {
8f0bc73d
C
8 CONSTRAINTS_FIELDS,
9 MIMETYPES,
3fd3ab2d 10 VIDEO_CATEGORIES,
28be8916 11 VIDEO_LICENCES,
3fd3ab2d 12 VIDEO_PRIVACIES,
2186386c
C
13 VIDEO_RATE_TYPES,
14 VIDEO_STATES
74dc3bca 15} from '../../initializers/constants'
3fd3ab2d 16import { VideoModel } from '../../models/video/video'
1e74f19a 17import { exists, isArray, isDateValid, isFileValid } from './misc'
0f320037 18import { VideoChannelModel } from '../../models/video/video-channel'
6200d8d9 19import { UserModel } from '../../models/account/user'
ce33919c 20import * as magnetUtil from 'magnet-uri'
4157cdb1 21import { fetchVideo, VideoFetchType } from '../video'
65fcc311
C
22
23const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
0b697522 24
1cd3facc
C
25function isVideoFilterValid (filter: VideoFilter) {
26 return filter === 'local' || filter === 'all-local'
27}
28
9d3ef9fe 29function isVideoCategoryValid (value: any) {
2186386c
C
30 return value === null || VIDEO_CATEGORIES[ value ] !== undefined
31}
32
33function isVideoStateValid (value: any) {
34 return exists(value) && VIDEO_STATES[ value ] !== undefined
6e07c3de
C
35}
36
9d3ef9fe 37function isVideoLicenceValid (value: any) {
2186386c 38 return value === null || VIDEO_LICENCES[ value ] !== undefined
6f0c39e2
C
39}
40
9d3ef9fe
C
41function isVideoLanguageValid (value: any) {
42 return value === null ||
43 (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
3092476e
C
44}
45
8e10cf1a
C
46function isVideoDurationValid (value: string) {
47 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
48}
49
9567011b
C
50function isVideoTruncatedDescriptionValid (value: string) {
51 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
52}
53
69818c93 54function isVideoDescriptionValid (value: string) {
f595d394 55 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
be587647
C
56}
57
2422c46b
C
58function isVideoSupportValid (value: string) {
59 return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
60}
61
69818c93
C
62function isVideoNameValid (value: string) {
63 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
be587647
C
64}
65
0d0e8dd0
C
66function isVideoTagValid (tag: string) {
67 return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
68}
69
69818c93 70function isVideoTagsValid (tags: string[]) {
2efd32f6
C
71 return tags === null || (
72 isArray(tags) &&
73 validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
74 tags.every(tag => isVideoTagValid(tag))
75 )
be587647
C
76}
77
69818c93
C
78function isVideoViewsValid (value: string) {
79 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
9e167724
C
80}
81
69818c93 82function isVideoRatingTypeValid (value: string) {
57a49263 83 return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
d38b8281
C
84}
85
14e2014a
C
86function isVideoFileExtnameValid (value: string) {
87 return exists(value) && MIMETYPES.VIDEO.EXT_MIMETYPE[value] !== undefined
88}
2186386c 89
b60e5f38 90function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
14e2014a 91 const videoFileTypesRegex = Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT)
307902e2
C
92 .map(m => `(${m})`)
93 .join('|')
14e2014a 94
0c237b19 95 return isFileValid(files, videoFileTypesRegex, 'videofile', null)
ac81d1a0 96}
f6f7dfee 97
ac81d1a0 98const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
2186386c
C
99 .map(v => v.replace('.', ''))
100 .join('|')
ac81d1a0 101const videoImageTypesRegex = `image/(${videoImageTypes})`
2186386c 102
ac81d1a0 103function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) {
0c237b19 104 return isFileValid(files, videoImageTypesRegex, field, CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max, true)
f6f7dfee
C
105}
106
2baea0c7 107function isVideoPrivacyValid (value: number) {
2186386c 108 return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
d4f1e94c
C
109}
110
2baea0c7
C
111function isScheduleVideoUpdatePrivacyValid (value: number) {
112 return validator.isInt(value + '') &&
113 (
114 value === VideoPrivacy.UNLISTED ||
115 value === VideoPrivacy.PUBLIC
116 )
117}
118
1e74f19a 119function isVideoOriginallyPublishedAtValid (value: string | null) {
120 return value === null || isDateValid(value)
121}
122
2cebd797 123function isVideoFileInfoHashValid (value: string | null | undefined) {
93e1258c
C
124 return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
125}
126
d4f1e94c
C
127function isVideoFileResolutionValid (value: string) {
128 return exists(value) && validator.isInt(value + '')
129}
130
3a6f351b
C
131function isVideoFPSResolutionValid (value: string) {
132 return value === null || validator.isInt(value + '')
133}
134
d4f1e94c
C
135function isVideoFileSizeValid (value: string) {
136 return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
8d468a16
C
137}
138
ce33919c
C
139function isVideoMagnetUriValid (value: string) {
140 if (!exists(value)) return false
141
142 const parsed = magnetUtil.decode(value)
143 return parsed && isVideoFileInfoHashValid(parsed.infoHash)
144}
145
40e87e9e
C
146function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: UserRight, res: Response) {
147 // Retrieve the user who did the request
148 if (video.isOwned() === false) {
149 res.status(403)
150 .json({ error: 'Cannot manage a video of another server.' })
151 .end()
152 return false
153 }
154
155 // Check if the user can delete the video
156 // The user can delete it if he has the right
157 // Or if s/he is the video's account
158 const account = video.VideoChannel.Account
159 if (user.hasRight(right) === false && account.userId !== user.id) {
160 res.status(403)
161 .json({ error: 'Cannot manage a video of another user.' })
162 .end()
163 return false
164 }
165
166 return true
167}
168
0f6acda1 169async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') {
6e46de09
C
170 const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined
171
172 const video = await fetchVideo(id, fetchType, userId)
4e50b6a1 173
2cebd797 174 if (video === null) {
4e50b6a1 175 res.status(404)
2186386c
C
176 .json({ error: 'Video not found' })
177 .end()
4e50b6a1
C
178
179 return false
180 }
181
627621c1 182 if (fetchType !== 'none') res.locals.video = video
4e50b6a1
C
183 return true
184}
185
0f6acda1 186async function doesVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
6200d8d9
C
187 if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
188 const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
2cebd797 189 if (videoChannel === null) {
6200d8d9 190 res.status(400)
e78980eb 191 .json({ error: 'Unknown video `video channel` on this instance.' })
6200d8d9
C
192 .end()
193
194 return false
195 }
196
197 res.locals.videoChannel = videoChannel
198 return true
199 }
200
201 const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
2cebd797 202 if (videoChannel === null) {
0f320037 203 res.status(400)
e78980eb 204 .json({ error: 'Unknown video `video channel` for this account.' })
0f320037
C
205 .end()
206
207 return false
208 }
209
210 res.locals.videoChannel = videoChannel
211 return true
212}
213
55fa55a9
C
214// ---------------------------------------------------------------------------
215
65fcc311 216export {
65fcc311 217 isVideoCategoryValid,
40e87e9e 218 checkUserCanManageVideo,
65fcc311
C
219 isVideoLicenceValid,
220 isVideoLanguageValid,
9567011b 221 isVideoTruncatedDescriptionValid,
65fcc311 222 isVideoDescriptionValid,
93e1258c 223 isVideoFileInfoHashValid,
65fcc311
C
224 isVideoNameValid,
225 isVideoTagsValid,
3a6f351b 226 isVideoFPSResolutionValid,
2baea0c7 227 isScheduleVideoUpdatePrivacyValid,
1e74f19a 228 isVideoOriginallyPublishedAtValid,
65fcc311 229 isVideoFile,
ce33919c 230 isVideoMagnetUriValid,
2186386c 231 isVideoStateValid,
65fcc311 232 isVideoViewsValid,
65fcc311 233 isVideoRatingTypeValid,
14e2014a 234 isVideoFileExtnameValid,
8e10cf1a 235 isVideoDurationValid,
0d0e8dd0 236 isVideoTagValid,
8d468a16 237 isVideoPrivacyValid,
d4f1e94c
C
238 isVideoFileResolutionValid,
239 isVideoFileSizeValid,
0f6acda1 240 doesVideoExist,
2422c46b 241 isVideoImage,
0f6acda1 242 doesVideoChannelOfAccountExist,
1cd3facc
C
243 isVideoSupportValid,
244 isVideoFilterValid
65fcc311 245}