Add tests and fix bugs for video privacy
[oweals/peertube.git] / server / middlewares / validators / video-channels.ts
1 import { body, param } from 'express-validator/check'
2 import * as express from 'express'
3
4 import { checkErrors } from './utils'
5 import { database as db } from '../../initializers'
6 import {
7   logger,
8   isIdOrUUIDValid,
9   isVideoChannelDescriptionValid,
10   isVideoChannelNameValid,
11   checkVideoChannelExists,
12   checkVideoAuthorExists
13 } from '../../helpers'
14 import { UserInstance } from '../../models'
15 import { UserRight } from '../../../shared'
16
17 const listVideoAuthorChannelsValidator = [
18   param('authorId').custom(isIdOrUUIDValid).withMessage('Should have a valid author id'),
19
20   (req: express.Request, res: express.Response, next: express.NextFunction) => {
21     logger.debug('Checking listVideoAuthorChannelsValidator parameters', { parameters: req.body })
22
23     checkErrors(req, res, () => {
24       checkVideoAuthorExists(req.params.authorId, res, next)
25     })
26   }
27 ]
28
29 const videoChannelsAddValidator = [
30   body('name').custom(isVideoChannelNameValid).withMessage('Should have a valid name'),
31   body('description').custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
32
33   (req: express.Request, res: express.Response, next: express.NextFunction) => {
34     logger.debug('Checking videoChannelsAdd parameters', { parameters: req.body })
35
36     checkErrors(req, res, next)
37   }
38 ]
39
40 const videoChannelsUpdateValidator = [
41   param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
42   body('name').optional().custom(isVideoChannelNameValid).withMessage('Should have a valid name'),
43   body('description').optional().custom(isVideoChannelDescriptionValid).withMessage('Should have a valid description'),
44
45   (req: express.Request, res: express.Response, next: express.NextFunction) => {
46     logger.debug('Checking videoChannelsUpdate parameters', { parameters: req.body })
47
48     checkErrors(req, res, () => {
49       checkVideoChannelExists(req.params.id, res, () => {
50         // We need to make additional checks
51         if (res.locals.videoChannel.isOwned() === false) {
52           return res.status(403)
53             .json({ error: 'Cannot update video channel of another pod' })
54             .end()
55         }
56
57         if (res.locals.videoChannel.Author.userId !== res.locals.oauth.token.User.id) {
58           return res.status(403)
59             .json({ error: 'Cannot update video channel of another user' })
60             .end()
61         }
62
63         next()
64       })
65     })
66   }
67 ]
68
69 const videoChannelsRemoveValidator = [
70   param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
71
72   (req: express.Request, res: express.Response, next: express.NextFunction) => {
73     logger.debug('Checking videoChannelsRemove parameters', { parameters: req.params })
74
75     checkErrors(req, res, () => {
76       checkVideoChannelExists(req.params.id, res, () => {
77         // Check if the user who did the request is able to delete the video
78         checkUserCanDeleteVideoChannel(res, () => {
79           checkVideoChannelIsNotTheLastOne(res, next)
80         })
81       })
82     })
83   }
84 ]
85
86 const videoChannelGetValidator = [
87   param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
88
89   (req: express.Request, res: express.Response, next: express.NextFunction) => {
90     logger.debug('Checking videoChannelsGet parameters', { parameters: req.params })
91
92     checkErrors(req, res, () => {
93       checkVideoChannelExists(req.params.id, res, next)
94     })
95   }
96 ]
97
98 // ---------------------------------------------------------------------------
99
100 export {
101   listVideoAuthorChannelsValidator,
102   videoChannelsAddValidator,
103   videoChannelsUpdateValidator,
104   videoChannelsRemoveValidator,
105   videoChannelGetValidator
106 }
107
108 // ---------------------------------------------------------------------------
109
110 function checkUserCanDeleteVideoChannel (res: express.Response, callback: () => void) {
111   const user: UserInstance = res.locals.oauth.token.User
112
113   // Retrieve the user who did the request
114   if (res.locals.videoChannel.isOwned() === false) {
115     return res.status(403)
116               .json({ error: 'Cannot remove video channel of another pod.' })
117               .end()
118   }
119
120   // Check if the user can delete the video channel
121   // The user can delete it if s/he is an admin
122   // Or if s/he is the video channel's author
123   if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_CHANNEL) === false && res.locals.videoChannel.Author.userId !== user.id) {
124     return res.status(403)
125               .json({ error: 'Cannot remove video channel of another user' })
126               .end()
127   }
128
129   // If we reach this comment, we can delete the video
130   callback()
131 }
132
133 function checkVideoChannelIsNotTheLastOne (res: express.Response, callback: () => void) {
134   db.VideoChannel.countByAuthor(res.locals.oauth.token.User.Author.id)
135     .then(count => {
136       if (count <= 1) {
137         return res.status(409)
138           .json({ error: 'Cannot remove the last channel of this user' })
139           .end()
140       }
141
142       callback()
143     })
144 }