]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/middlewares/validators/videos/video-channels.ts
Merge branch 'release/5.0.0' into develop
[github/Chocobozzz/PeerTube.git] / server / middlewares / validators / videos / video-channels.ts
CommitLineData
41fb13c3 1import express from 'express'
747c5628 2import { body, param, query } from 'express-validator'
2a491182 3import { isUrlValid } from '@server/helpers/custom-validators/activitypub/misc'
a37e9e74 4import { CONFIG } from '@server/initializers/config'
5import { MChannelAccountDefault } from '@server/types/models'
a3b472a1 6import { VideosImportInChannelCreate } from '@shared/models'
c0e8b12e 7import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes'
a3b472a1 8import { isBooleanValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc'
4e50b6a1 9import {
7d8e778a 10 isVideoChannelDescriptionValid,
27db7840
C
11 isVideoChannelDisplayNameValid,
12 isVideoChannelSupportValid,
13 isVideoChannelUsernameValid
6e46de09 14} from '../../../helpers/custom-validators/video-channels'
7d9ba5c0 15import { ActorModel } from '../../../models/actor/actor'
6e46de09 16import { VideoChannelModel } from '../../../models/video/video-channel'
2a491182 17import { areValidationErrors, checkUserQuota, doesVideoChannelNameWithHostExist } from '../shared'
a3b472a1 18import { doesVideoChannelSyncIdExist } from '../shared/video-channel-syncs'
72c7248b 19
2a491182 20export const videoChannelsAddValidator = [
396f6f01
C
21 body('name')
22 .custom(isVideoChannelUsernameValid),
23 body('displayName')
24 .custom(isVideoChannelDisplayNameValid),
25 body('description')
26 .optional()
27 .custom(isVideoChannelDescriptionValid),
28 body('support')
29 .optional()
30 .custom(isVideoChannelSupportValid),
72c7248b 31
601527d7 32 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
a2431b7d
C
33 if (areValidationErrors(req, res)) return
34
601527d7
C
35 const actor = await ActorModel.loadLocalByName(req.body.name)
36 if (actor) {
76148b27
RK
37 res.fail({
38 status: HttpStatusCode.CONFLICT_409,
39 message: 'Another actor (account/channel) with this name on this instance already exists or has already existed.'
40 })
601527d7
C
41 return false
42 }
43
a3ce4ae8 44 const count = await VideoChannelModel.countByAccount(res.locals.oauth.token.User.Account.id)
754b6f5f
FC
45 if (count >= CONFIG.VIDEO_CHANNELS.MAX_PER_USER) {
46 res.fail({ message: `You cannot create more than ${CONFIG.VIDEO_CHANNELS.MAX_PER_USER} channels` })
a3ce4ae8
C
47 return false
48 }
49
a2431b7d 50 return next()
72c7248b
C
51 }
52]
53
2a491182 54export const videoChannelsUpdateValidator = [
396f6f01
C
55 param('nameWithHost')
56 .exists(),
57
7d14d4d2
C
58 body('displayName')
59 .optional()
396f6f01 60 .custom(isVideoChannelDisplayNameValid),
7d14d4d2
C
61 body('description')
62 .optional()
396f6f01 63 .custom(isVideoChannelDescriptionValid),
7d14d4d2
C
64 body('support')
65 .optional()
396f6f01 66 .custom(isVideoChannelSupportValid),
7d14d4d2
C
67 body('bulkVideosSupportUpdate')
68 .optional()
69 .custom(isBooleanValid).withMessage('Should have a valid bulkVideosSupportUpdate boolean field'),
72c7248b 70
906f46d0 71 (req: express.Request, res: express.Response, next: express.NextFunction) => {
a2431b7d 72 if (areValidationErrors(req, res)) return
a2431b7d
C
73
74 return next()
72c7248b
C
75 }
76]
77
2a491182 78export const videoChannelsRemoveValidator = [
a2431b7d 79 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
a37e9e74 80 if (!await checkVideoChannelIsNotTheLastOne(res.locals.videoChannel, res)) return
a2431b7d
C
81
82 return next()
72c7248b
C
83 }
84]
85
2a491182 86export const videoChannelsNameWithHostValidator = [
396f6f01
C
87 param('nameWithHost')
88 .exists(),
72c7248b 89
a2431b7d 90 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
a2431b7d 91 if (areValidationErrors(req, res)) return
6b738c7a 92
0f6acda1 93 if (!await doesVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return
a2431b7d
C
94
95 return next()
72c7248b
C
96 }
97]
98
2a491182 99export const ensureIsLocalChannel = [
a37e9e74 100 (req: express.Request, res: express.Response, next: express.NextFunction) => {
101 if (res.locals.videoChannel.Actor.isOwned() === false) {
102 return res.fail({
103 status: HttpStatusCode.FORBIDDEN_403,
104 message: 'This channel is not owned.'
105 })
106 }
06a05d5f
C
107
108 return next()
109 }
110]
111
2a491182
F
112export const ensureChannelOwnerCanUpload = [
113 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
114 const channel = res.locals.videoChannel
115 const user = { id: channel.Account.userId }
116
117 if (!await checkUserQuota(user, 1, res)) return
118
119 next()
120 }
121]
122
123export const videoChannelStatsValidator = [
5a61ffbb
C
124 query('withStats')
125 .optional()
126 .customSanitizer(toBooleanOrNull)
396f6f01 127 .custom(isBooleanValid).withMessage('Should have a valid stats flag boolean'),
747c5628
RK
128
129 (req: express.Request, res: express.Response, next: express.NextFunction) => {
130 if (areValidationErrors(req, res)) return
131 return next()
132 }
133]
134
2a491182 135export const videoChannelsListValidator = [
396f6f01
C
136 query('search')
137 .optional()
138 .not().isEmpty(),
37a44fc9
C
139
140 (req: express.Request, res: express.Response, next: express.NextFunction) => {
37a44fc9
C
141 if (areValidationErrors(req, res)) return
142
143 return next()
144 }
145]
146
2a491182 147export const videoChannelImportVideosValidator = [
396f6f01
C
148 body('externalChannelUrl')
149 .custom(isUrlValid),
72c7248b 150
a3b472a1
C
151 body('videoChannelSyncId')
152 .optional()
396f6f01 153 .custom(isIdValid),
a3b472a1
C
154
155 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
2a491182
F
156 if (areValidationErrors(req, res)) return
157
a3b472a1
C
158 const body: VideosImportInChannelCreate = req.body
159
2a491182
F
160 if (!CONFIG.IMPORT.VIDEOS.HTTP.ENABLED) {
161 return res.fail({
162 status: HttpStatusCode.FORBIDDEN_403,
163 message: 'Channel import is impossible as video upload via HTTP is not enabled on the server'
164 })
165 }
166
a3b472a1
C
167 if (body.videoChannelSyncId && !await doesVideoChannelSyncIdExist(body.videoChannelSyncId, res)) return
168
8a6828b1
C
169 if (res.locals.videoChannelSync && res.locals.videoChannelSync.videoChannelId !== res.locals.videoChannel.id) {
170 return res.fail({
171 status: HttpStatusCode.FORBIDDEN_403,
172 message: 'This channel sync is not owned by this channel'
173 })
174 }
175
2a491182
F
176 return next()
177 }
178]
72c7248b
C
179
180// ---------------------------------------------------------------------------
181
a37e9e74 182async function checkVideoChannelIsNotTheLastOne (videoChannel: MChannelAccountDefault, res: express.Response) {
183 const count = await VideoChannelModel.countByAccount(videoChannel.Account.id)
a2431b7d
C
184
185 if (count <= 1) {
76148b27
RK
186 res.fail({
187 status: HttpStatusCode.CONFLICT_409,
188 message: 'Cannot remove the last channel of this user'
189 })
a2431b7d
C
190 return false
191 }
192
193 return true
72c7248b 194}