]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/middlewares/validators/videos/video-comments.ts
Add hook filters tests
[github/Chocobozzz/PeerTube.git] / server / middlewares / validators / videos / video-comments.ts
CommitLineData
bf1f6508
C
1import * as express from 'express'
2import { body, param } from 'express-validator/check'
6e46de09
C
3import { UserRight } from '../../../../shared'
4import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc'
5import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments'
0f6acda1 6import { doesVideoExist } from '../../../helpers/custom-validators/videos'
6e46de09
C
7import { logger } from '../../../helpers/logger'
8import { UserModel } from '../../../models/account/user'
9import { VideoModel } from '../../../models/video/video'
10import { VideoCommentModel } from '../../../models/video/video-comment'
11import { areValidationErrors } from '../utils'
b4055e1c
C
12import { Hooks } from '../../../lib/plugins/hooks'
13import { isLocalVideoThreadAccepted, isLocalVideoCommentReplyAccepted, AcceptResult } from '../../../lib/moderation'
bf1f6508
C
14
15const listVideoCommentThreadsValidator = [
16 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
17
18 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
d3ea8975 19 logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params })
bf1f6508
C
20
21 if (areValidationErrors(req, res)) return
0f6acda1 22 if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return
bf1f6508
C
23
24 return next()
25 }
26]
27
28const listVideoThreadCommentsValidator = [
29 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
30 param('threadId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'),
31
32 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
d3ea8975 33 logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params })
bf1f6508
C
34
35 if (areValidationErrors(req, res)) return
0f6acda1
C
36 if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return
37 if (!await doesVideoCommentThreadExist(req.params.threadId, res.locals.video, res)) return
bf1f6508
C
38
39 return next()
40 }
41]
42
43const addVideoCommentThreadValidator = [
44 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
45 body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
46
47 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
5de8a55a 48 logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params, body: req.body })
bf1f6508
C
49
50 if (areValidationErrors(req, res)) return
0f6acda1 51 if (!await doesVideoExist(req.params.videoId, res)) return
47564bbe 52 if (!isVideoCommentsEnabled(res.locals.video, res)) return
b4055e1c 53 if (!await isVideoCommentAccepted(req, res, false)) return
bf1f6508
C
54
55 return next()
56 }
57]
58
59const addVideoCommentReplyValidator = [
60 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
61 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
62 body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
63
64 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
5de8a55a 65 logger.debug('Checking addVideoCommentReply parameters.', { parameters: req.params, body: req.body })
bf1f6508
C
66
67 if (areValidationErrors(req, res)) return
0f6acda1 68 if (!await doesVideoExist(req.params.videoId, res)) return
47564bbe 69 if (!isVideoCommentsEnabled(res.locals.video, res)) return
0f6acda1 70 if (!await doesVideoCommentExist(req.params.commentId, res.locals.video, res)) return
b4055e1c 71 if (!await isVideoCommentAccepted(req, res, true)) return
bf1f6508
C
72
73 return next()
74 }
75]
76
da854ddd
C
77const videoCommentGetValidator = [
78 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
79 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
80
81 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
82 logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
83
84 if (areValidationErrors(req, res)) return
0f6acda1
C
85 if (!await doesVideoExist(req.params.videoId, res, 'id')) return
86 if (!await doesVideoCommentExist(req.params.commentId, res.locals.video, res)) return
da854ddd
C
87
88 return next()
89 }
90]
91
4cb6d457
C
92const removeVideoCommentValidator = [
93 param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
94 param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
95
96 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
97 logger.debug('Checking removeVideoCommentValidator parameters.', { parameters: req.params })
98
99 if (areValidationErrors(req, res)) return
0f6acda1
C
100 if (!await doesVideoExist(req.params.videoId, res)) return
101 if (!await doesVideoCommentExist(req.params.commentId, res.locals.video, res)) return
4cb6d457
C
102
103 // Check if the user who did the request is able to delete the video
104 if (!checkUserCanDeleteVideoComment(res.locals.oauth.token.User, res.locals.videoComment, res)) return
105
106 return next()
107 }
108]
109
bf1f6508
C
110// ---------------------------------------------------------------------------
111
112export {
113 listVideoCommentThreadsValidator,
114 listVideoThreadCommentsValidator,
115 addVideoCommentThreadValidator,
da854ddd 116 addVideoCommentReplyValidator,
4cb6d457
C
117 videoCommentGetValidator,
118 removeVideoCommentValidator
bf1f6508
C
119}
120
121// ---------------------------------------------------------------------------
122
0f6acda1 123async function doesVideoCommentThreadExist (id: number, video: VideoModel, res: express.Response) {
bf1f6508
C
124 const videoComment = await VideoCommentModel.loadById(id)
125
126 if (!videoComment) {
127 res.status(404)
128 .json({ error: 'Video comment thread not found' })
129 .end()
130
131 return false
132 }
133
d3ea8975 134 if (videoComment.videoId !== video.id) {
bf1f6508
C
135 res.status(400)
136 .json({ error: 'Video comment is associated to this video.' })
137 .end()
138
139 return false
140 }
141
142 if (videoComment.inReplyToCommentId !== null) {
143 res.status(400)
144 .json({ error: 'Video comment is not a thread.' })
145 .end()
146
147 return false
148 }
149
150 res.locals.videoCommentThread = videoComment
151 return true
152}
153
0f6acda1 154async function doesVideoCommentExist (id: number, video: VideoModel, res: express.Response) {
da854ddd 155 const videoComment = await VideoCommentModel.loadByIdAndPopulateVideoAndAccountAndReply(id)
bf1f6508
C
156
157 if (!videoComment) {
158 res.status(404)
159 .json({ error: 'Video comment thread not found' })
160 .end()
161
162 return false
163 }
164
d3ea8975 165 if (videoComment.videoId !== video.id) {
bf1f6508
C
166 res.status(400)
167 .json({ error: 'Video comment is associated to this video.' })
168 .end()
169
170 return false
171 }
172
173 res.locals.videoComment = videoComment
174 return true
175}
47564bbe
C
176
177function isVideoCommentsEnabled (video: VideoModel, res: express.Response) {
178 if (video.commentsEnabled !== true) {
179 res.status(409)
180 .json({ error: 'Video comments are disabled for this video.' })
181 .end()
182
183 return false
184 }
185
186 return true
187}
4cb6d457
C
188
189function checkUserCanDeleteVideoComment (user: UserModel, videoComment: VideoCommentModel, res: express.Response) {
190 const account = videoComment.Account
191 if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT) === false && account.userId !== user.id) {
192 res.status(403)
193 .json({ error: 'Cannot remove video comment of another user' })
194 .end()
195 return false
196 }
197
198 return true
199}
b4055e1c
C
200
201async function isVideoCommentAccepted (req: express.Request, res: express.Response, isReply: boolean) {
202 const acceptParameters = {
203 video: res.locals.video,
204 commentBody: req.body,
205 user: res.locals.oauth.token.User
206 }
207
208 let acceptedResult: AcceptResult
209
210 if (isReply) {
211 const acceptReplyParameters = Object.assign(acceptParameters, { parentComment: res.locals.videoComment })
212
213 acceptedResult = await Hooks.wrapObject(
214 isLocalVideoCommentReplyAccepted(acceptReplyParameters),
215 'filter:api.video-comment-reply.create.accept.result'
216 )
217 } else {
218 acceptedResult = await Hooks.wrapObject(
219 isLocalVideoThreadAccepted(acceptParameters),
220 'filter:api.video-thread.create.accept.result'
221 )
222 }
223
224 if (!acceptedResult || acceptedResult.accepted !== true) {
225 logger.info('Refused local comment.', { acceptedResult, acceptParameters })
226 res.status(403)
227 .json({ error: acceptedResult.errorMessage || 'Refused local comment' })
228
229 return false
230 }
231
232 return true
233}