]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/middlewares/validators/videos/video-comments.ts
Live streaming implementation first step
[github/Chocobozzz/PeerTube.git] / server / middlewares / validators / videos / video-comments.ts
1 import * as express from 'express'
2 import { body, param } from 'express-validator'
3 import { MUserAccountUrl } from '@server/types/models'
4 import { UserRight } from '../../../../shared'
5 import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc'
6 import {
7 doesVideoCommentExist,
8 doesVideoCommentThreadExist,
9 isValidVideoCommentText
10 } from '../../../helpers/custom-validators/video-comments'
11 import { logger } from '../../../helpers/logger'
12 import { doesVideoExist } from '../../../helpers/middlewares'
13 import { AcceptResult, isLocalVideoCommentReplyAccepted, isLocalVideoThreadAccepted } from '../../../lib/moderation'
14 import { Hooks } from '../../../lib/plugins/hooks'
15 import { MCommentOwnerVideoReply, MVideo, MVideoFullLight } from '../../../types/models/video'
16 import { areValidationErrors } from '../utils'
17
18 const listVideoCommentThreadsValidator = [
19 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
20
21 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
22 logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params })
23
24 if (areValidationErrors(req, res)) return
25 if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return
26
27 return next()
28 }
29 ]
30
31 const listVideoThreadCommentsValidator = [
32 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
33 param('threadId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'),
34
35 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
36 logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params })
37
38 if (areValidationErrors(req, res)) return
39 if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return
40 if (!await doesVideoCommentThreadExist(req.params.threadId, res.locals.onlyVideo, res)) return
41
42 return next()
43 }
44 ]
45
46 const addVideoCommentThreadValidator = [
47 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
48 body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
49
50 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
51 logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params, body: req.body })
52
53 if (areValidationErrors(req, res)) return
54 if (!await doesVideoExist(req.params.videoId, res)) return
55 if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
56 if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, false)) return
57
58 return next()
59 }
60 ]
61
62 const addVideoCommentReplyValidator = [
63 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
64 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
65 body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
66
67 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
68 logger.debug('Checking addVideoCommentReply parameters.', { parameters: req.params, body: req.body })
69
70 if (areValidationErrors(req, res)) return
71 if (!await doesVideoExist(req.params.videoId, res)) return
72 if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
73 if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoAll, res)) return
74 if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, true)) return
75
76 return next()
77 }
78 ]
79
80 const videoCommentGetValidator = [
81 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
82 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
83
84 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
85 logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
86
87 if (areValidationErrors(req, res)) return
88 if (!await doesVideoExist(req.params.videoId, res, 'id')) return
89 if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoId, res)) return
90
91 return next()
92 }
93 ]
94
95 const removeVideoCommentValidator = [
96 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
97 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
98
99 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
100 logger.debug('Checking removeVideoCommentValidator parameters.', { parameters: req.params })
101
102 if (areValidationErrors(req, res)) return
103 if (!await doesVideoExist(req.params.videoId, res)) return
104 if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoAll, res)) return
105
106 // Check if the user who did the request is able to delete the video
107 if (!checkUserCanDeleteVideoComment(res.locals.oauth.token.User, res.locals.videoCommentFull, res)) return
108
109 return next()
110 }
111 ]
112
113 // ---------------------------------------------------------------------------
114
115 export {
116 listVideoCommentThreadsValidator,
117 listVideoThreadCommentsValidator,
118 addVideoCommentThreadValidator,
119 addVideoCommentReplyValidator,
120 videoCommentGetValidator,
121 removeVideoCommentValidator
122 }
123
124 // ---------------------------------------------------------------------------
125
126 function isVideoCommentsEnabled (video: MVideo, res: express.Response) {
127 if (video.commentsEnabled !== true) {
128 res.status(409)
129 .json({ error: 'Video comments are disabled for this video.' })
130
131 return false
132 }
133
134 return true
135 }
136
137 function checkUserCanDeleteVideoComment (user: MUserAccountUrl, videoComment: MCommentOwnerVideoReply, res: express.Response) {
138 if (videoComment.isDeleted()) {
139 res.status(409)
140 .json({ error: 'This comment is already deleted' })
141
142 return false
143 }
144
145 const userAccount = user.Account
146
147 if (
148 user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT) === false && // Not a moderator
149 videoComment.accountId !== userAccount.id && // Not the comment owner
150 videoComment.Video.VideoChannel.accountId !== userAccount.id // Not the video owner
151 ) {
152 res.status(403)
153 .json({ error: 'Cannot remove video comment of another user' })
154
155 return false
156 }
157
158 return true
159 }
160
161 async function isVideoCommentAccepted (req: express.Request, res: express.Response, video: MVideoFullLight, isReply: boolean) {
162 const acceptParameters = {
163 video,
164 commentBody: req.body,
165 user: res.locals.oauth.token.User
166 }
167
168 let acceptedResult: AcceptResult
169
170 if (isReply) {
171 const acceptReplyParameters = Object.assign(acceptParameters, { parentComment: res.locals.videoCommentFull })
172
173 acceptedResult = await Hooks.wrapFun(
174 isLocalVideoCommentReplyAccepted,
175 acceptReplyParameters,
176 'filter:api.video-comment-reply.create.accept.result'
177 )
178 } else {
179 acceptedResult = await Hooks.wrapFun(
180 isLocalVideoThreadAccepted,
181 acceptParameters,
182 'filter:api.video-thread.create.accept.result'
183 )
184 }
185
186 if (!acceptedResult || acceptedResult.accepted !== true) {
187 logger.info('Refused local comment.', { acceptedResult, acceptParameters })
188 res.status(403)
189 .json({ error: acceptedResult.errorMessage || 'Refused local comment' })
190
191 return false
192 }
193
194 return true
195 }