diff options
Diffstat (limited to 'server/middlewares/validators/videos/video-comments.ts')
-rw-r--r-- | server/middlewares/validators/videos/video-comments.ts | 249 |
1 files changed, 0 insertions, 249 deletions
diff --git a/server/middlewares/validators/videos/video-comments.ts b/server/middlewares/validators/videos/video-comments.ts deleted file mode 100644 index 70689b02e..000000000 --- a/server/middlewares/validators/videos/video-comments.ts +++ /dev/null | |||
@@ -1,249 +0,0 @@ | |||
1 | import express from 'express' | ||
2 | import { body, param, query } from 'express-validator' | ||
3 | import { MUserAccountUrl } from '@server/types/models' | ||
4 | import { HttpStatusCode, UserRight } from '@shared/models' | ||
5 | import { exists, isBooleanValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc' | ||
6 | import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments' | ||
7 | import { logger } from '../../../helpers/logger' | ||
8 | import { AcceptResult, isLocalVideoCommentReplyAccepted, isLocalVideoThreadAccepted } from '../../../lib/moderation' | ||
9 | import { Hooks } from '../../../lib/plugins/hooks' | ||
10 | import { MCommentOwnerVideoReply, MVideo, MVideoFullLight } from '../../../types/models/video' | ||
11 | import { | ||
12 | areValidationErrors, | ||
13 | checkCanSeeVideo, | ||
14 | doesVideoCommentExist, | ||
15 | doesVideoCommentThreadExist, | ||
16 | doesVideoExist, | ||
17 | isValidVideoIdParam, | ||
18 | isValidVideoPasswordHeader | ||
19 | } from '../shared' | ||
20 | |||
21 | const listVideoCommentsValidator = [ | ||
22 | query('isLocal') | ||
23 | .optional() | ||
24 | .customSanitizer(toBooleanOrNull) | ||
25 | .custom(isBooleanValid) | ||
26 | .withMessage('Should have a valid isLocal boolean'), | ||
27 | |||
28 | query('onLocalVideo') | ||
29 | .optional() | ||
30 | .customSanitizer(toBooleanOrNull) | ||
31 | .custom(isBooleanValid) | ||
32 | .withMessage('Should have a valid onLocalVideo boolean'), | ||
33 | |||
34 | query('search') | ||
35 | .optional() | ||
36 | .custom(exists), | ||
37 | |||
38 | query('searchAccount') | ||
39 | .optional() | ||
40 | .custom(exists), | ||
41 | |||
42 | query('searchVideo') | ||
43 | .optional() | ||
44 | .custom(exists), | ||
45 | |||
46 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
47 | if (areValidationErrors(req, res)) return | ||
48 | |||
49 | return next() | ||
50 | } | ||
51 | ] | ||
52 | |||
53 | const listVideoCommentThreadsValidator = [ | ||
54 | isValidVideoIdParam('videoId'), | ||
55 | isValidVideoPasswordHeader(), | ||
56 | |||
57 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
58 | if (areValidationErrors(req, res)) return | ||
59 | if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return | ||
60 | |||
61 | if (!await checkCanSeeVideo({ req, res, paramId: req.params.videoId, video: res.locals.onlyVideo })) return | ||
62 | |||
63 | return next() | ||
64 | } | ||
65 | ] | ||
66 | |||
67 | const listVideoThreadCommentsValidator = [ | ||
68 | isValidVideoIdParam('videoId'), | ||
69 | |||
70 | param('threadId') | ||
71 | .custom(isIdValid), | ||
72 | isValidVideoPasswordHeader(), | ||
73 | |||
74 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
75 | if (areValidationErrors(req, res)) return | ||
76 | if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return | ||
77 | if (!await doesVideoCommentThreadExist(req.params.threadId, res.locals.onlyVideo, res)) return | ||
78 | |||
79 | if (!await checkCanSeeVideo({ req, res, paramId: req.params.videoId, video: res.locals.onlyVideo })) return | ||
80 | |||
81 | return next() | ||
82 | } | ||
83 | ] | ||
84 | |||
85 | const addVideoCommentThreadValidator = [ | ||
86 | isValidVideoIdParam('videoId'), | ||
87 | |||
88 | body('text') | ||
89 | .custom(isValidVideoCommentText), | ||
90 | isValidVideoPasswordHeader(), | ||
91 | |||
92 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
93 | if (areValidationErrors(req, res)) return | ||
94 | if (!await doesVideoExist(req.params.videoId, res)) return | ||
95 | |||
96 | if (!await checkCanSeeVideo({ req, res, paramId: req.params.videoId, video: res.locals.videoAll })) return | ||
97 | |||
98 | if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return | ||
99 | if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, false)) return | ||
100 | |||
101 | return next() | ||
102 | } | ||
103 | ] | ||
104 | |||
105 | const addVideoCommentReplyValidator = [ | ||
106 | isValidVideoIdParam('videoId'), | ||
107 | |||
108 | param('commentId').custom(isIdValid), | ||
109 | isValidVideoPasswordHeader(), | ||
110 | |||
111 | body('text').custom(isValidVideoCommentText), | ||
112 | |||
113 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
114 | if (areValidationErrors(req, res)) return | ||
115 | if (!await doesVideoExist(req.params.videoId, res)) return | ||
116 | |||
117 | if (!await checkCanSeeVideo({ req, res, paramId: req.params.videoId, video: res.locals.videoAll })) return | ||
118 | |||
119 | if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return | ||
120 | if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoAll, res)) return | ||
121 | if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, true)) return | ||
122 | |||
123 | return next() | ||
124 | } | ||
125 | ] | ||
126 | |||
127 | const videoCommentGetValidator = [ | ||
128 | isValidVideoIdParam('videoId'), | ||
129 | |||
130 | param('commentId') | ||
131 | .custom(isIdValid), | ||
132 | |||
133 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
134 | if (areValidationErrors(req, res)) return | ||
135 | if (!await doesVideoExist(req.params.videoId, res, 'id')) return | ||
136 | if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoId, res)) return | ||
137 | |||
138 | return next() | ||
139 | } | ||
140 | ] | ||
141 | |||
142 | const removeVideoCommentValidator = [ | ||
143 | isValidVideoIdParam('videoId'), | ||
144 | |||
145 | param('commentId') | ||
146 | .custom(isIdValid), | ||
147 | |||
148 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
149 | if (areValidationErrors(req, res)) return | ||
150 | if (!await doesVideoExist(req.params.videoId, res)) return | ||
151 | if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoAll, res)) return | ||
152 | |||
153 | // Check if the user who did the request is able to delete the video | ||
154 | if (!checkUserCanDeleteVideoComment(res.locals.oauth.token.User, res.locals.videoCommentFull, res)) return | ||
155 | |||
156 | return next() | ||
157 | } | ||
158 | ] | ||
159 | |||
160 | // --------------------------------------------------------------------------- | ||
161 | |||
162 | export { | ||
163 | listVideoCommentThreadsValidator, | ||
164 | listVideoThreadCommentsValidator, | ||
165 | addVideoCommentThreadValidator, | ||
166 | listVideoCommentsValidator, | ||
167 | addVideoCommentReplyValidator, | ||
168 | videoCommentGetValidator, | ||
169 | removeVideoCommentValidator | ||
170 | } | ||
171 | |||
172 | // --------------------------------------------------------------------------- | ||
173 | |||
174 | function isVideoCommentsEnabled (video: MVideo, res: express.Response) { | ||
175 | if (video.commentsEnabled !== true) { | ||
176 | res.fail({ | ||
177 | status: HttpStatusCode.CONFLICT_409, | ||
178 | message: 'Video comments are disabled for this video.' | ||
179 | }) | ||
180 | return false | ||
181 | } | ||
182 | |||
183 | return true | ||
184 | } | ||
185 | |||
186 | function checkUserCanDeleteVideoComment (user: MUserAccountUrl, videoComment: MCommentOwnerVideoReply, res: express.Response) { | ||
187 | if (videoComment.isDeleted()) { | ||
188 | res.fail({ | ||
189 | status: HttpStatusCode.CONFLICT_409, | ||
190 | message: 'This comment is already deleted' | ||
191 | }) | ||
192 | return false | ||
193 | } | ||
194 | |||
195 | const userAccount = user.Account | ||
196 | |||
197 | if ( | ||
198 | user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT) === false && // Not a moderator | ||
199 | videoComment.accountId !== userAccount.id && // Not the comment owner | ||
200 | videoComment.Video.VideoChannel.accountId !== userAccount.id // Not the video owner | ||
201 | ) { | ||
202 | res.fail({ | ||
203 | status: HttpStatusCode.FORBIDDEN_403, | ||
204 | message: 'Cannot remove video comment of another user' | ||
205 | }) | ||
206 | return false | ||
207 | } | ||
208 | |||
209 | return true | ||
210 | } | ||
211 | |||
212 | async function isVideoCommentAccepted (req: express.Request, res: express.Response, video: MVideoFullLight, isReply: boolean) { | ||
213 | const acceptParameters = { | ||
214 | video, | ||
215 | commentBody: req.body, | ||
216 | user: res.locals.oauth.token.User, | ||
217 | req | ||
218 | } | ||
219 | |||
220 | let acceptedResult: AcceptResult | ||
221 | |||
222 | if (isReply) { | ||
223 | const acceptReplyParameters = Object.assign(acceptParameters, { parentComment: res.locals.videoCommentFull }) | ||
224 | |||
225 | acceptedResult = await Hooks.wrapFun( | ||
226 | isLocalVideoCommentReplyAccepted, | ||
227 | acceptReplyParameters, | ||
228 | 'filter:api.video-comment-reply.create.accept.result' | ||
229 | ) | ||
230 | } else { | ||
231 | acceptedResult = await Hooks.wrapFun( | ||
232 | isLocalVideoThreadAccepted, | ||
233 | acceptParameters, | ||
234 | 'filter:api.video-thread.create.accept.result' | ||
235 | ) | ||
236 | } | ||
237 | |||
238 | if (!acceptedResult || acceptedResult.accepted !== true) { | ||
239 | logger.info('Refused local comment.', { acceptedResult, acceptParameters }) | ||
240 | |||
241 | res.fail({ | ||
242 | status: HttpStatusCode.FORBIDDEN_403, | ||
243 | message: acceptedResult?.errorMessage || 'Comment has been rejected.' | ||
244 | }) | ||
245 | return false | ||
246 | } | ||
247 | |||
248 | return true | ||
249 | } | ||