Optimize SQL requests of videos AP endpoints

pull/1093/head
Chocobozzz 2018-09-19 10:16:44 +02:00
parent ad76628b17
commit 96f29c0f6d
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
7 changed files with 56 additions and 44 deletions

View File

@ -6,7 +6,13 @@ import { CONFIG, ROUTE_CACHE_LIFETIME } from '../../initializers'
import { buildAnnounceWithVideoAudience } from '../../lib/activitypub/send'
import { audiencify, getAudience } from '../../lib/activitypub/audience'
import { buildCreateActivity } from '../../lib/activitypub/send/send-create'
import { asyncMiddleware, executeIfActivityPub, localAccountValidator, localVideoChannelValidator } from '../../middlewares'
import {
asyncMiddleware,
executeIfActivityPub,
localAccountValidator,
localVideoChannelValidator,
videosCustomGetValidator
} from '../../middlewares'
import { videosGetValidator, videosShareValidator } from '../../middlewares/validators'
import { videoCommentGetValidator } from '../../middlewares/validators/video-comments'
import { AccountModel } from '../../models/account/account'
@ -54,7 +60,7 @@ activityPubClientRouter.get('/videos/watch/:id/activity',
executeIfActivityPub(asyncMiddleware(videoController))
)
activityPubClientRouter.get('/videos/watch/:id/announces',
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))),
executeIfActivityPub(asyncMiddleware(videoAnnouncesController))
)
activityPubClientRouter.get('/videos/watch/:id/announces/:accountId',
@ -62,15 +68,15 @@ activityPubClientRouter.get('/videos/watch/:id/announces/:accountId',
executeIfActivityPub(asyncMiddleware(videoAnnounceController))
)
activityPubClientRouter.get('/videos/watch/:id/likes',
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))),
executeIfActivityPub(asyncMiddleware(videoLikesController))
)
activityPubClientRouter.get('/videos/watch/:id/dislikes',
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))),
executeIfActivityPub(asyncMiddleware(videoDislikesController))
)
activityPubClientRouter.get('/videos/watch/:id/comments',
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))),
executeIfActivityPub(asyncMiddleware(videoCommentsController))
)
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId',

View File

@ -152,7 +152,8 @@ function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: Use
return true
}
async function isVideoExist (id: string, res: Response, fetchType: 'all' | 'only-video' | 'id' | 'none' = 'all') {
export type VideoFetchType = 'all' | 'only-video' | 'id' | 'none'
async function isVideoExist (id: string, res: Response, fetchType: VideoFetchType = 'all') {
let video: VideoModel | null
if (fetchType === 'all') {

View File

@ -61,7 +61,7 @@ function fetchRemoteVideoStaticFile (video: VideoModel, path: string, reject: Fu
async function fetchRemoteVideoDescription (video: VideoModel) {
const host = video.VideoChannel.Account.Actor.Server.host
const path = video.getDescriptionPath()
const path = video.getDescriptionAPIPath()
const options = {
uri: REMOTE_SCHEME.HTTP + '://' + host + path,
json: true

View File

@ -78,7 +78,7 @@ const videoCommentGetValidator = [
logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
if (areValidationErrors(req, res)) return
if (!await isVideoExist(req.params.videoId, res)) return
if (!await isVideoExist(req.params.videoId, res, 'id')) return
if (!await isVideoCommentExist(req.params.commentId, res.locals.video, res)) return
return next()

View File

@ -26,7 +26,8 @@ import {
isVideoPrivacyValid,
isVideoRatingTypeValid,
isVideoSupportValid,
isVideoTagsValid
isVideoTagsValid,
VideoFetchType
} from '../../helpers/custom-validators/videos'
import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
import { logger } from '../../helpers/logger'
@ -128,47 +129,49 @@ const videosUpdateValidator = getCommonVideoAttributes().concat([
}
])
const videosGetValidator = [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
const videosCustomGetValidator = (fetchType: VideoFetchType) => {
return [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videosGet parameters', { parameters: req.params })
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking videosGet parameters', { parameters: req.params })
if (areValidationErrors(req, res)) return
if (!await isVideoExist(req.params.id, res)) return
if (areValidationErrors(req, res)) return
if (!await isVideoExist(req.params.id, res, fetchType)) return
const video: VideoModel = res.locals.video
const video: VideoModel = res.locals.video
// Video private or blacklisted
if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) {
return authenticate(req, res, () => {
const user: UserModel = res.locals.oauth.token.User
// Video private or blacklisted
if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) {
return authenticate(req, res, () => {
const user: UserModel = res.locals.oauth.token.User
// Only the owner or a user that have blacklist rights can see the video
if (video.VideoChannel.Account.userId !== user.id && !user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)) {
return res.status(403)
.json({ error: 'Cannot get this private or blacklisted video.' })
.end()
}
// Only the owner or a user that have blacklist rights can see the video
if (video.VideoChannel.Account.userId !== user.id && !user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)) {
return res.status(403)
.json({ error: 'Cannot get this private or blacklisted video.' })
.end()
}
return next()
})
return next()
})
}
return
// Video is public, anyone can access it
if (video.privacy === VideoPrivacy.PUBLIC) return next()
// Video is unlisted, check we used the uuid to fetch it
if (video.privacy === VideoPrivacy.UNLISTED) {
if (isUUIDValid(req.params.id)) return next()
// Don't leak this unlisted video
return res.status(404).end()
}
}
]
}
// Video is public, anyone can access it
if (video.privacy === VideoPrivacy.PUBLIC) return next()
// Video is unlisted, check we used the uuid to fetch it
if (video.privacy === VideoPrivacy.UNLISTED) {
if (isUUIDValid(req.params.id)) return next()
// Don't leak this unlisted video
return res.status(404).end()
}
}
]
const videosGetValidator = videosCustomGetValidator('all')
const videosRemoveValidator = [
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
@ -366,6 +369,7 @@ export {
videosAddValidator,
videosUpdateValidator,
videosGetValidator,
videosCustomGetValidator,
videosRemoveValidator,
videosShareValidator,

View File

@ -112,12 +112,13 @@ function videoModelToFormattedDetailsJSON (video: VideoModel): VideoDetails {
}
})
const tags = video.Tags ? video.Tags.map(t => t.name) : []
const detailsJson = {
support: video.support,
descriptionPath: video.getDescriptionPath(),
descriptionPath: video.getDescriptionAPIPath(),
channel: video.VideoChannel.toFormattedJSON(),
account: video.VideoChannel.Account.toFormattedJSON(),
tags: video.Tags.map(t => t.name),
tags,
commentsEnabled: video.commentsEnabled,
waitTranscoding: video.waitTranscoding,
state: {

View File

@ -1406,7 +1406,7 @@ export class VideoModel extends Model<VideoModel> {
return getVideoFileResolution(originalFilePath)
}
getDescriptionPath () {
getDescriptionAPIPath () {
return `/api/${API_VERSION}/videos/${this.uuid}/description`
}