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