Optimize SQL requests of videos AP endpoints
This commit is contained in:
parent
ad76628b17
commit
96f29c0f6d
|
@ -6,7 +6,13 @@ import { CONFIG, ROUTE_CACHE_LIFETIME } from '../../initializers'
|
||||||
import { buildAnnounceWithVideoAudience } from '../../lib/activitypub/send'
|
import { buildAnnounceWithVideoAudience } from '../../lib/activitypub/send'
|
||||||
import { audiencify, getAudience } from '../../lib/activitypub/audience'
|
import { audiencify, getAudience } from '../../lib/activitypub/audience'
|
||||||
import { buildCreateActivity } from '../../lib/activitypub/send/send-create'
|
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 { videosGetValidator, videosShareValidator } from '../../middlewares/validators'
|
||||||
import { videoCommentGetValidator } from '../../middlewares/validators/video-comments'
|
import { videoCommentGetValidator } from '../../middlewares/validators/video-comments'
|
||||||
import { AccountModel } from '../../models/account/account'
|
import { AccountModel } from '../../models/account/account'
|
||||||
|
@ -54,7 +60,7 @@ activityPubClientRouter.get('/videos/watch/:id/activity',
|
||||||
executeIfActivityPub(asyncMiddleware(videoController))
|
executeIfActivityPub(asyncMiddleware(videoController))
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/announces',
|
activityPubClientRouter.get('/videos/watch/:id/announces',
|
||||||
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
|
executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))),
|
||||||
executeIfActivityPub(asyncMiddleware(videoAnnouncesController))
|
executeIfActivityPub(asyncMiddleware(videoAnnouncesController))
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/announces/:accountId',
|
activityPubClientRouter.get('/videos/watch/:id/announces/:accountId',
|
||||||
|
@ -62,15 +68,15 @@ activityPubClientRouter.get('/videos/watch/:id/announces/:accountId',
|
||||||
executeIfActivityPub(asyncMiddleware(videoAnnounceController))
|
executeIfActivityPub(asyncMiddleware(videoAnnounceController))
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/likes',
|
activityPubClientRouter.get('/videos/watch/:id/likes',
|
||||||
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
|
executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))),
|
||||||
executeIfActivityPub(asyncMiddleware(videoLikesController))
|
executeIfActivityPub(asyncMiddleware(videoLikesController))
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/dislikes',
|
activityPubClientRouter.get('/videos/watch/:id/dislikes',
|
||||||
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
|
executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))),
|
||||||
executeIfActivityPub(asyncMiddleware(videoDislikesController))
|
executeIfActivityPub(asyncMiddleware(videoDislikesController))
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:id/comments',
|
activityPubClientRouter.get('/videos/watch/:id/comments',
|
||||||
executeIfActivityPub(asyncMiddleware(videosGetValidator)),
|
executeIfActivityPub(asyncMiddleware(videosCustomGetValidator('only-video'))),
|
||||||
executeIfActivityPub(asyncMiddleware(videoCommentsController))
|
executeIfActivityPub(asyncMiddleware(videoCommentsController))
|
||||||
)
|
)
|
||||||
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId',
|
activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId',
|
||||||
|
|
|
@ -152,7 +152,8 @@ function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: Use
|
||||||
return true
|
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
|
let video: VideoModel | null
|
||||||
|
|
||||||
if (fetchType === 'all') {
|
if (fetchType === 'all') {
|
||||||
|
|
|
@ -61,7 +61,7 @@ function fetchRemoteVideoStaticFile (video: VideoModel, path: string, reject: Fu
|
||||||
|
|
||||||
async function fetchRemoteVideoDescription (video: VideoModel) {
|
async function fetchRemoteVideoDescription (video: VideoModel) {
|
||||||
const host = video.VideoChannel.Account.Actor.Server.host
|
const host = video.VideoChannel.Account.Actor.Server.host
|
||||||
const path = video.getDescriptionPath()
|
const path = video.getDescriptionAPIPath()
|
||||||
const options = {
|
const options = {
|
||||||
uri: REMOTE_SCHEME.HTTP + '://' + host + path,
|
uri: REMOTE_SCHEME.HTTP + '://' + host + path,
|
||||||
json: true
|
json: true
|
||||||
|
|
|
@ -78,7 +78,7 @@ const videoCommentGetValidator = [
|
||||||
logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
|
logger.debug('Checking videoCommentGetValidator parameters.', { parameters: req.params })
|
||||||
|
|
||||||
if (areValidationErrors(req, res)) return
|
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
|
if (!await isVideoCommentExist(req.params.commentId, res.locals.video, res)) return
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
|
|
|
@ -26,7 +26,8 @@ import {
|
||||||
isVideoPrivacyValid,
|
isVideoPrivacyValid,
|
||||||
isVideoRatingTypeValid,
|
isVideoRatingTypeValid,
|
||||||
isVideoSupportValid,
|
isVideoSupportValid,
|
||||||
isVideoTagsValid
|
isVideoTagsValid,
|
||||||
|
VideoFetchType
|
||||||
} from '../../helpers/custom-validators/videos'
|
} from '../../helpers/custom-validators/videos'
|
||||||
import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
|
import { getDurationFromVideoFile } from '../../helpers/ffmpeg-utils'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
|
@ -128,47 +129,49 @@ const videosUpdateValidator = getCommonVideoAttributes().concat([
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
const videosGetValidator = [
|
const videosCustomGetValidator = (fetchType: VideoFetchType) => {
|
||||||
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
|
return [
|
||||||
|
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
|
||||||
|
|
||||||
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
logger.debug('Checking videosGet parameters', { parameters: req.params })
|
logger.debug('Checking videosGet parameters', { parameters: req.params })
|
||||||
|
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
if (!await isVideoExist(req.params.id, 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
|
// Video private or blacklisted
|
||||||
if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) {
|
if (video.privacy === VideoPrivacy.PRIVATE || video.VideoBlacklist) {
|
||||||
return authenticate(req, res, () => {
|
return authenticate(req, res, () => {
|
||||||
const user: UserModel = res.locals.oauth.token.User
|
const user: UserModel = res.locals.oauth.token.User
|
||||||
|
|
||||||
// Only the owner or a user that have blacklist rights can see the video
|
// 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)) {
|
if (video.VideoChannel.Account.userId !== user.id && !user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)) {
|
||||||
return res.status(403)
|
return res.status(403)
|
||||||
.json({ error: 'Cannot get this private or blacklisted video.' })
|
.json({ error: 'Cannot get this private or blacklisted video.' })
|
||||||
.end()
|
.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
|
const videosGetValidator = videosCustomGetValidator('all')
|
||||||
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 videosRemoveValidator = [
|
const videosRemoveValidator = [
|
||||||
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
|
param('id').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid id'),
|
||||||
|
@ -366,6 +369,7 @@ export {
|
||||||
videosAddValidator,
|
videosAddValidator,
|
||||||
videosUpdateValidator,
|
videosUpdateValidator,
|
||||||
videosGetValidator,
|
videosGetValidator,
|
||||||
|
videosCustomGetValidator,
|
||||||
videosRemoveValidator,
|
videosRemoveValidator,
|
||||||
videosShareValidator,
|
videosShareValidator,
|
||||||
|
|
||||||
|
|
|
@ -112,12 +112,13 @@ function videoModelToFormattedDetailsJSON (video: VideoModel): VideoDetails {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const tags = video.Tags ? video.Tags.map(t => t.name) : []
|
||||||
const detailsJson = {
|
const detailsJson = {
|
||||||
support: video.support,
|
support: video.support,
|
||||||
descriptionPath: video.getDescriptionPath(),
|
descriptionPath: video.getDescriptionAPIPath(),
|
||||||
channel: video.VideoChannel.toFormattedJSON(),
|
channel: video.VideoChannel.toFormattedJSON(),
|
||||||
account: video.VideoChannel.Account.toFormattedJSON(),
|
account: video.VideoChannel.Account.toFormattedJSON(),
|
||||||
tags: video.Tags.map(t => t.name),
|
tags,
|
||||||
commentsEnabled: video.commentsEnabled,
|
commentsEnabled: video.commentsEnabled,
|
||||||
waitTranscoding: video.waitTranscoding,
|
waitTranscoding: video.waitTranscoding,
|
||||||
state: {
|
state: {
|
||||||
|
|
|
@ -1406,7 +1406,7 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
return getVideoFileResolution(originalFilePath)
|
return getVideoFileResolution(originalFilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
getDescriptionPath () {
|
getDescriptionAPIPath () {
|
||||||
return `/api/${API_VERSION}/videos/${this.uuid}/description`
|
return `/api/${API_VERSION}/videos/${this.uuid}/description`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue