]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/middlewares/validators/videos/video-comments.ts
Add akismet tests
[github/Chocobozzz/PeerTube.git] / server / middlewares / validators / videos / video-comments.ts
index 8adbb02ba13187a67ff4ad6d6732c12bc3b57ec8..133feb7bd4453ab09bb24b6f7f86892ff5cc21a2 100644 (file)
-import * as express from 'express'
-import { body, param } from 'express-validator'
-import { UserRight } from '../../../../shared'
-import { isIdOrUUIDValid, isIdValid } from '../../../helpers/custom-validators/misc'
+import express from 'express'
+import { body, param, query } from 'express-validator'
+import { MUserAccountUrl } from '@server/types/models'
+import { HttpStatusCode, UserRight } from '@shared/models'
+import { exists, isBooleanValid, isIdValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc'
 import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments'
 import { logger } from '../../../helpers/logger'
 import { isValidVideoCommentText } from '../../../helpers/custom-validators/video-comments'
 import { logger } from '../../../helpers/logger'
-import { VideoCommentModel } from '../../../models/video/video-comment'
-import { areValidationErrors } from '../utils'
-import { Hooks } from '../../../lib/plugins/hooks'
 import { AcceptResult, isLocalVideoCommentReplyAccepted, isLocalVideoThreadAccepted } from '../../../lib/moderation'
 import { AcceptResult, isLocalVideoCommentReplyAccepted, isLocalVideoThreadAccepted } from '../../../lib/moderation'
-import { doesVideoExist } from '../../../helpers/middlewares'
-import { MCommentOwner, MVideo, MVideoFullLight, MVideoId } from '../../../typings/models/video'
-import { MUser } from '@server/typings/models'
+import { Hooks } from '../../../lib/plugins/hooks'
+import { MCommentOwnerVideoReply, MVideo, MVideoFullLight } from '../../../types/models/video'
+import {
+  areValidationErrors,
+  checkCanSeeVideo,
+  doesVideoCommentExist,
+  doesVideoCommentThreadExist,
+  doesVideoExist,
+  isValidVideoIdParam
+} from '../shared'
+
+const listVideoCommentsValidator = [
+  query('isLocal')
+    .optional()
+    .customSanitizer(toBooleanOrNull)
+    .custom(isBooleanValid)
+    .withMessage('Should have a valid isLocal boolean'),
+
+  query('onLocalVideo')
+    .optional()
+    .customSanitizer(toBooleanOrNull)
+    .custom(isBooleanValid)
+    .withMessage('Should have a valid onLocalVideo boolean'),
+
+  query('search')
+    .optional()
+    .custom(exists),
+
+  query('searchAccount')
+    .optional()
+    .custom(exists),
+
+  query('searchVideo')
+    .optional()
+    .custom(exists),
+
+  (req: express.Request, res: express.Response, next: express.NextFunction) => {
+    if (areValidationErrors(req, res)) return
+
+    return next()
+  }
+]
 
 const listVideoCommentThreadsValidator = [
 
 const listVideoCommentThreadsValidator = [
-  param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
+  isValidVideoIdParam('videoId'),
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
 
   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking listVideoCommentThreads parameters.', { parameters: req.params })
-
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return
 
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return
 
+    if (!await checkCanSeeVideo({ req, res, paramId: req.params.videoId, video: res.locals.onlyVideo })) return
+
     return next()
   }
 ]
 
 const listVideoThreadCommentsValidator = [
     return next()
   }
 ]
 
 const listVideoThreadCommentsValidator = [
-  param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
-  param('threadId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid threadId'),
+  isValidVideoIdParam('videoId'),
 
 
-  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking listVideoThreadComments parameters.', { parameters: req.params })
+  param('threadId')
+    .custom(isIdValid),
 
 
+  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return
     if (!await doesVideoCommentThreadExist(req.params.threadId, res.locals.onlyVideo, res)) return
 
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res, 'only-video')) return
     if (!await doesVideoCommentThreadExist(req.params.threadId, res.locals.onlyVideo, res)) return
 
+    if (!await checkCanSeeVideo({ req, res, paramId: req.params.videoId, video: res.locals.onlyVideo })) return
+
     return next()
   }
 ]
 
 const addVideoCommentThreadValidator = [
     return next()
   }
 ]
 
 const addVideoCommentThreadValidator = [
-  param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
-  body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
+  isValidVideoIdParam('videoId'),
 
 
-  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking addVideoCommentThread parameters.', { parameters: req.params, body: req.body })
+  body('text')
+    .custom(isValidVideoCommentText),
 
 
+  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res)) return
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res)) return
+
+    if (!await checkCanSeeVideo({ req, res, paramId: req.params.videoId, video: res.locals.videoAll })) return
+
     if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
     if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
-    if (!await isVideoCommentAccepted(req, res, res.locals.videoAll,false)) return
+    if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, false)) return
 
     return next()
   }
 ]
 
 const addVideoCommentReplyValidator = [
 
     return next()
   }
 ]
 
 const addVideoCommentReplyValidator = [
-  param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
-  param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
-  body('text').custom(isValidVideoCommentText).not().isEmpty().withMessage('Should have a valid comment text'),
+  isValidVideoIdParam('videoId'),
 
 
-  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking addVideoCommentReply parameters.', { parameters: req.params, body: req.body })
+  param('commentId').custom(isIdValid),
+
+  body('text').custom(isValidVideoCommentText),
 
 
+  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res)) return
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res)) return
+
+    if (!await checkCanSeeVideo({ req, res, paramId: req.params.videoId, video: res.locals.videoAll })) return
+
     if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
     if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoAll, res)) return
     if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, true)) return
     if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
     if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoAll, res)) return
     if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, true)) return
@@ -75,12 +120,12 @@ const addVideoCommentReplyValidator = [
 ]
 
 const videoCommentGetValidator = [
 ]
 
 const videoCommentGetValidator = [
-  param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
-  param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
+  isValidVideoIdParam('videoId'),
 
 
-  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
+  param('commentId')
+    .custom(isIdValid),
 
 
+  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res, 'id')) return
     if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoId, res)) return
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res, 'id')) return
     if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoId, res)) return
@@ -90,12 +135,12 @@ const videoCommentGetValidator = [
 ]
 
 const removeVideoCommentValidator = [
 ]
 
 const removeVideoCommentValidator = [
-  param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid videoId'),
-  param('commentId').custom(isIdValid).not().isEmpty().withMessage('Should have a valid commentId'),
+  isValidVideoIdParam('videoId'),
 
 
-  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking removeVideoCommentValidator parameters.', { parameters: req.params })
+  param('commentId')
+    .custom(isIdValid),
 
 
+  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res)) return
     if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoAll, res)) return
     if (areValidationErrors(req, res)) return
     if (!await doesVideoExist(req.params.videoId, res)) return
     if (!await doesVideoCommentExist(req.params.commentId, res.locals.videoAll, res)) return
@@ -113,6 +158,7 @@ export {
   listVideoCommentThreadsValidator,
   listVideoThreadCommentsValidator,
   addVideoCommentThreadValidator,
   listVideoCommentThreadsValidator,
   listVideoThreadCommentsValidator,
   addVideoCommentThreadValidator,
+  listVideoCommentsValidator,
   addVideoCommentReplyValidator,
   videoCommentGetValidator,
   removeVideoCommentValidator
   addVideoCommentReplyValidator,
   videoCommentGetValidator,
   removeVideoCommentValidator
@@ -120,78 +166,38 @@ export {
 
 // ---------------------------------------------------------------------------
 
 
 // ---------------------------------------------------------------------------
 
-async function doesVideoCommentThreadExist (id: number, video: MVideoId, res: express.Response) {
-  const videoComment = await VideoCommentModel.loadById(id)
-
-  if (!videoComment) {
-    res.status(404)
-      .json({ error: 'Video comment thread not found' })
-      .end()
-
-    return false
-  }
-
-  if (videoComment.videoId !== video.id) {
-    res.status(400)
-      .json({ error: 'Video comment is associated to this video.' })
-      .end()
-
-    return false
-  }
-
-  if (videoComment.inReplyToCommentId !== null) {
-    res.status(400)
-      .json({ error: 'Video comment is not a thread.' })
-      .end()
-
-    return false
-  }
-
-  res.locals.videoCommentThread = videoComment
-  return true
-}
-
-async function doesVideoCommentExist (id: number, video: MVideoId, res: express.Response) {
-  const videoComment = await VideoCommentModel.loadByIdAndPopulateVideoAndAccountAndReply(id)
-
-  if (!videoComment) {
-    res.status(404)
-      .json({ error: 'Video comment thread not found' })
-      .end()
-
-    return false
-  }
-
-  if (videoComment.videoId !== video.id) {
-    res.status(400)
-      .json({ error: 'Video comment is associated to this video.' })
-      .end()
-
+function isVideoCommentsEnabled (video: MVideo, res: express.Response) {
+  if (video.commentsEnabled !== true) {
+    res.fail({
+      status: HttpStatusCode.CONFLICT_409,
+      message: 'Video comments are disabled for this video.'
+    })
     return false
   }
 
     return false
   }
 
-  res.locals.videoCommentFull = videoComment
   return true
 }
 
   return true
 }
 
-function isVideoCommentsEnabled (video: MVideo, res: express.Response) {
-  if (video.commentsEnabled !== true) {
-    res.status(409)
-      .json({ error: 'Video comments are disabled for this video.' })
-      .end()
-
+function checkUserCanDeleteVideoComment (user: MUserAccountUrl, videoComment: MCommentOwnerVideoReply, res: express.Response) {
+  if (videoComment.isDeleted()) {
+    res.fail({
+      status: HttpStatusCode.CONFLICT_409,
+      message: 'This comment is already deleted'
+    })
     return false
   }
 
     return false
   }
 
-  return true
-}
+  const userAccount = user.Account
 
 
-function checkUserCanDeleteVideoComment (user: MUser, videoComment: MCommentOwner, res: express.Response) {
-  const account = videoComment.Account
-  if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT) === false && account.userId !== user.id) {
-    res.status(403)
-      .json({ error: 'Cannot remove video comment of another user' })
-      .end()
+  if (
+    user.hasRight(UserRight.REMOVE_ANY_VIDEO_COMMENT) === false && // Not a moderator
+    videoComment.accountId !== userAccount.id && // Not the comment owner
+    videoComment.Video.VideoChannel.accountId !== userAccount.id // Not the video owner
+  ) {
+    res.fail({
+      status: HttpStatusCode.FORBIDDEN_403,
+      message: 'Cannot remove video comment of another user'
+    })
     return false
   }
 
     return false
   }
 
@@ -202,7 +208,8 @@ async function isVideoCommentAccepted (req: express.Request, res: express.Respon
   const acceptParameters = {
     video,
     commentBody: req.body,
   const acceptParameters = {
     video,
     commentBody: req.body,
-    user: res.locals.oauth.token.User
+    user: res.locals.oauth.token.User,
+    req
   }
 
   let acceptedResult: AcceptResult
   }
 
   let acceptedResult: AcceptResult
@@ -225,9 +232,11 @@ async function isVideoCommentAccepted (req: express.Request, res: express.Respon
 
   if (!acceptedResult || acceptedResult.accepted !== true) {
     logger.info('Refused local comment.', { acceptedResult, acceptParameters })
 
   if (!acceptedResult || acceptedResult.accepted !== true) {
     logger.info('Refused local comment.', { acceptedResult, acceptParameters })
-    res.status(403)
-              .json({ error: acceptedResult.errorMessage || 'Refused local comment' })
 
 
+    res.fail({
+      status: HttpStatusCode.FORBIDDEN_403,
+      message: acceptedResult?.errorMessage || 'Comment has been rejected.'
+    })
     return false
   }
 
     return false
   }