Use async/await in controllers
This commit is contained in:
parent
5f04dd2f74
commit
eb08047657
|
@ -2,30 +2,32 @@ import * as express from 'express'
|
|||
|
||||
import { isSignupAllowed } from '../../helpers'
|
||||
import { CONFIG } from '../../initializers'
|
||||
import { asyncMiddleware } from '../../middlewares'
|
||||
import { ServerConfig } from '../../../shared'
|
||||
|
||||
const configRouter = express.Router()
|
||||
|
||||
configRouter.get('/', getConfig)
|
||||
configRouter.get('/',
|
||||
asyncMiddleware(getConfig)
|
||||
)
|
||||
|
||||
function getConfig (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function getConfig (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const allowed = await isSignupAllowed()
|
||||
|
||||
isSignupAllowed().then(allowed => {
|
||||
const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
|
||||
.filter(key => CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
|
||||
.map(r => parseInt(r, 10))
|
||||
const enabledResolutions = Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
|
||||
.filter(key => CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
|
||||
.map(r => parseInt(r, 10))
|
||||
|
||||
const json: ServerConfig = {
|
||||
signup: {
|
||||
allowed
|
||||
},
|
||||
transcoding: {
|
||||
enabledResolutions
|
||||
}
|
||||
const json: ServerConfig = {
|
||||
signup: {
|
||||
allowed
|
||||
},
|
||||
transcoding: {
|
||||
enabledResolutions
|
||||
}
|
||||
}
|
||||
|
||||
res.json(json)
|
||||
})
|
||||
return res.json(json)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -2,15 +2,18 @@ import * as express from 'express'
|
|||
|
||||
import { CONFIG } from '../../initializers'
|
||||
import { logger } from '../../helpers'
|
||||
import { asyncMiddleware } from '../../middlewares'
|
||||
import { database as db } from '../../initializers/database'
|
||||
import { OAuthClientLocal } from '../../../shared'
|
||||
|
||||
const oauthClientsRouter = express.Router()
|
||||
|
||||
oauthClientsRouter.get('/local', getLocalClient)
|
||||
oauthClientsRouter.get('/local',
|
||||
asyncMiddleware(getLocalClient)
|
||||
)
|
||||
|
||||
// Get the client credentials for the PeerTube front end
|
||||
function getLocalClient (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function getLocalClient (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const serverHostname = CONFIG.WEBSERVER.HOSTNAME
|
||||
const serverPort = CONFIG.WEBSERVER.PORT
|
||||
let headerHostShouldBe = serverHostname
|
||||
|
@ -24,17 +27,14 @@ function getLocalClient (req: express.Request, res: express.Response, next: expr
|
|||
return res.type('json').status(403).end()
|
||||
}
|
||||
|
||||
db.OAuthClient.loadFirstClient()
|
||||
.then(client => {
|
||||
if (!client) throw new Error('No client available.')
|
||||
const client = await db.OAuthClient.loadFirstClient()
|
||||
if (!client) throw new Error('No client available.')
|
||||
|
||||
const json: OAuthClientLocal = {
|
||||
client_id: client.clientId,
|
||||
client_secret: client.clientSecret
|
||||
}
|
||||
res.json(json)
|
||||
})
|
||||
.catch(err => next(err))
|
||||
const json: OAuthClientLocal = {
|
||||
client_id: client.clientId,
|
||||
client_secret: client.clientSecret
|
||||
}
|
||||
return res.json(json)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -16,7 +16,8 @@ import {
|
|||
paginationValidator,
|
||||
setPagination,
|
||||
setPodsSort,
|
||||
podsSortValidator
|
||||
podsSortValidator,
|
||||
asyncMiddleware
|
||||
} from '../../middlewares'
|
||||
import { PodInstance } from '../../models'
|
||||
|
||||
|
@ -27,25 +28,25 @@ podsRouter.get('/',
|
|||
podsSortValidator,
|
||||
setPodsSort,
|
||||
setPagination,
|
||||
listPods
|
||||
asyncMiddleware(listPods)
|
||||
)
|
||||
podsRouter.post('/make-friends',
|
||||
authenticate,
|
||||
ensureIsAdmin,
|
||||
makeFriendsValidator,
|
||||
setBodyHostsPort,
|
||||
makeFriendsController
|
||||
asyncMiddleware(makeFriendsController)
|
||||
)
|
||||
podsRouter.get('/quit-friends',
|
||||
authenticate,
|
||||
ensureIsAdmin,
|
||||
quitFriendsController
|
||||
asyncMiddleware(quitFriendsController)
|
||||
)
|
||||
podsRouter.delete('/:id',
|
||||
authenticate,
|
||||
ensureIsAdmin,
|
||||
podRemoveValidator,
|
||||
removeFriendController
|
||||
asyncMiddleware(removeFriendController)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -56,33 +57,33 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function listPods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.Pod.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
.then(resultList => res.json(getFormattedObjects(resultList.data, resultList.total)))
|
||||
.catch(err => next(err))
|
||||
async function listPods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.Pod.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
function makeFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function makeFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const hosts = req.body.hosts as string[]
|
||||
|
||||
// Don't wait the process that could be long
|
||||
makeFriends(hosts)
|
||||
.then(() => logger.info('Made friends!'))
|
||||
.catch(err => logger.error('Could not make friends.', err))
|
||||
|
||||
// Don't wait the process that could be long
|
||||
res.type('json').status(204).end()
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function quitFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
quitFriends()
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
async function quitFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
await quitFriends()
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function removeFriendController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function removeFriendController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const pod = res.locals.pod as PodInstance
|
||||
|
||||
removeFriend(pod)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
await removeFriend(pod)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@ import {
|
|||
checkSignature,
|
||||
signatureValidator,
|
||||
setBodyHostPort,
|
||||
remotePodsAddValidator
|
||||
remotePodsAddValidator,
|
||||
asyncMiddleware
|
||||
} from '../../../middlewares'
|
||||
import { sendOwnedDataToPod } from '../../../lib'
|
||||
import { getMyPublicCert, getFormattedObjects } from '../../../helpers'
|
||||
|
@ -18,15 +19,17 @@ const remotePodsRouter = express.Router()
|
|||
remotePodsRouter.post('/remove',
|
||||
signatureValidator,
|
||||
checkSignature,
|
||||
removePods
|
||||
asyncMiddleware(removePods)
|
||||
)
|
||||
|
||||
remotePodsRouter.post('/list', remotePodsList)
|
||||
remotePodsRouter.post('/list',
|
||||
asyncMiddleware(remotePodsList)
|
||||
)
|
||||
|
||||
remotePodsRouter.post('/add',
|
||||
setBodyHostPort, // We need to modify the host before running the validator!
|
||||
remotePodsAddValidator,
|
||||
addPods
|
||||
asyncMiddleware(addPods)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -37,35 +40,30 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function addPods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function addPods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const information = req.body
|
||||
|
||||
const pod = db.Pod.build(information)
|
||||
pod.save()
|
||||
.then(podCreated => {
|
||||
return sendOwnedDataToPod(podCreated.id)
|
||||
})
|
||||
.then(() => {
|
||||
return getMyPublicCert()
|
||||
})
|
||||
.then(cert => {
|
||||
return res.json({ cert: cert, email: CONFIG.ADMIN.EMAIL })
|
||||
})
|
||||
.catch(err => next(err))
|
||||
const podCreated = await pod.save()
|
||||
|
||||
await sendOwnedDataToPod(podCreated.id)
|
||||
|
||||
const cert = await getMyPublicCert()
|
||||
return res.json({ cert, email: CONFIG.ADMIN.EMAIL })
|
||||
}
|
||||
|
||||
function remotePodsList (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.Pod.list()
|
||||
.then(podsList => res.json(getFormattedObjects<FormattedPod, PodInstance>(podsList, podsList.length)))
|
||||
.catch(err => next(err))
|
||||
async function remotePodsList (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const pods = await db.Pod.list()
|
||||
|
||||
return res.json(getFormattedObjects<FormattedPod, PodInstance>(pods, pods.length))
|
||||
}
|
||||
|
||||
function removePods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function removePods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const signature: PodSignature = req.body.signature
|
||||
const host = signature.host
|
||||
|
||||
db.Pod.loadByHost(host)
|
||||
.then(pod => pod.destroy())
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
const pod = await db.Pod.loadByHost(host)
|
||||
await pod.destroy()
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as express from 'express'
|
||||
import * as Promise from 'bluebird'
|
||||
import * as Bluebird from 'bluebird'
|
||||
import * as Sequelize from 'sequelize'
|
||||
|
||||
import { database as db } from '../../../initializers/database'
|
||||
|
@ -17,7 +17,7 @@ import {
|
|||
remoteEventsVideosValidator
|
||||
} from '../../../middlewares'
|
||||
import { logger, retryTransactionWrapper } from '../../../helpers'
|
||||
import { quickAndDirtyUpdatesVideoToFriends } from '../../../lib'
|
||||
import { quickAndDirtyUpdatesVideoToFriends, fetchVideoChannelByHostAndUUID } from '../../../lib'
|
||||
import { PodInstance, VideoFileInstance } from '../../../models'
|
||||
import {
|
||||
RemoteVideoRequest,
|
||||
|
@ -87,7 +87,7 @@ function remoteVideos (req: express.Request, res: express.Response, next: expres
|
|||
const fromPod = res.locals.secure.pod
|
||||
|
||||
// We need to process in the same order to keep consistency
|
||||
Promise.each(requests, request => {
|
||||
Bluebird.each(requests, request => {
|
||||
const data = request.data
|
||||
|
||||
// Get the function we need to call in order to process the request
|
||||
|
@ -109,7 +109,7 @@ function remoteVideosQadu (req: express.Request, res: express.Response, next: ex
|
|||
const requests: RemoteQaduVideoRequest[] = req.body.data
|
||||
const fromPod = res.locals.secure.pod
|
||||
|
||||
Promise.each(requests, request => {
|
||||
Bluebird.each(requests, request => {
|
||||
const videoData = request.data
|
||||
|
||||
return quickAndDirtyUpdateVideoRetryWrapper(videoData, fromPod)
|
||||
|
@ -123,7 +123,7 @@ function remoteVideosEvents (req: express.Request, res: express.Response, next:
|
|||
const requests: RemoteVideoEventRequest[] = req.body.data
|
||||
const fromPod = res.locals.secure.pod
|
||||
|
||||
Promise.each(requests, request => {
|
||||
Bluebird.each(requests, request => {
|
||||
const eventData = request.data
|
||||
|
||||
return processVideosEventsRetryWrapper(eventData, fromPod)
|
||||
|
@ -133,541 +133,447 @@ function remoteVideosEvents (req: express.Request, res: express.Response, next:
|
|||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function processVideosEventsRetryWrapper (eventData: RemoteVideoEventData, fromPod: PodInstance) {
|
||||
async function processVideosEventsRetryWrapper (eventData: RemoteVideoEventData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ eventData, fromPod ],
|
||||
errorMessage: 'Cannot process videos events with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(processVideosEvents, options)
|
||||
await retryTransactionWrapper(processVideosEvents, options)
|
||||
}
|
||||
|
||||
function processVideosEvents (eventData: RemoteVideoEventData, fromPod: PodInstance) {
|
||||
async function processVideosEvents (eventData: RemoteVideoEventData, fromPod: PodInstance) {
|
||||
await db.sequelize.transaction(async t => {
|
||||
const sequelizeOptions = { transaction: t }
|
||||
const videoInstance = await fetchVideoByUUID(eventData.uuid, t)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return fetchVideoByUUID(eventData.uuid, t)
|
||||
.then(videoInstance => {
|
||||
const options = { transaction: t }
|
||||
let columnToUpdate
|
||||
let qaduType
|
||||
|
||||
let columnToUpdate
|
||||
let qaduType
|
||||
switch (eventData.eventType) {
|
||||
case REQUEST_VIDEO_EVENT_TYPES.VIEWS:
|
||||
columnToUpdate = 'views'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.VIEWS
|
||||
break
|
||||
|
||||
switch (eventData.eventType) {
|
||||
case REQUEST_VIDEO_EVENT_TYPES.VIEWS:
|
||||
columnToUpdate = 'views'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.VIEWS
|
||||
break
|
||||
case REQUEST_VIDEO_EVENT_TYPES.LIKES:
|
||||
columnToUpdate = 'likes'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.LIKES
|
||||
break
|
||||
|
||||
case REQUEST_VIDEO_EVENT_TYPES.LIKES:
|
||||
columnToUpdate = 'likes'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.LIKES
|
||||
break
|
||||
case REQUEST_VIDEO_EVENT_TYPES.DISLIKES:
|
||||
columnToUpdate = 'dislikes'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.DISLIKES
|
||||
break
|
||||
|
||||
case REQUEST_VIDEO_EVENT_TYPES.DISLIKES:
|
||||
columnToUpdate = 'dislikes'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.DISLIKES
|
||||
break
|
||||
default:
|
||||
throw new Error('Unknown video event type.')
|
||||
}
|
||||
|
||||
default:
|
||||
throw new Error('Unknown video event type.')
|
||||
}
|
||||
const query = {}
|
||||
query[columnToUpdate] = eventData.count
|
||||
|
||||
const query = {}
|
||||
query[columnToUpdate] = eventData.count
|
||||
await videoInstance.increment(query, sequelizeOptions)
|
||||
|
||||
return videoInstance.increment(query, options).then(() => ({ videoInstance, qaduType }))
|
||||
})
|
||||
.then(({ videoInstance, qaduType }) => {
|
||||
const qadusParams = [
|
||||
{
|
||||
videoId: videoInstance.id,
|
||||
type: qaduType
|
||||
}
|
||||
]
|
||||
|
||||
return quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('Remote video event processed for video with uuid %s.', eventData.uuid))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot process a video event.', err)
|
||||
throw err
|
||||
const qadusParams = [
|
||||
{
|
||||
videoId: videoInstance.id,
|
||||
type: qaduType
|
||||
}
|
||||
]
|
||||
await quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
|
||||
})
|
||||
|
||||
logger.info('Remote video event processed for video with uuid %s.', eventData.uuid)
|
||||
}
|
||||
|
||||
function quickAndDirtyUpdateVideoRetryWrapper (videoData: RemoteQaduVideoData, fromPod: PodInstance) {
|
||||
async function quickAndDirtyUpdateVideoRetryWrapper (videoData: RemoteQaduVideoData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoData, fromPod ],
|
||||
errorMessage: 'Cannot update quick and dirty the remote video with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(quickAndDirtyUpdateVideo, options)
|
||||
await retryTransactionWrapper(quickAndDirtyUpdateVideo, options)
|
||||
}
|
||||
|
||||
function quickAndDirtyUpdateVideo (videoData: RemoteQaduVideoData, fromPod: PodInstance) {
|
||||
async function quickAndDirtyUpdateVideo (videoData: RemoteQaduVideoData, fromPod: PodInstance) {
|
||||
let videoUUID = ''
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return fetchVideoByHostAndUUID(fromPod.host, videoData.uuid, t)
|
||||
.then(videoInstance => {
|
||||
const options = { transaction: t }
|
||||
await db.sequelize.transaction(async t => {
|
||||
const videoInstance = await fetchVideoByHostAndUUID(fromPod.host, videoData.uuid, t)
|
||||
const sequelizeOptions = { transaction: t }
|
||||
|
||||
videoUUID = videoInstance.uuid
|
||||
videoUUID = videoInstance.uuid
|
||||
|
||||
if (videoData.views) {
|
||||
videoInstance.set('views', videoData.views)
|
||||
}
|
||||
if (videoData.views) {
|
||||
videoInstance.set('views', videoData.views)
|
||||
}
|
||||
|
||||
if (videoData.likes) {
|
||||
videoInstance.set('likes', videoData.likes)
|
||||
}
|
||||
if (videoData.likes) {
|
||||
videoInstance.set('likes', videoData.likes)
|
||||
}
|
||||
|
||||
if (videoData.dislikes) {
|
||||
videoInstance.set('dislikes', videoData.dislikes)
|
||||
}
|
||||
if (videoData.dislikes) {
|
||||
videoInstance.set('dislikes', videoData.dislikes)
|
||||
}
|
||||
|
||||
return videoInstance.save(options)
|
||||
})
|
||||
await videoInstance.save(sequelizeOptions)
|
||||
})
|
||||
.then(() => logger.info('Remote video with uuid %s quick and dirty updated', videoUUID))
|
||||
.catch(err => logger.debug('Cannot quick and dirty update the remote video.', err))
|
||||
|
||||
logger.info('Remote video with uuid %s quick and dirty updated', videoUUID)
|
||||
}
|
||||
|
||||
// Handle retries on fail
|
||||
function addRemoteVideoRetryWrapper (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) {
|
||||
async function addRemoteVideoRetryWrapper (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoToCreateData, fromPod ],
|
||||
errorMessage: 'Cannot insert the remote video with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(addRemoteVideo, options)
|
||||
await retryTransactionWrapper(addRemoteVideo, options)
|
||||
}
|
||||
|
||||
function addRemoteVideo (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) {
|
||||
async function addRemoteVideo (videoToCreateData: RemoteVideoCreateData, fromPod: PodInstance) {
|
||||
logger.debug('Adding remote video "%s".', videoToCreateData.uuid)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return db.Video.loadByUUID(videoToCreateData.uuid)
|
||||
.then(video => {
|
||||
if (video) throw new Error('UUID already exists.')
|
||||
await db.sequelize.transaction(async t => {
|
||||
const sequelizeOptions = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
return db.VideoChannel.loadByHostAndUUID(fromPod.host, videoToCreateData.channelUUID, t)
|
||||
const videoFromDatabase = await db.Video.loadByUUID(videoToCreateData.uuid)
|
||||
if (videoFromDatabase) throw new Error('UUID already exists.')
|
||||
|
||||
const videoChannel = await db.VideoChannel.loadByHostAndUUID(fromPod.host, videoToCreateData.channelUUID, t)
|
||||
if (!videoChannel) throw new Error('Video channel ' + videoToCreateData.channelUUID + ' not found.')
|
||||
|
||||
const tags = videoToCreateData.tags
|
||||
const tagInstances = await db.Tag.findOrCreateTags(tags, t)
|
||||
|
||||
const videoData = {
|
||||
name: videoToCreateData.name,
|
||||
uuid: videoToCreateData.uuid,
|
||||
category: videoToCreateData.category,
|
||||
licence: videoToCreateData.licence,
|
||||
language: videoToCreateData.language,
|
||||
nsfw: videoToCreateData.nsfw,
|
||||
description: videoToCreateData.description,
|
||||
channelId: videoChannel.id,
|
||||
duration: videoToCreateData.duration,
|
||||
createdAt: videoToCreateData.createdAt,
|
||||
// FIXME: updatedAt does not seems to be considered by Sequelize
|
||||
updatedAt: videoToCreateData.updatedAt,
|
||||
views: videoToCreateData.views,
|
||||
likes: videoToCreateData.likes,
|
||||
dislikes: videoToCreateData.dislikes,
|
||||
remote: true
|
||||
}
|
||||
|
||||
const video = db.Video.build(videoData)
|
||||
await db.Video.generateThumbnailFromData(video, videoToCreateData.thumbnailData)
|
||||
const videoCreated = await video.save(sequelizeOptions)
|
||||
|
||||
const tasks = []
|
||||
for (const fileData of videoToCreateData.files) {
|
||||
const videoFileInstance = db.VideoFile.build({
|
||||
extname: fileData.extname,
|
||||
infoHash: fileData.infoHash,
|
||||
resolution: fileData.resolution,
|
||||
size: fileData.size,
|
||||
videoId: videoCreated.id
|
||||
})
|
||||
.then(videoChannel => {
|
||||
if (!videoChannel) throw new Error('Video channel ' + videoToCreateData.channelUUID + ' not found.')
|
||||
|
||||
const tags = videoToCreateData.tags
|
||||
tasks.push(videoFileInstance.save(sequelizeOptions))
|
||||
}
|
||||
|
||||
return db.Tag.findOrCreateTags(tags, t).then(tagInstances => ({ videoChannel, tagInstances }))
|
||||
})
|
||||
.then(({ videoChannel, tagInstances }) => {
|
||||
const videoData = {
|
||||
name: videoToCreateData.name,
|
||||
uuid: videoToCreateData.uuid,
|
||||
category: videoToCreateData.category,
|
||||
licence: videoToCreateData.licence,
|
||||
language: videoToCreateData.language,
|
||||
nsfw: videoToCreateData.nsfw,
|
||||
description: videoToCreateData.description,
|
||||
channelId: videoChannel.id,
|
||||
duration: videoToCreateData.duration,
|
||||
createdAt: videoToCreateData.createdAt,
|
||||
// FIXME: updatedAt does not seems to be considered by Sequelize
|
||||
updatedAt: videoToCreateData.updatedAt,
|
||||
views: videoToCreateData.views,
|
||||
likes: videoToCreateData.likes,
|
||||
dislikes: videoToCreateData.dislikes,
|
||||
remote: true
|
||||
}
|
||||
await Promise.all(tasks)
|
||||
|
||||
const video = db.Video.build(videoData)
|
||||
return { tagInstances, video }
|
||||
})
|
||||
.then(({ tagInstances, video }) => {
|
||||
return db.Video.generateThumbnailFromData(video, videoToCreateData.thumbnailData).then(() => ({ tagInstances, video }))
|
||||
})
|
||||
.then(({ tagInstances, video }) => {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
return video.save(options).then(videoCreated => ({ tagInstances, videoCreated }))
|
||||
})
|
||||
.then(({ tagInstances, videoCreated }) => {
|
||||
const tasks = []
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
videoToCreateData.files.forEach(fileData => {
|
||||
const videoFileInstance = db.VideoFile.build({
|
||||
extname: fileData.extname,
|
||||
infoHash: fileData.infoHash,
|
||||
resolution: fileData.resolution,
|
||||
size: fileData.size,
|
||||
videoId: videoCreated.id
|
||||
})
|
||||
|
||||
tasks.push(videoFileInstance.save(options))
|
||||
})
|
||||
|
||||
return Promise.all(tasks).then(() => ({ tagInstances, videoCreated }))
|
||||
})
|
||||
.then(({ tagInstances, videoCreated }) => {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
return videoCreated.setTags(tagInstances, options)
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('Remote video with uuid %s inserted.', videoToCreateData.uuid))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot insert the remote video.', err)
|
||||
throw err
|
||||
await videoCreated.setTags(tagInstances, sequelizeOptions)
|
||||
})
|
||||
|
||||
logger.info('Remote video with uuid %s inserted.', videoToCreateData.uuid)
|
||||
}
|
||||
|
||||
// Handle retries on fail
|
||||
function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) {
|
||||
async function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoAttributesToUpdate, fromPod ],
|
||||
errorMessage: 'Cannot update the remote video with many retries'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(updateRemoteVideo, options)
|
||||
await retryTransactionWrapper(updateRemoteVideo, options)
|
||||
}
|
||||
|
||||
function updateRemoteVideo (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) {
|
||||
async function updateRemoteVideo (videoAttributesToUpdate: RemoteVideoUpdateData, fromPod: PodInstance) {
|
||||
logger.debug('Updating remote video "%s".', videoAttributesToUpdate.uuid)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return fetchVideoByHostAndUUID(fromPod.host, videoAttributesToUpdate.uuid, t)
|
||||
.then(videoInstance => {
|
||||
const tags = videoAttributesToUpdate.tags
|
||||
try {
|
||||
await db.sequelize.transaction(async t => {
|
||||
const sequelizeOptions = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
return db.Tag.findOrCreateTags(tags, t).then(tagInstances => ({ videoInstance, tagInstances }))
|
||||
})
|
||||
.then(({ videoInstance, tagInstances }) => {
|
||||
const options = { transaction: t }
|
||||
const videoInstance = await fetchVideoByHostAndUUID(fromPod.host, videoAttributesToUpdate.uuid, t)
|
||||
const tags = videoAttributesToUpdate.tags
|
||||
|
||||
videoInstance.set('name', videoAttributesToUpdate.name)
|
||||
videoInstance.set('category', videoAttributesToUpdate.category)
|
||||
videoInstance.set('licence', videoAttributesToUpdate.licence)
|
||||
videoInstance.set('language', videoAttributesToUpdate.language)
|
||||
videoInstance.set('nsfw', videoAttributesToUpdate.nsfw)
|
||||
videoInstance.set('description', videoAttributesToUpdate.description)
|
||||
videoInstance.set('duration', videoAttributesToUpdate.duration)
|
||||
videoInstance.set('createdAt', videoAttributesToUpdate.createdAt)
|
||||
videoInstance.set('updatedAt', videoAttributesToUpdate.updatedAt)
|
||||
videoInstance.set('views', videoAttributesToUpdate.views)
|
||||
videoInstance.set('likes', videoAttributesToUpdate.likes)
|
||||
videoInstance.set('dislikes', videoAttributesToUpdate.dislikes)
|
||||
const tagInstances = await db.Tag.findOrCreateTags(tags, t)
|
||||
|
||||
return videoInstance.save(options).then(() => ({ videoInstance, tagInstances }))
|
||||
})
|
||||
.then(({ tagInstances, videoInstance }) => {
|
||||
const tasks: Promise<void>[] = []
|
||||
videoInstance.set('name', videoAttributesToUpdate.name)
|
||||
videoInstance.set('category', videoAttributesToUpdate.category)
|
||||
videoInstance.set('licence', videoAttributesToUpdate.licence)
|
||||
videoInstance.set('language', videoAttributesToUpdate.language)
|
||||
videoInstance.set('nsfw', videoAttributesToUpdate.nsfw)
|
||||
videoInstance.set('description', videoAttributesToUpdate.description)
|
||||
videoInstance.set('duration', videoAttributesToUpdate.duration)
|
||||
videoInstance.set('createdAt', videoAttributesToUpdate.createdAt)
|
||||
videoInstance.set('updatedAt', videoAttributesToUpdate.updatedAt)
|
||||
videoInstance.set('views', videoAttributesToUpdate.views)
|
||||
videoInstance.set('likes', videoAttributesToUpdate.likes)
|
||||
videoInstance.set('dislikes', videoAttributesToUpdate.dislikes)
|
||||
|
||||
// Remove old video files
|
||||
videoInstance.VideoFiles.forEach(videoFile => {
|
||||
tasks.push(videoFile.destroy({ transaction: t }))
|
||||
await videoInstance.save(sequelizeOptions)
|
||||
|
||||
// Remove old video files
|
||||
const videoFileDestroyTasks: Bluebird<void>[] = []
|
||||
for (const videoFile of videoInstance.VideoFiles) {
|
||||
videoFileDestroyTasks.push(videoFile.destroy(sequelizeOptions))
|
||||
}
|
||||
await Promise.all(videoFileDestroyTasks)
|
||||
|
||||
const videoFileCreateTasks: Bluebird<VideoFileInstance>[] = []
|
||||
for (const fileData of videoAttributesToUpdate.files) {
|
||||
const videoFileInstance = db.VideoFile.build({
|
||||
extname: fileData.extname,
|
||||
infoHash: fileData.infoHash,
|
||||
resolution: fileData.resolution,
|
||||
size: fileData.size,
|
||||
videoId: videoInstance.id
|
||||
})
|
||||
|
||||
return Promise.all(tasks).then(() => ({ tagInstances, videoInstance }))
|
||||
})
|
||||
.then(({ tagInstances, videoInstance }) => {
|
||||
const tasks: Promise<VideoFileInstance>[] = []
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
videoFileCreateTasks.push(videoFileInstance.save(sequelizeOptions))
|
||||
}
|
||||
|
||||
videoAttributesToUpdate.files.forEach(fileData => {
|
||||
const videoFileInstance = db.VideoFile.build({
|
||||
extname: fileData.extname,
|
||||
infoHash: fileData.infoHash,
|
||||
resolution: fileData.resolution,
|
||||
size: fileData.size,
|
||||
videoId: videoInstance.id
|
||||
})
|
||||
await Promise.all(videoFileCreateTasks)
|
||||
|
||||
tasks.push(videoFileInstance.save(options))
|
||||
})
|
||||
await videoInstance.setTags(tagInstances, sequelizeOptions)
|
||||
})
|
||||
|
||||
return Promise.all(tasks).then(() => ({ tagInstances, videoInstance }))
|
||||
})
|
||||
.then(({ videoInstance, tagInstances }) => {
|
||||
const options = { transaction: t }
|
||||
|
||||
return videoInstance.setTags(tagInstances, options)
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('Remote video with uuid %s updated', videoAttributesToUpdate.uuid))
|
||||
.catch(err => {
|
||||
logger.info('Remote video with uuid %s updated', videoAttributesToUpdate.uuid)
|
||||
} catch (err) {
|
||||
// This is just a debug because we will retry the insert
|
||||
logger.debug('Cannot update the remote video.', err)
|
||||
throw err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function removeRemoteVideoRetryWrapper (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
|
||||
async function removeRemoteVideoRetryWrapper (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoToRemoveData, fromPod ],
|
||||
errorMessage: 'Cannot remove the remote video channel with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(removeRemoteVideo, options)
|
||||
await retryTransactionWrapper(removeRemoteVideo, options)
|
||||
}
|
||||
|
||||
function removeRemoteVideo (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
|
||||
async function removeRemoteVideo (videoToRemoveData: RemoteVideoRemoveData, fromPod: PodInstance) {
|
||||
logger.debug('Removing remote video "%s".', videoToRemoveData.uuid)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
await db.sequelize.transaction(async t => {
|
||||
// We need the instance because we have to remove some other stuffs (thumbnail etc)
|
||||
return fetchVideoByHostAndUUID(fromPod.host, videoToRemoveData.uuid, t)
|
||||
.then(video => video.destroy({ transaction: t }))
|
||||
})
|
||||
.then(() => logger.info('Remote video with uuid %s removed.', videoToRemoveData.uuid))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot remove the remote video.', err)
|
||||
throw err
|
||||
const videoInstance = await fetchVideoByHostAndUUID(fromPod.host, videoToRemoveData.uuid, t)
|
||||
await videoInstance.destroy({ transaction: t })
|
||||
})
|
||||
|
||||
logger.info('Remote video with uuid %s removed.', videoToRemoveData.uuid)
|
||||
}
|
||||
|
||||
function addRemoteVideoAuthorRetryWrapper (authorToCreateData: RemoteVideoAuthorCreateData, fromPod: PodInstance) {
|
||||
async function addRemoteVideoAuthorRetryWrapper (authorToCreateData: RemoteVideoAuthorCreateData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ authorToCreateData, fromPod ],
|
||||
errorMessage: 'Cannot insert the remote video author with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(addRemoteVideoAuthor, options)
|
||||
await retryTransactionWrapper(addRemoteVideoAuthor, options)
|
||||
}
|
||||
|
||||
function addRemoteVideoAuthor (authorToCreateData: RemoteVideoAuthorCreateData, fromPod: PodInstance) {
|
||||
async function addRemoteVideoAuthor (authorToCreateData: RemoteVideoAuthorCreateData, fromPod: PodInstance) {
|
||||
logger.debug('Adding remote video author "%s".', authorToCreateData.uuid)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return db.Author.loadAuthorByPodAndUUID(authorToCreateData.uuid, fromPod.id, t)
|
||||
.then(author => {
|
||||
if (author) throw new Error('UUID already exists.')
|
||||
await db.sequelize.transaction(async t => {
|
||||
const authorInDatabase = await db.Author.loadAuthorByPodAndUUID(authorToCreateData.uuid, fromPod.id, t)
|
||||
if (authorInDatabase) throw new Error('Author with UUID ' + authorToCreateData.uuid + ' already exists.')
|
||||
|
||||
return undefined
|
||||
})
|
||||
.then(() => {
|
||||
const videoAuthorData = {
|
||||
name: authorToCreateData.name,
|
||||
uuid: authorToCreateData.uuid,
|
||||
userId: null, // Not on our pod
|
||||
podId: fromPod.id
|
||||
}
|
||||
const videoAuthorData = {
|
||||
name: authorToCreateData.name,
|
||||
uuid: authorToCreateData.uuid,
|
||||
userId: null, // Not on our pod
|
||||
podId: fromPod.id
|
||||
}
|
||||
|
||||
const author = db.Author.build(videoAuthorData)
|
||||
return author.save({ transaction: t })
|
||||
})
|
||||
const author = db.Author.build(videoAuthorData)
|
||||
await author.save({ transaction: t })
|
||||
})
|
||||
.then(() => logger.info('Remote video author with uuid %s inserted.', authorToCreateData.uuid))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot insert the remote video author.', err)
|
||||
throw err
|
||||
})
|
||||
|
||||
logger.info('Remote video author with uuid %s inserted.', authorToCreateData.uuid)
|
||||
}
|
||||
|
||||
function removeRemoteVideoAuthorRetryWrapper (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) {
|
||||
async function removeRemoteVideoAuthorRetryWrapper (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ authorAttributesToRemove, fromPod ],
|
||||
errorMessage: 'Cannot remove the remote video author with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(removeRemoteVideoAuthor, options)
|
||||
await retryTransactionWrapper(removeRemoteVideoAuthor, options)
|
||||
}
|
||||
|
||||
function removeRemoteVideoAuthor (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) {
|
||||
async function removeRemoteVideoAuthor (authorAttributesToRemove: RemoteVideoAuthorRemoveData, fromPod: PodInstance) {
|
||||
logger.debug('Removing remote video author "%s".', authorAttributesToRemove.uuid)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return db.Author.loadAuthorByPodAndUUID(authorAttributesToRemove.uuid, fromPod.id, t)
|
||||
.then(videoAuthor => videoAuthor.destroy({ transaction: t }))
|
||||
})
|
||||
.then(() => logger.info('Remote video author with uuid %s removed.', authorAttributesToRemove.uuid))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot remove the remote video author.', err)
|
||||
throw err
|
||||
await db.sequelize.transaction(async t => {
|
||||
const videoAuthor = await db.Author.loadAuthorByPodAndUUID(authorAttributesToRemove.uuid, fromPod.id, t)
|
||||
await videoAuthor.destroy({ transaction: t })
|
||||
})
|
||||
|
||||
logger.info('Remote video author with uuid %s removed.', authorAttributesToRemove.uuid)
|
||||
}
|
||||
|
||||
function addRemoteVideoChannelRetryWrapper (videoChannelToCreateData: RemoteVideoChannelCreateData, fromPod: PodInstance) {
|
||||
async function addRemoteVideoChannelRetryWrapper (videoChannelToCreateData: RemoteVideoChannelCreateData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoChannelToCreateData, fromPod ],
|
||||
errorMessage: 'Cannot insert the remote video channel with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(addRemoteVideoChannel, options)
|
||||
await retryTransactionWrapper(addRemoteVideoChannel, options)
|
||||
}
|
||||
|
||||
function addRemoteVideoChannel (videoChannelToCreateData: RemoteVideoChannelCreateData, fromPod: PodInstance) {
|
||||
async function addRemoteVideoChannel (videoChannelToCreateData: RemoteVideoChannelCreateData, fromPod: PodInstance) {
|
||||
logger.debug('Adding remote video channel "%s".', videoChannelToCreateData.uuid)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return db.VideoChannel.loadByUUID(videoChannelToCreateData.uuid)
|
||||
.then(videoChannel => {
|
||||
if (videoChannel) throw new Error('UUID already exists.')
|
||||
await db.sequelize.transaction(async t => {
|
||||
const videoChannelInDatabase = await db.VideoChannel.loadByUUID(videoChannelToCreateData.uuid)
|
||||
if (videoChannelInDatabase) {
|
||||
throw new Error('Video channel with UUID ' + videoChannelToCreateData.uuid + ' already exists.')
|
||||
}
|
||||
|
||||
return undefined
|
||||
})
|
||||
.then(() => {
|
||||
const authorUUID = videoChannelToCreateData.ownerUUID
|
||||
const podId = fromPod.id
|
||||
const authorUUID = videoChannelToCreateData.ownerUUID
|
||||
const podId = fromPod.id
|
||||
|
||||
return db.Author.loadAuthorByPodAndUUID(authorUUID, podId, t)
|
||||
})
|
||||
.then(author => {
|
||||
if (!author) throw new Error('Unknown author UUID.')
|
||||
const author = await db.Author.loadAuthorByPodAndUUID(authorUUID, podId, t)
|
||||
if (!author) throw new Error('Unknown author UUID' + authorUUID + '.')
|
||||
|
||||
const videoChannelData = {
|
||||
name: videoChannelToCreateData.name,
|
||||
description: videoChannelToCreateData.description,
|
||||
uuid: videoChannelToCreateData.uuid,
|
||||
createdAt: videoChannelToCreateData.createdAt,
|
||||
updatedAt: videoChannelToCreateData.updatedAt,
|
||||
remote: true,
|
||||
authorId: author.id
|
||||
}
|
||||
const videoChannelData = {
|
||||
name: videoChannelToCreateData.name,
|
||||
description: videoChannelToCreateData.description,
|
||||
uuid: videoChannelToCreateData.uuid,
|
||||
createdAt: videoChannelToCreateData.createdAt,
|
||||
updatedAt: videoChannelToCreateData.updatedAt,
|
||||
remote: true,
|
||||
authorId: author.id
|
||||
}
|
||||
|
||||
const videoChannel = db.VideoChannel.build(videoChannelData)
|
||||
return videoChannel.save({ transaction: t })
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('Remote video channel with uuid %s inserted.', videoChannelToCreateData.uuid))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot insert the remote video channel.', err)
|
||||
throw err
|
||||
const videoChannel = db.VideoChannel.build(videoChannelData)
|
||||
await videoChannel.save({ transaction: t })
|
||||
})
|
||||
|
||||
logger.info('Remote video channel with uuid %s inserted.', videoChannelToCreateData.uuid)
|
||||
}
|
||||
|
||||
function updateRemoteVideoChannelRetryWrapper (videoChannelAttributesToUpdate: RemoteVideoChannelUpdateData, fromPod: PodInstance) {
|
||||
async function updateRemoteVideoChannelRetryWrapper (videoChannelAttributesToUpdate: RemoteVideoChannelUpdateData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoChannelAttributesToUpdate, fromPod ],
|
||||
errorMessage: 'Cannot update the remote video channel with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(updateRemoteVideoChannel, options)
|
||||
await retryTransactionWrapper(updateRemoteVideoChannel, options)
|
||||
}
|
||||
|
||||
function updateRemoteVideoChannel (videoChannelAttributesToUpdate: RemoteVideoChannelUpdateData, fromPod: PodInstance) {
|
||||
async function updateRemoteVideoChannel (videoChannelAttributesToUpdate: RemoteVideoChannelUpdateData, fromPod: PodInstance) {
|
||||
logger.debug('Updating remote video channel "%s".', videoChannelAttributesToUpdate.uuid)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return fetchVideoChannelByHostAndUUID(fromPod.host, videoChannelAttributesToUpdate.uuid, t)
|
||||
.then(videoChannelInstance => {
|
||||
const options = { transaction: t }
|
||||
await db.sequelize.transaction(async t => {
|
||||
const sequelizeOptions = { transaction: t }
|
||||
|
||||
videoChannelInstance.set('name', videoChannelAttributesToUpdate.name)
|
||||
videoChannelInstance.set('description', videoChannelAttributesToUpdate.description)
|
||||
videoChannelInstance.set('createdAt', videoChannelAttributesToUpdate.createdAt)
|
||||
videoChannelInstance.set('updatedAt', videoChannelAttributesToUpdate.updatedAt)
|
||||
const videoChannelInstance = await fetchVideoChannelByHostAndUUID(fromPod.host, videoChannelAttributesToUpdate.uuid, t)
|
||||
videoChannelInstance.set('name', videoChannelAttributesToUpdate.name)
|
||||
videoChannelInstance.set('description', videoChannelAttributesToUpdate.description)
|
||||
videoChannelInstance.set('createdAt', videoChannelAttributesToUpdate.createdAt)
|
||||
videoChannelInstance.set('updatedAt', videoChannelAttributesToUpdate.updatedAt)
|
||||
|
||||
return videoChannelInstance.save(options)
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('Remote video channel with uuid %s updated', videoChannelAttributesToUpdate.uuid))
|
||||
.catch(err => {
|
||||
// This is just a debug because we will retry the insert
|
||||
logger.debug('Cannot update the remote video channel.', err)
|
||||
throw err
|
||||
await videoChannelInstance.save(sequelizeOptions)
|
||||
})
|
||||
|
||||
logger.info('Remote video channel with uuid %s updated', videoChannelAttributesToUpdate.uuid)
|
||||
}
|
||||
|
||||
function removeRemoteVideoChannelRetryWrapper (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) {
|
||||
async function removeRemoteVideoChannelRetryWrapper (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoChannelAttributesToRemove, fromPod ],
|
||||
errorMessage: 'Cannot remove the remote video channel with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(removeRemoteVideoChannel, options)
|
||||
await retryTransactionWrapper(removeRemoteVideoChannel, options)
|
||||
}
|
||||
|
||||
function removeRemoteVideoChannel (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) {
|
||||
async function removeRemoteVideoChannel (videoChannelAttributesToRemove: RemoteVideoChannelRemoveData, fromPod: PodInstance) {
|
||||
logger.debug('Removing remote video channel "%s".', videoChannelAttributesToRemove.uuid)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return fetchVideoChannelByHostAndUUID(fromPod.host, videoChannelAttributesToRemove.uuid, t)
|
||||
.then(videoChannel => videoChannel.destroy({ transaction: t }))
|
||||
})
|
||||
.then(() => logger.info('Remote video channel with uuid %s removed.', videoChannelAttributesToRemove.uuid))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot remove the remote video channel.', err)
|
||||
throw err
|
||||
await db.sequelize.transaction(async t => {
|
||||
const videoChannel = await fetchVideoChannelByHostAndUUID(fromPod.host, videoChannelAttributesToRemove.uuid, t)
|
||||
await videoChannel.destroy({ transaction: t })
|
||||
})
|
||||
|
||||
logger.info('Remote video channel with uuid %s removed.', videoChannelAttributesToRemove.uuid)
|
||||
}
|
||||
|
||||
function reportAbuseRemoteVideoRetryWrapper (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
|
||||
async function reportAbuseRemoteVideoRetryWrapper (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ reportData, fromPod ],
|
||||
errorMessage: 'Cannot create remote abuse video with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(reportAbuseRemoteVideo, options)
|
||||
await retryTransactionWrapper(reportAbuseRemoteVideo, options)
|
||||
}
|
||||
|
||||
function reportAbuseRemoteVideo (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
|
||||
async function reportAbuseRemoteVideo (reportData: RemoteVideoReportAbuseData, fromPod: PodInstance) {
|
||||
logger.debug('Reporting remote abuse for video %s.', reportData.videoUUID)
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return fetchVideoByUUID(reportData.videoUUID, t)
|
||||
.then(video => {
|
||||
const videoAbuseData = {
|
||||
reporterUsername: reportData.reporterUsername,
|
||||
reason: reportData.reportReason,
|
||||
reporterPodId: fromPod.id,
|
||||
videoId: video.id
|
||||
}
|
||||
await db.sequelize.transaction(async t => {
|
||||
const videoInstance = await fetchVideoByUUID(reportData.videoUUID, t)
|
||||
const videoAbuseData = {
|
||||
reporterUsername: reportData.reporterUsername,
|
||||
reason: reportData.reportReason,
|
||||
reporterPodId: fromPod.id,
|
||||
videoId: videoInstance.id
|
||||
}
|
||||
|
||||
await db.VideoAbuse.create(videoAbuseData)
|
||||
|
||||
return db.VideoAbuse.create(videoAbuseData)
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('Remote abuse for video uuid %s created', reportData.videoUUID))
|
||||
.catch(err => {
|
||||
// This is just a debug because we will retry the insert
|
||||
logger.debug('Cannot create remote abuse video', err)
|
||||
|
||||
logger.info('Remote abuse for video uuid %s created', reportData.videoUUID)
|
||||
}
|
||||
|
||||
async function fetchVideoByUUID (id: string, t: Sequelize.Transaction) {
|
||||
try {
|
||||
const video = await db.Video.loadByUUID(id, t)
|
||||
|
||||
if (!video) throw new Error('Video ' + id + ' not found')
|
||||
|
||||
return video
|
||||
} catch (err) {
|
||||
logger.error('Cannot load owned video from id.', { error: err.stack, id })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function fetchVideoByUUID (id: string, t: Sequelize.Transaction) {
|
||||
return db.Video.loadByUUID(id, t)
|
||||
.then(video => {
|
||||
if (!video) throw new Error('Video not found')
|
||||
async function fetchVideoByHostAndUUID (podHost: string, uuid: string, t: Sequelize.Transaction) {
|
||||
try {
|
||||
const video = await db.Video.loadByHostAndUUID(podHost, uuid, t)
|
||||
if (!video) throw new Error('Video not found')
|
||||
|
||||
return video
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Cannot load owned video from id.', { error: err.stack, id })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
function fetchVideoByHostAndUUID (podHost: string, uuid: string, t: Sequelize.Transaction) {
|
||||
return db.Video.loadByHostAndUUID(podHost, uuid, t)
|
||||
.then(video => {
|
||||
if (!video) throw new Error('Video not found')
|
||||
|
||||
return video
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Cannot load video from host and uuid.', { error: err.stack, podHost, uuid })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
function fetchVideoChannelByHostAndUUID (podHost: string, uuid: string, t: Sequelize.Transaction) {
|
||||
return db.VideoChannel.loadByHostAndUUID(podHost, uuid, t)
|
||||
.then(videoChannel => {
|
||||
if (!videoChannel) throw new Error('Video channel not found')
|
||||
|
||||
return videoChannel
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Cannot load video channel from host and uuid.', { error: err.stack, podHost, uuid })
|
||||
throw err
|
||||
})
|
||||
return video
|
||||
} catch (err) {
|
||||
logger.error('Cannot load video from host and uuid.', { error: err.stack, podHost, uuid })
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as express from 'express'
|
||||
import * as Promise from 'bluebird'
|
||||
import * as Bluebird from 'bluebird'
|
||||
|
||||
import {
|
||||
AbstractRequestScheduler,
|
||||
|
@ -7,7 +7,7 @@ import {
|
|||
getRequestVideoQaduScheduler,
|
||||
getRequestVideoEventScheduler
|
||||
} from '../../lib'
|
||||
import { authenticate, ensureIsAdmin } from '../../middlewares'
|
||||
import { authenticate, ensureIsAdmin, asyncMiddleware } from '../../middlewares'
|
||||
import { RequestSchedulerStatsAttributes } from '../../../shared'
|
||||
|
||||
const requestSchedulerRouter = express.Router()
|
||||
|
@ -15,7 +15,7 @@ const requestSchedulerRouter = express.Router()
|
|||
requestSchedulerRouter.get('/stats',
|
||||
authenticate,
|
||||
ensureIsAdmin,
|
||||
getRequestSchedulersStats
|
||||
asyncMiddleware(getRequestSchedulersStats)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -26,28 +26,28 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function getRequestSchedulersStats (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
Promise.props({
|
||||
async function getRequestSchedulersStats (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const result = await Bluebird.props({
|
||||
requestScheduler: buildRequestSchedulerStats(getRequestScheduler()),
|
||||
requestVideoQaduScheduler: buildRequestSchedulerStats(getRequestVideoQaduScheduler()),
|
||||
requestVideoEventScheduler: buildRequestSchedulerStats(getRequestVideoEventScheduler())
|
||||
})
|
||||
.then(result => res.json(result))
|
||||
.catch(err => next(err))
|
||||
|
||||
return res.json(result)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function buildRequestSchedulerStats (requestScheduler: AbstractRequestScheduler<any>) {
|
||||
return requestScheduler.remainingRequestsCount().then(count => {
|
||||
const result: RequestSchedulerStatsAttributes = {
|
||||
totalRequests: count,
|
||||
requestsLimitPods: requestScheduler.limitPods,
|
||||
requestsLimitPerPod: requestScheduler.limitPerPod,
|
||||
remainingMilliSeconds: requestScheduler.remainingMilliSeconds(),
|
||||
milliSecondsInterval: requestScheduler.requestInterval
|
||||
}
|
||||
async function buildRequestSchedulerStats (requestScheduler: AbstractRequestScheduler<any>) {
|
||||
const count = await requestScheduler.remainingRequestsCount()
|
||||
|
||||
return result
|
||||
})
|
||||
const result: RequestSchedulerStatsAttributes = {
|
||||
totalRequests: count,
|
||||
requestsLimitPods: requestScheduler.limitPods,
|
||||
requestsLimitPerPod: requestScheduler.limitPerPod,
|
||||
remainingMilliSeconds: requestScheduler.remainingMilliSeconds(),
|
||||
milliSecondsInterval: requestScheduler.requestInterval
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -18,7 +18,8 @@ import {
|
|||
setPagination,
|
||||
usersSortValidator,
|
||||
setUsersSort,
|
||||
token
|
||||
token,
|
||||
asyncMiddleware
|
||||
} from '../../middlewares'
|
||||
import {
|
||||
UserVideoRate as FormattedUserVideoRate,
|
||||
|
@ -33,13 +34,13 @@ const usersRouter = express.Router()
|
|||
|
||||
usersRouter.get('/me',
|
||||
authenticate,
|
||||
getUserInformation
|
||||
asyncMiddleware(getUserInformation)
|
||||
)
|
||||
|
||||
usersRouter.get('/me/videos/:videoId/rating',
|
||||
authenticate,
|
||||
usersVideoRatingValidator,
|
||||
getUserVideoRating
|
||||
asyncMiddleware(getUserVideoRating)
|
||||
)
|
||||
|
||||
usersRouter.get('/',
|
||||
|
@ -47,7 +48,7 @@ usersRouter.get('/',
|
|||
usersSortValidator,
|
||||
setUsersSort,
|
||||
setPagination,
|
||||
listUsers
|
||||
asyncMiddleware(listUsers)
|
||||
)
|
||||
|
||||
usersRouter.get('/:id',
|
||||
|
@ -65,27 +66,27 @@ usersRouter.post('/',
|
|||
usersRouter.post('/register',
|
||||
ensureUserRegistrationAllowed,
|
||||
usersRegisterValidator,
|
||||
registerUser
|
||||
asyncMiddleware(registerUser)
|
||||
)
|
||||
|
||||
usersRouter.put('/me',
|
||||
authenticate,
|
||||
usersUpdateMeValidator,
|
||||
updateMe
|
||||
asyncMiddleware(updateMe)
|
||||
)
|
||||
|
||||
usersRouter.put('/:id',
|
||||
authenticate,
|
||||
ensureIsAdmin,
|
||||
usersUpdateValidator,
|
||||
updateUser
|
||||
asyncMiddleware(updateUser)
|
||||
)
|
||||
|
||||
usersRouter.delete('/:id',
|
||||
authenticate,
|
||||
ensureIsAdmin,
|
||||
usersRemoveValidator,
|
||||
removeUser
|
||||
asyncMiddleware(removeUser)
|
||||
)
|
||||
|
||||
usersRouter.post('/token', token, success)
|
||||
|
@ -99,21 +100,19 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function createUserRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function createUserRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const options = {
|
||||
arguments: [ req, res ],
|
||||
errorMessage: 'Cannot insert the user with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(createUser, options)
|
||||
.then(() => {
|
||||
// TODO : include Location of the new user -> 201
|
||||
res.type('json').status(204).end()
|
||||
})
|
||||
.catch(err => next(err))
|
||||
await retryTransactionWrapper(createUser, options)
|
||||
|
||||
// TODO : include Location of the new user -> 201
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function createUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function createUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const body: UserCreate = req.body
|
||||
const user = db.User.build({
|
||||
username: body.username,
|
||||
|
@ -124,15 +123,12 @@ function createUser (req: express.Request, res: express.Response, next: express.
|
|||
videoQuota: body.videoQuota
|
||||
})
|
||||
|
||||
return createUserAuthorAndChannel(user)
|
||||
.then(() => logger.info('User %s with its channel and author created.', body.username))
|
||||
.catch((err: Error) => {
|
||||
logger.debug('Cannot insert the user.', err)
|
||||
throw err
|
||||
})
|
||||
await createUserAuthorAndChannel(user)
|
||||
|
||||
logger.info('User %s with its channel and author created.', body.username)
|
||||
}
|
||||
|
||||
function registerUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function registerUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const body: UserCreate = req.body
|
||||
|
||||
const user = db.User.build({
|
||||
|
@ -144,22 +140,21 @@ function registerUser (req: express.Request, res: express.Response, next: expres
|
|||
videoQuota: CONFIG.USER.VIDEO_QUOTA
|
||||
})
|
||||
|
||||
return createUserAuthorAndChannel(user)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
await createUserAuthorAndChannel(user)
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function getUserInformation (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.User.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
|
||||
.then(user => res.json(user.toFormattedJSON()))
|
||||
.catch(err => next(err))
|
||||
async function getUserInformation (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const user = await db.User.loadByUsernameAndPopulateChannels(res.locals.oauth.token.user.username)
|
||||
|
||||
return res.json(user.toFormattedJSON())
|
||||
}
|
||||
|
||||
function getUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
return res.json(res.locals.user.toFormattedJSON())
|
||||
}
|
||||
|
||||
function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const videoId = +req.params.videoId
|
||||
const userId = +res.locals.oauth.token.User.id
|
||||
|
||||
|
@ -175,50 +170,45 @@ function getUserVideoRating (req: express.Request, res: express.Response, next:
|
|||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.User.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
.then(resultList => {
|
||||
res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
})
|
||||
.catch(err => next(err))
|
||||
async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.User.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.User.loadById(req.params.id)
|
||||
.then(user => user.destroy())
|
||||
.then(() => res.sendStatus(204))
|
||||
.catch(err => {
|
||||
logger.error('Errors when removed the user.', err)
|
||||
return next(err)
|
||||
})
|
||||
async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const user = await db.User.loadById(req.params.id)
|
||||
|
||||
await user.destroy()
|
||||
|
||||
return res.sendStatus(204)
|
||||
}
|
||||
|
||||
function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const body: UserUpdateMe = req.body
|
||||
|
||||
// FIXME: user is not already a Sequelize instance?
|
||||
db.User.loadByUsername(res.locals.oauth.token.user.username)
|
||||
.then(user => {
|
||||
if (body.password !== undefined) user.password = body.password
|
||||
if (body.email !== undefined) user.email = body.email
|
||||
if (body.displayNSFW !== undefined) user.displayNSFW = body.displayNSFW
|
||||
const user = res.locals.oauth.token.user
|
||||
|
||||
return user.save()
|
||||
})
|
||||
.then(() => res.sendStatus(204))
|
||||
.catch(err => next(err))
|
||||
if (body.password !== undefined) user.password = body.password
|
||||
if (body.email !== undefined) user.email = body.email
|
||||
if (body.displayNSFW !== undefined) user.displayNSFW = body.displayNSFW
|
||||
|
||||
await user.save()
|
||||
|
||||
return await res.sendStatus(204)
|
||||
}
|
||||
|
||||
function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const body: UserUpdate = req.body
|
||||
const user: UserInstance = res.locals.user
|
||||
|
||||
if (body.email !== undefined) user.email = body.email
|
||||
if (body.videoQuota !== undefined) user.videoQuota = body.videoQuota
|
||||
|
||||
return user.save()
|
||||
.then(() => res.sendStatus(204))
|
||||
.catch(err => next(err))
|
||||
await user.save()
|
||||
|
||||
return res.sendStatus(204)
|
||||
}
|
||||
|
||||
function success (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
|
|
|
@ -14,7 +14,8 @@ import {
|
|||
videoAbuseReportValidator,
|
||||
videoAbusesSortValidator,
|
||||
setVideoAbusesSort,
|
||||
setPagination
|
||||
setPagination,
|
||||
asyncMiddleware
|
||||
} from '../../../middlewares'
|
||||
import { VideoInstance } from '../../../models'
|
||||
import { VideoAbuseCreate } from '../../../../shared'
|
||||
|
@ -28,12 +29,12 @@ abuseVideoRouter.get('/abuse',
|
|||
videoAbusesSortValidator,
|
||||
setVideoAbusesSort,
|
||||
setPagination,
|
||||
listVideoAbuses
|
||||
asyncMiddleware(listVideoAbuses)
|
||||
)
|
||||
abuseVideoRouter.post('/:id/abuse',
|
||||
authenticate,
|
||||
videoAbuseReportValidator,
|
||||
reportVideoAbuseRetryWrapper
|
||||
asyncMiddleware(reportVideoAbuseRetryWrapper)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -44,55 +45,48 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function listVideoAbuses (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
.then(result => res.json(getFormattedObjects(result.data, result.total)))
|
||||
.catch(err => next(err))
|
||||
async function listVideoAbuses (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const options = {
|
||||
arguments: [ req, res ],
|
||||
errorMessage: 'Cannot report abuse to the video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(reportVideoAbuse, options)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
await retryTransactionWrapper(reportVideoAbuse, options)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function reportVideoAbuse (req: express.Request, res: express.Response) {
|
||||
async function reportVideoAbuse (req: express.Request, res: express.Response) {
|
||||
const videoInstance = res.locals.video as VideoInstance
|
||||
const reporterUsername = res.locals.oauth.token.User.username
|
||||
const body: VideoAbuseCreate = req.body
|
||||
|
||||
const abuse = {
|
||||
const abuseToCreate = {
|
||||
reporterUsername,
|
||||
reason: body.reason,
|
||||
videoId: videoInstance.id,
|
||||
reporterPodId: null // This is our pod that reported this abuse
|
||||
}
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return db.VideoAbuse.create(abuse, { transaction: t })
|
||||
.then(abuse => {
|
||||
// We send the information to the destination pod
|
||||
if (videoInstance.isOwned() === false) {
|
||||
const reportData = {
|
||||
reporterUsername,
|
||||
reportReason: abuse.reason,
|
||||
videoUUID: videoInstance.uuid
|
||||
}
|
||||
await db.sequelize.transaction(async t => {
|
||||
const abuse = await db.VideoAbuse.create(abuseToCreate, { transaction: t })
|
||||
// We send the information to the destination pod
|
||||
if (videoInstance.isOwned() === false) {
|
||||
const reportData = {
|
||||
reporterUsername,
|
||||
reportReason: abuse.reason,
|
||||
videoUUID: videoInstance.uuid
|
||||
}
|
||||
|
||||
return friends.reportAbuseVideoToFriend(reportData, videoInstance, t).then(() => videoInstance)
|
||||
}
|
||||
await friends.reportAbuseVideoToFriend(reportData, videoInstance, t)
|
||||
}
|
||||
})
|
||||
|
||||
return videoInstance
|
||||
})
|
||||
})
|
||||
.then((videoInstance: VideoInstance) => logger.info('Abuse report for video %s created.', videoInstance.name))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot update the video.', err)
|
||||
throw err
|
||||
})
|
||||
logger.info('Abuse report for video %s created.', videoInstance.name)
|
||||
}
|
||||
|
|
|
@ -10,7 +10,8 @@ import {
|
|||
paginationValidator,
|
||||
blacklistSortValidator,
|
||||
setBlacklistSort,
|
||||
setPagination
|
||||
setPagination,
|
||||
asyncMiddleware
|
||||
} from '../../../middlewares'
|
||||
import { BlacklistedVideoInstance } from '../../../models'
|
||||
import { BlacklistedVideo } from '../../../../shared'
|
||||
|
@ -21,7 +22,7 @@ blacklistRouter.post('/:videoId/blacklist',
|
|||
authenticate,
|
||||
ensureIsAdmin,
|
||||
videosBlacklistAddValidator,
|
||||
addVideoToBlacklist
|
||||
asyncMiddleware(addVideoToBlacklist)
|
||||
)
|
||||
|
||||
blacklistRouter.get('/blacklist',
|
||||
|
@ -31,14 +32,14 @@ blacklistRouter.get('/blacklist',
|
|||
blacklistSortValidator,
|
||||
setBlacklistSort,
|
||||
setPagination,
|
||||
listBlacklist
|
||||
asyncMiddleware(listBlacklist)
|
||||
)
|
||||
|
||||
blacklistRouter.delete('/:videoId/blacklist',
|
||||
authenticate,
|
||||
ensureIsAdmin,
|
||||
videosBlacklistRemoveValidator,
|
||||
removeVideoFromBlacklistController
|
||||
asyncMiddleware(removeVideoFromBlacklistController)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -49,37 +50,34 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function addVideoToBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function addVideoToBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const videoInstance = res.locals.video
|
||||
|
||||
const toCreate = {
|
||||
videoId: videoInstance.id
|
||||
}
|
||||
|
||||
db.BlacklistedVideo.create(toCreate)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => {
|
||||
logger.error('Errors when blacklisting video ', err)
|
||||
return next(err)
|
||||
})
|
||||
await db.BlacklistedVideo.create(toCreate)
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function listBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.BlacklistedVideo.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
.then(resultList => res.json(getFormattedObjects<BlacklistedVideo, BlacklistedVideoInstance>(resultList.data, resultList.total)))
|
||||
.catch(err => next(err))
|
||||
async function listBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.BlacklistedVideo.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
|
||||
return res.json(getFormattedObjects<BlacklistedVideo, BlacklistedVideoInstance>(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function removeVideoFromBlacklistController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const blacklistedVideo = res.locals.blacklistedVideo as BlacklistedVideoInstance
|
||||
|
||||
blacklistedVideo.destroy()
|
||||
.then(() => {
|
||||
logger.info('Video %s removed from blacklist.', res.locals.video.uuid)
|
||||
res.sendStatus(204)
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Some error while removing video %s from blacklist.', res.locals.video.uuid, err)
|
||||
next(err)
|
||||
})
|
||||
try {
|
||||
await blacklistedVideo.destroy()
|
||||
|
||||
logger.info('Video %s removed from blacklist.', res.locals.video.uuid)
|
||||
|
||||
return res.sendStatus(204)
|
||||
} catch (err) {
|
||||
logger.error('Some error while removing video %s from blacklist.', res.locals.video.uuid, err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,8 @@ import { database as db } from '../../../initializers'
|
|||
import {
|
||||
logger,
|
||||
getFormattedObjects,
|
||||
retryTransactionWrapper
|
||||
retryTransactionWrapper,
|
||||
resetSequelizeInstance
|
||||
} from '../../../helpers'
|
||||
import {
|
||||
authenticate,
|
||||
|
@ -16,7 +17,8 @@ import {
|
|||
videoChannelsRemoveValidator,
|
||||
videoChannelGetValidator,
|
||||
videoChannelsUpdateValidator,
|
||||
listVideoAuthorChannelsValidator
|
||||
listVideoAuthorChannelsValidator,
|
||||
asyncMiddleware
|
||||
} from '../../../middlewares'
|
||||
import {
|
||||
createVideoChannel,
|
||||
|
@ -32,18 +34,18 @@ videoChannelRouter.get('/channels',
|
|||
videoChannelsSortValidator,
|
||||
setVideoChannelsSort,
|
||||
setPagination,
|
||||
listVideoChannels
|
||||
asyncMiddleware(listVideoChannels)
|
||||
)
|
||||
|
||||
videoChannelRouter.get('/authors/:authorId/channels',
|
||||
listVideoAuthorChannelsValidator,
|
||||
listVideoAuthorChannels
|
||||
asyncMiddleware(listVideoAuthorChannels)
|
||||
)
|
||||
|
||||
videoChannelRouter.post('/channels',
|
||||
authenticate,
|
||||
videoChannelsAddValidator,
|
||||
addVideoChannelRetryWrapper
|
||||
asyncMiddleware(addVideoChannelRetryWrapper)
|
||||
)
|
||||
|
||||
videoChannelRouter.put('/channels/:id',
|
||||
|
@ -55,12 +57,12 @@ videoChannelRouter.put('/channels/:id',
|
|||
videoChannelRouter.delete('/channels/:id',
|
||||
authenticate,
|
||||
videoChannelsRemoveValidator,
|
||||
removeVideoChannelRetryWrapper
|
||||
asyncMiddleware(removeVideoChannelRetryWrapper)
|
||||
)
|
||||
|
||||
videoChannelRouter.get('/channels/:id',
|
||||
videoChannelGetValidator,
|
||||
getVideoChannel
|
||||
asyncMiddleware(getVideoChannel)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -71,126 +73,113 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function listVideoChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.VideoChannel.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
.then(result => res.json(getFormattedObjects(result.data, result.total)))
|
||||
.catch(err => next(err))
|
||||
async function listVideoChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.VideoChannel.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
function listVideoAuthorChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.VideoChannel.listByAuthor(res.locals.author.id)
|
||||
.then(result => res.json(getFormattedObjects(result.data, result.total)))
|
||||
.catch(err => next(err))
|
||||
async function listVideoAuthorChannels (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.VideoChannel.listByAuthor(res.locals.author.id)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
// Wrapper to video channel add that retry the function if there is a database error
|
||||
// Wrapper to video channel add that retry the async function if there is a database error
|
||||
// We need this because we run the transaction in SERIALIZABLE isolation that can fail
|
||||
function addVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function addVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const options = {
|
||||
arguments: [ req, res ],
|
||||
errorMessage: 'Cannot insert the video video channel with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(addVideoChannel, options)
|
||||
.then(() => {
|
||||
// TODO : include Location of the new video channel -> 201
|
||||
res.type('json').status(204).end()
|
||||
})
|
||||
.catch(err => next(err))
|
||||
await retryTransactionWrapper(addVideoChannel, options)
|
||||
|
||||
// TODO : include Location of the new video channel -> 201
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function addVideoChannel (req: express.Request, res: express.Response) {
|
||||
async function addVideoChannel (req: express.Request, res: express.Response) {
|
||||
const videoChannelInfo: VideoChannelCreate = req.body
|
||||
const author: AuthorInstance = res.locals.oauth.token.User.Author
|
||||
let videoChannelCreated: VideoChannelInstance
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return createVideoChannel(videoChannelInfo, author, t)
|
||||
})
|
||||
.then(videoChannelUUID => logger.info('Video channel with uuid %s created.', videoChannelUUID))
|
||||
.catch((err: Error) => {
|
||||
logger.debug('Cannot insert the video channel.', err)
|
||||
throw err
|
||||
await db.sequelize.transaction(async t => {
|
||||
videoChannelCreated = await createVideoChannel(videoChannelInfo, author, t)
|
||||
})
|
||||
|
||||
logger.info('Video channel with uuid %s created.', videoChannelCreated.uuid)
|
||||
}
|
||||
|
||||
function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function updateVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const options = {
|
||||
arguments: [ req, res ],
|
||||
errorMessage: 'Cannot update the video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(updateVideoChannel, options)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
await retryTransactionWrapper(updateVideoChannel, options)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function updateVideoChannel (req: express.Request, res: express.Response) {
|
||||
async function updateVideoChannel (req: express.Request, res: express.Response) {
|
||||
const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel
|
||||
const videoChannelFieldsSave = videoChannelInstance.toJSON()
|
||||
const videoChannelInfoToUpdate: VideoChannelUpdate = req.body
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
try {
|
||||
await db.sequelize.transaction(async t => {
|
||||
const sequelizeOptions = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name)
|
||||
if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)
|
||||
if (videoChannelInfoToUpdate.name !== undefined) videoChannelInstance.set('name', videoChannelInfoToUpdate.name)
|
||||
if (videoChannelInfoToUpdate.description !== undefined) videoChannelInstance.set('description', videoChannelInfoToUpdate.description)
|
||||
|
||||
return videoChannelInstance.save(options)
|
||||
.then(() => {
|
||||
const json = videoChannelInstance.toUpdateRemoteJSON()
|
||||
await videoChannelInstance.save(sequelizeOptions)
|
||||
const json = videoChannelInstance.toUpdateRemoteJSON()
|
||||
|
||||
// Now we'll update the video channel's meta data to our friends
|
||||
return updateVideoChannelToFriends(json, t)
|
||||
|
||||
// Now we'll update the video channel's meta data to our friends
|
||||
return updateVideoChannelToFriends(json, t)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.uuid)
|
||||
})
|
||||
.catch(err => {
|
||||
logger.debug('Cannot update the video channel.', err)
|
||||
|
||||
// Force fields we want to update
|
||||
// If the transaction is retried, sequelize will think the object has not changed
|
||||
// So it will skip the SQL request, even if the last one was ROLLBACKed!
|
||||
Object.keys(videoChannelFieldsSave).forEach(key => {
|
||||
const value = videoChannelFieldsSave[key]
|
||||
videoChannelInstance.set(key, value)
|
||||
})
|
||||
logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.uuid)
|
||||
} catch (err) {
|
||||
logger.debug('Cannot update the video channel.', err)
|
||||
|
||||
throw err
|
||||
})
|
||||
// Force fields we want to update
|
||||
// If the transaction is retried, sequelize will think the object has not changed
|
||||
// So it will skip the SQL request, even if the last one was ROLLBACKed!
|
||||
resetSequelizeInstance(videoChannelInstance, videoChannelFieldsSave)
|
||||
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
function removeVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function removeVideoChannelRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const options = {
|
||||
arguments: [ req, res ],
|
||||
errorMessage: 'Cannot remove the video channel with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(removeVideoChannel, options)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
await retryTransactionWrapper(removeVideoChannel, options)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function removeVideoChannel (req: express.Request, res: express.Response) {
|
||||
async function removeVideoChannel (req: express.Request, res: express.Response) {
|
||||
const videoChannelInstance: VideoChannelInstance = res.locals.videoChannel
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return videoChannelInstance.destroy({ transaction: t })
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.uuid)
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Errors when removed the video channel.', err)
|
||||
throw err
|
||||
await db.sequelize.transaction(async t => {
|
||||
await videoChannelInstance.destroy({ transaction: t })
|
||||
})
|
||||
|
||||
logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.uuid)
|
||||
}
|
||||
|
||||
function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.VideoChannel.loadAndPopulateAuthorAndVideos(res.locals.videoChannel.id)
|
||||
.then(videoChannelWithVideos => res.json(videoChannelWithVideos.toFormattedJSON()))
|
||||
.catch(err => next(err))
|
||||
async function getVideoChannel (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const videoChannelWithVideos = await db.VideoChannel.loadAndPopulateAuthorAndVideos(res.locals.videoChannel.id)
|
||||
|
||||
return res.json(videoChannelWithVideos.toFormattedJSON())
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as express from 'express'
|
||||
import * as Promise from 'bluebird'
|
||||
import * as multer from 'multer'
|
||||
import { extname, join } from 'path'
|
||||
|
||||
|
@ -30,7 +29,8 @@ import {
|
|||
videosSearchValidator,
|
||||
videosAddValidator,
|
||||
videosGetValidator,
|
||||
videosRemoveValidator
|
||||
videosRemoveValidator,
|
||||
asyncMiddleware
|
||||
} from '../../../middlewares'
|
||||
import {
|
||||
logger,
|
||||
|
@ -38,7 +38,8 @@ import {
|
|||
generateRandomString,
|
||||
getFormattedObjects,
|
||||
renamePromise,
|
||||
getVideoFileHeight
|
||||
getVideoFileHeight,
|
||||
resetSequelizeInstance
|
||||
} from '../../../helpers'
|
||||
import { TagInstance, VideoInstance } from '../../../models'
|
||||
import { VideoCreate, VideoUpdate } from '../../../../shared'
|
||||
|
@ -88,18 +89,18 @@ videosRouter.get('/',
|
|||
videosSortValidator,
|
||||
setVideosSort,
|
||||
setPagination,
|
||||
listVideos
|
||||
asyncMiddleware(listVideos)
|
||||
)
|
||||
videosRouter.put('/:id',
|
||||
authenticate,
|
||||
videosUpdateValidator,
|
||||
updateVideoRetryWrapper
|
||||
asyncMiddleware(updateVideoRetryWrapper)
|
||||
)
|
||||
videosRouter.post('/upload',
|
||||
authenticate,
|
||||
reqFiles,
|
||||
videosAddValidator,
|
||||
addVideoRetryWrapper
|
||||
asyncMiddleware(addVideoRetryWrapper)
|
||||
)
|
||||
videosRouter.get('/:id',
|
||||
videosGetValidator,
|
||||
|
@ -109,7 +110,7 @@ videosRouter.get('/:id',
|
|||
videosRouter.delete('/:id',
|
||||
authenticate,
|
||||
videosRemoveValidator,
|
||||
removeVideoRetryWrapper
|
||||
asyncMiddleware(removeVideoRetryWrapper)
|
||||
)
|
||||
|
||||
videosRouter.get('/search/:value',
|
||||
|
@ -119,7 +120,7 @@ videosRouter.get('/search/:value',
|
|||
setVideosSort,
|
||||
setPagination,
|
||||
setVideosSearch,
|
||||
searchVideos
|
||||
asyncMiddleware(searchVideos)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -144,220 +145,157 @@ function listVideoLanguages (req: express.Request, res: express.Response) {
|
|||
|
||||
// Wrapper to video add that retry the function if there is a database error
|
||||
// We need this because we run the transaction in SERIALIZABLE isolation that can fail
|
||||
function addVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function addVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const options = {
|
||||
arguments: [ req, res, req.files['videofile'][0] ],
|
||||
errorMessage: 'Cannot insert the video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(addVideo, options)
|
||||
.then(() => {
|
||||
// TODO : include Location of the new video -> 201
|
||||
res.type('json').status(204).end()
|
||||
})
|
||||
.catch(err => next(err))
|
||||
await retryTransactionWrapper(addVideo, options)
|
||||
|
||||
// TODO : include Location of the new video -> 201
|
||||
res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) {
|
||||
async function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) {
|
||||
const videoInfo: VideoCreate = req.body
|
||||
let videoUUID = ''
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
let p: Promise<TagInstance[]>
|
||||
await db.sequelize.transaction(async t => {
|
||||
const sequelizeOptions = { transaction: t }
|
||||
|
||||
if (!videoInfo.tags) p = Promise.resolve(undefined)
|
||||
else p = db.Tag.findOrCreateTags(videoInfo.tags, t)
|
||||
const videoData = {
|
||||
name: videoInfo.name,
|
||||
remote: false,
|
||||
extname: extname(videoPhysicalFile.filename),
|
||||
category: videoInfo.category,
|
||||
licence: videoInfo.licence,
|
||||
language: videoInfo.language,
|
||||
nsfw: videoInfo.nsfw,
|
||||
description: videoInfo.description,
|
||||
duration: videoPhysicalFile['duration'], // duration was added by a previous middleware
|
||||
channelId: res.locals.videoChannel.id
|
||||
}
|
||||
const video = db.Video.build(videoData)
|
||||
|
||||
return p
|
||||
.then(tagInstances => {
|
||||
const videoData = {
|
||||
name: videoInfo.name,
|
||||
remote: false,
|
||||
extname: extname(videoPhysicalFile.filename),
|
||||
category: videoInfo.category,
|
||||
licence: videoInfo.licence,
|
||||
language: videoInfo.language,
|
||||
nsfw: videoInfo.nsfw,
|
||||
description: videoInfo.description,
|
||||
duration: videoPhysicalFile['duration'], // duration was added by a previous middleware
|
||||
channelId: res.locals.videoChannel.id
|
||||
}
|
||||
const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename)
|
||||
const videoFileHeight = await getVideoFileHeight(videoFilePath)
|
||||
|
||||
const video = db.Video.build(videoData)
|
||||
return { tagInstances, video }
|
||||
})
|
||||
.then(({ tagInstances, video }) => {
|
||||
const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename)
|
||||
return getVideoFileHeight(videoFilePath)
|
||||
.then(height => ({ tagInstances, video, videoFileHeight: height }))
|
||||
})
|
||||
.then(({ tagInstances, video, videoFileHeight }) => {
|
||||
const videoFileData = {
|
||||
extname: extname(videoPhysicalFile.filename),
|
||||
resolution: videoFileHeight,
|
||||
size: videoPhysicalFile.size
|
||||
}
|
||||
const videoFileData = {
|
||||
extname: extname(videoPhysicalFile.filename),
|
||||
resolution: videoFileHeight,
|
||||
size: videoPhysicalFile.size
|
||||
}
|
||||
const videoFile = db.VideoFile.build(videoFileData)
|
||||
const videoDir = CONFIG.STORAGE.VIDEOS_DIR
|
||||
const source = join(videoDir, videoPhysicalFile.filename)
|
||||
const destination = join(videoDir, video.getVideoFilename(videoFile))
|
||||
|
||||
const videoFile = db.VideoFile.build(videoFileData)
|
||||
return { tagInstances, video, videoFile }
|
||||
})
|
||||
.then(({ tagInstances, video, videoFile }) => {
|
||||
const videoDir = CONFIG.STORAGE.VIDEOS_DIR
|
||||
const source = join(videoDir, videoPhysicalFile.filename)
|
||||
const destination = join(videoDir, video.getVideoFilename(videoFile))
|
||||
await renamePromise(source, destination)
|
||||
// This is important in case if there is another attempt in the retry process
|
||||
videoPhysicalFile.filename = video.getVideoFilename(videoFile)
|
||||
|
||||
return renamePromise(source, destination)
|
||||
.then(() => {
|
||||
// This is important in case if there is another attempt in the retry process
|
||||
videoPhysicalFile.filename = video.getVideoFilename(videoFile)
|
||||
return { tagInstances, video, videoFile }
|
||||
})
|
||||
})
|
||||
.then(({ tagInstances, video, videoFile }) => {
|
||||
const tasks = []
|
||||
const tasks = []
|
||||
|
||||
tasks.push(
|
||||
video.createTorrentAndSetInfoHash(videoFile),
|
||||
video.createThumbnail(videoFile),
|
||||
video.createPreview(videoFile)
|
||||
)
|
||||
tasks.push(
|
||||
video.createTorrentAndSetInfoHash(videoFile),
|
||||
video.createThumbnail(videoFile),
|
||||
video.createPreview(videoFile)
|
||||
)
|
||||
|
||||
if (CONFIG.TRANSCODING.ENABLED === true) {
|
||||
// Put uuid because we don't have id auto incremented for now
|
||||
const dataInput = {
|
||||
videoUUID: video.uuid
|
||||
}
|
||||
if (CONFIG.TRANSCODING.ENABLED === true) {
|
||||
// Put uuid because we don't have id auto incremented for now
|
||||
const dataInput = {
|
||||
videoUUID: video.uuid
|
||||
}
|
||||
|
||||
tasks.push(
|
||||
JobScheduler.Instance.createJob(t, 'videoFileOptimizer', dataInput)
|
||||
)
|
||||
}
|
||||
tasks.push(
|
||||
JobScheduler.Instance.createJob(t, 'videoFileOptimizer', dataInput)
|
||||
)
|
||||
}
|
||||
await Promise.all(tasks)
|
||||
|
||||
return Promise.all(tasks).then(() => ({ tagInstances, video, videoFile }))
|
||||
})
|
||||
.then(({ tagInstances, video, videoFile }) => {
|
||||
const options = { transaction: t }
|
||||
const videoCreated = await video.save(sequelizeOptions)
|
||||
// Do not forget to add video channel information to the created video
|
||||
videoCreated.VideoChannel = res.locals.videoChannel
|
||||
videoUUID = videoCreated.uuid
|
||||
|
||||
return video.save(options)
|
||||
.then(videoCreated => {
|
||||
// Do not forget to add video channel information to the created video
|
||||
videoCreated.VideoChannel = res.locals.videoChannel
|
||||
videoUUID = videoCreated.uuid
|
||||
videoFile.videoId = video.id
|
||||
|
||||
return { tagInstances, video: videoCreated, videoFile }
|
||||
})
|
||||
})
|
||||
.then(({ tagInstances, video, videoFile }) => {
|
||||
const options = { transaction: t }
|
||||
videoFile.videoId = video.id
|
||||
await videoFile.save(sequelizeOptions)
|
||||
video.VideoFiles = [videoFile]
|
||||
|
||||
return videoFile.save(options)
|
||||
.then(() => video.VideoFiles = [ videoFile ])
|
||||
.then(() => ({ tagInstances, video }))
|
||||
})
|
||||
.then(({ tagInstances, video }) => {
|
||||
if (!tagInstances) return video
|
||||
if (videoInfo.tags) {
|
||||
const tagInstances = await db.Tag.findOrCreateTags(videoInfo.tags, t)
|
||||
|
||||
const options = { transaction: t }
|
||||
return video.setTags(tagInstances, options)
|
||||
.then(() => {
|
||||
video.Tags = tagInstances
|
||||
return video
|
||||
})
|
||||
})
|
||||
.then(video => {
|
||||
// Let transcoding job send the video to friends because the video file extension might change
|
||||
if (CONFIG.TRANSCODING.ENABLED === true) return undefined
|
||||
await video.setTags(tagInstances, sequelizeOptions)
|
||||
video.Tags = tagInstances
|
||||
}
|
||||
|
||||
return video.toAddRemoteJSON()
|
||||
.then(remoteVideo => {
|
||||
// Now we'll add the video's meta data to our friends
|
||||
return addVideoToFriends(remoteVideo, t)
|
||||
})
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoUUID))
|
||||
.catch((err: Error) => {
|
||||
logger.debug('Cannot insert the video.', err)
|
||||
throw err
|
||||
// Let transcoding job send the video to friends because the video file extension might change
|
||||
if (CONFIG.TRANSCODING.ENABLED === true) return undefined
|
||||
|
||||
const remoteVideo = await video.toAddRemoteJSON()
|
||||
// Now we'll add the video's meta data to our friends
|
||||
return addVideoToFriends(remoteVideo, t)
|
||||
})
|
||||
|
||||
logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoUUID)
|
||||
}
|
||||
|
||||
function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const options = {
|
||||
arguments: [ req, res ],
|
||||
errorMessage: 'Cannot update the video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(updateVideo, options)
|
||||
.then(() => {
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
.catch(err => next(err))
|
||||
await retryTransactionWrapper(updateVideo, options)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function updateVideo (req: express.Request, res: express.Response) {
|
||||
async function updateVideo (req: express.Request, res: express.Response) {
|
||||
const videoInstance = res.locals.video
|
||||
const videoFieldsSave = videoInstance.toJSON()
|
||||
const videoInfoToUpdate: VideoUpdate = req.body
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
let tagsPromise: Promise<TagInstance[]>
|
||||
if (!videoInfoToUpdate.tags) {
|
||||
tagsPromise = Promise.resolve(null)
|
||||
} else {
|
||||
tagsPromise = db.Tag.findOrCreateTags(videoInfoToUpdate.tags, t)
|
||||
}
|
||||
try {
|
||||
await db.sequelize.transaction(async t => {
|
||||
const sequelizeOptions = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
return tagsPromise
|
||||
.then(tagInstances => {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
if (videoInfoToUpdate.name !== undefined) videoInstance.set('name', videoInfoToUpdate.name)
|
||||
if (videoInfoToUpdate.category !== undefined) videoInstance.set('category', videoInfoToUpdate.category)
|
||||
if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence)
|
||||
if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language)
|
||||
if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw)
|
||||
if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
|
||||
|
||||
if (videoInfoToUpdate.name !== undefined) videoInstance.set('name', videoInfoToUpdate.name)
|
||||
if (videoInfoToUpdate.category !== undefined) videoInstance.set('category', videoInfoToUpdate.category)
|
||||
if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence)
|
||||
if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language)
|
||||
if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw)
|
||||
if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description)
|
||||
await videoInstance.save(sequelizeOptions)
|
||||
|
||||
return videoInstance.save(options).then(() => tagInstances)
|
||||
})
|
||||
.then(tagInstances => {
|
||||
if (!tagInstances) return
|
||||
if (videoInfoToUpdate.tags) {
|
||||
const tagInstances = await db.Tag.findOrCreateTags(videoInfoToUpdate.tags, t)
|
||||
|
||||
const options = { transaction: t }
|
||||
return videoInstance.setTags(tagInstances, options)
|
||||
.then(() => {
|
||||
videoInstance.Tags = tagInstances
|
||||
await videoInstance.setTags(tagInstances, sequelizeOptions)
|
||||
videoInstance.Tags = tagInstances
|
||||
}
|
||||
|
||||
return
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
const json = videoInstance.toUpdateRemoteJSON()
|
||||
const json = videoInstance.toUpdateRemoteJSON()
|
||||
|
||||
// Now we'll update the video's meta data to our friends
|
||||
return updateVideoToFriends(json, t)
|
||||
})
|
||||
|
||||
// Now we'll update the video's meta data to our friends
|
||||
return updateVideoToFriends(json, t)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid)
|
||||
})
|
||||
.catch(err => {
|
||||
logger.debug('Cannot update the video.', err)
|
||||
|
||||
} catch (err) {
|
||||
// Force fields we want to update
|
||||
// If the transaction is retried, sequelize will think the object has not changed
|
||||
// So it will skip the SQL request, even if the last one was ROLLBACKed!
|
||||
Object.keys(videoFieldsSave).forEach(key => {
|
||||
const value = videoFieldsSave[key]
|
||||
videoInstance.set(key, value)
|
||||
})
|
||||
resetSequelizeInstance(videoInstance, videoFieldsSave)
|
||||
|
||||
throw err
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function getVideo (req: express.Request, res: express.Response) {
|
||||
|
@ -365,17 +303,17 @@ function getVideo (req: express.Request, res: express.Response) {
|
|||
|
||||
if (videoInstance.isOwned()) {
|
||||
// The increment is done directly in the database, not using the instance value
|
||||
// FIXME: make a real view system
|
||||
// For example, only add a view when a user watch a video during 30s etc
|
||||
videoInstance.increment('views')
|
||||
.then(() => {
|
||||
// FIXME: make a real view system
|
||||
// For example, only add a view when a user watch a video during 30s etc
|
||||
const qaduParams = {
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.VIEWS
|
||||
}
|
||||
return quickAndDirtyUpdateVideoToFriends(qaduParams)
|
||||
})
|
||||
.catch(err => logger.error('Cannot add view to video %d.', videoInstance.id, err))
|
||||
.catch(err => logger.error('Cannot add view to video %s.', videoInstance.uuid, err))
|
||||
} else {
|
||||
// Just send the event to our friends
|
||||
const eventParams = {
|
||||
|
@ -383,48 +321,48 @@ function getVideo (req: express.Request, res: express.Response) {
|
|||
type: REQUEST_VIDEO_EVENT_TYPES.VIEWS
|
||||
}
|
||||
addEventToRemoteVideo(eventParams)
|
||||
.catch(err => logger.error('Cannot add event to remote video %s.', videoInstance.uuid, err))
|
||||
}
|
||||
|
||||
// Do not wait the view system
|
||||
res.json(videoInstance.toFormattedDetailsJSON())
|
||||
return res.json(videoInstance.toFormattedDetailsJSON())
|
||||
}
|
||||
|
||||
function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.Video.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
.then(result => res.json(getFormattedObjects(result.data, result.total)))
|
||||
.catch(err => next(err))
|
||||
async function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.Video.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
||||
function removeVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function removeVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const options = {
|
||||
arguments: [ req, res ],
|
||||
errorMessage: 'Cannot remove the video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(removeVideo, options)
|
||||
.then(() => {
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
.catch(err => next(err))
|
||||
await retryTransactionWrapper(removeVideo, options)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function removeVideo (req: express.Request, res: express.Response) {
|
||||
async function removeVideo (req: express.Request, res: express.Response) {
|
||||
const videoInstance: VideoInstance = res.locals.video
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return videoInstance.destroy({ transaction: t })
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Errors when removed the video.', err)
|
||||
throw err
|
||||
await db.sequelize.transaction(async t => {
|
||||
await videoInstance.destroy({ transaction: t })
|
||||
})
|
||||
|
||||
logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
|
||||
}
|
||||
|
||||
function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.Video.searchAndPopulateAuthorAndPodAndTags(req.params.value, req.query.field, req.query.start, req.query.count, req.query.sort)
|
||||
.then(result => res.json(getFormattedObjects(result.data, result.total)))
|
||||
.catch(err => next(err))
|
||||
async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const resultList = await db.Video.searchAndPopulateAuthorAndPodAndTags(
|
||||
req.params.value,
|
||||
req.query.field,
|
||||
req.query.start,
|
||||
req.query.count,
|
||||
req.query.sort
|
||||
)
|
||||
|
||||
return res.json(getFormattedObjects(resultList.data, resultList.total))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as express from 'express'
|
||||
import * as Promise from 'bluebird'
|
||||
|
||||
import { database as db } from '../../../initializers/database'
|
||||
import {
|
||||
|
@ -17,7 +16,8 @@ import {
|
|||
} from '../../../lib'
|
||||
import {
|
||||
authenticate,
|
||||
videoRateValidator
|
||||
videoRateValidator,
|
||||
asyncMiddleware
|
||||
} from '../../../middlewares'
|
||||
import { UserVideoRateUpdate, VideoRateType } from '../../../../shared'
|
||||
|
||||
|
@ -26,7 +26,7 @@ const rateVideoRouter = express.Router()
|
|||
rateVideoRouter.put('/:id/rate',
|
||||
authenticate,
|
||||
videoRateValidator,
|
||||
rateVideoRetryWrapper
|
||||
asyncMiddleware(rateVideoRetryWrapper)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -37,126 +37,107 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function rateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function rateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const options = {
|
||||
arguments: [ req, res ],
|
||||
errorMessage: 'Cannot update the user video rate.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(rateVideo, options)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
await retryTransactionWrapper(rateVideo, options)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function rateVideo (req: express.Request, res: express.Response) {
|
||||
async function rateVideo (req: express.Request, res: express.Response) {
|
||||
const body: UserVideoRateUpdate = req.body
|
||||
const rateType = body.rating
|
||||
const videoInstance = res.locals.video
|
||||
const userInstance = res.locals.oauth.token.User
|
||||
|
||||
return db.sequelize.transaction(t => {
|
||||
return db.UserVideoRate.load(userInstance.id, videoInstance.id, t)
|
||||
.then(previousRate => {
|
||||
const options = { transaction: t }
|
||||
await db.sequelize.transaction(async t => {
|
||||
const sequelizeOptions = { transaction: t }
|
||||
const previousRate = await db.UserVideoRate.load(userInstance.id, videoInstance.id, t)
|
||||
|
||||
let likesToIncrement = 0
|
||||
let dislikesToIncrement = 0
|
||||
let likesToIncrement = 0
|
||||
let dislikesToIncrement = 0
|
||||
|
||||
if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
|
||||
else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
|
||||
if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
|
||||
else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
|
||||
|
||||
let promise: Promise<any>
|
||||
// There was a previous rate, update it
|
||||
if (previousRate) {
|
||||
// We will remove the previous rate, so we will need to update the video count attribute
|
||||
if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
|
||||
else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
|
||||
|
||||
// There was a previous rate, update it
|
||||
if (previousRate) {
|
||||
// We will remove the previous rate, so we will need to update the video count attribute
|
||||
if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
|
||||
else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
|
||||
if (rateType === 'none') { // Destroy previous rate
|
||||
await previousRate.destroy()
|
||||
} else { // Update previous rate
|
||||
previousRate.type = rateType as VideoRateType
|
||||
|
||||
if (rateType === 'none') { // Destroy previous rate
|
||||
promise = previousRate.destroy()
|
||||
} else { // Update previous rate
|
||||
previousRate.type = rateType as VideoRateType
|
||||
await previousRate.save()
|
||||
}
|
||||
} else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate
|
||||
const query = {
|
||||
userId: userInstance.id,
|
||||
videoId: videoInstance.id,
|
||||
type: rateType
|
||||
}
|
||||
|
||||
promise = previousRate.save()
|
||||
}
|
||||
} else if (rateType !== 'none') { // There was not a previous rate, insert a new one if there is a rate
|
||||
const query = {
|
||||
userId: userInstance.id,
|
||||
videoId: videoInstance.id,
|
||||
type: rateType
|
||||
}
|
||||
await db.UserVideoRate.create(query, sequelizeOptions)
|
||||
}
|
||||
|
||||
promise = db.UserVideoRate.create(query, options)
|
||||
} else {
|
||||
promise = Promise.resolve()
|
||||
}
|
||||
const incrementQuery = {
|
||||
likes: likesToIncrement,
|
||||
dislikes: dislikesToIncrement
|
||||
}
|
||||
|
||||
return promise.then(() => ({ likesToIncrement, dislikesToIncrement }))
|
||||
})
|
||||
.then(({ likesToIncrement, dislikesToIncrement }) => {
|
||||
const options = { transaction: t }
|
||||
const incrementQuery = {
|
||||
likes: likesToIncrement,
|
||||
dislikes: dislikesToIncrement
|
||||
}
|
||||
// Even if we do not own the video we increment the attributes
|
||||
// It is useful for the user to have a feedback
|
||||
await videoInstance.increment(incrementQuery, sequelizeOptions)
|
||||
|
||||
// Even if we do not own the video we increment the attributes
|
||||
// It is usefull for the user to have a feedback
|
||||
return videoInstance.increment(incrementQuery, options).then(() => ({ likesToIncrement, dislikesToIncrement }))
|
||||
})
|
||||
.then(({ likesToIncrement, dislikesToIncrement }) => {
|
||||
// No need for an event type, we own the video
|
||||
if (videoInstance.isOwned()) return { likesToIncrement, dislikesToIncrement }
|
||||
// Send a event to original pod
|
||||
if (videoInstance.isOwned() === false) {
|
||||
|
||||
const eventsParams = []
|
||||
const eventsParams = []
|
||||
|
||||
if (likesToIncrement !== 0) {
|
||||
eventsParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
|
||||
count: likesToIncrement
|
||||
})
|
||||
}
|
||||
if (likesToIncrement !== 0) {
|
||||
eventsParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
|
||||
count: likesToIncrement
|
||||
})
|
||||
}
|
||||
|
||||
if (dislikesToIncrement !== 0) {
|
||||
eventsParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
|
||||
count: dislikesToIncrement
|
||||
})
|
||||
}
|
||||
if (dislikesToIncrement !== 0) {
|
||||
eventsParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
|
||||
count: dislikesToIncrement
|
||||
})
|
||||
}
|
||||
|
||||
return addEventsToRemoteVideo(eventsParams, t).then(() => ({ likesToIncrement, dislikesToIncrement }))
|
||||
})
|
||||
.then(({ likesToIncrement, dislikesToIncrement }) => {
|
||||
// We do not own the video, there is no need to send a quick and dirty update to friends
|
||||
// Our rate was already sent by the addEvent function
|
||||
if (videoInstance.isOwned() === false) return undefined
|
||||
await addEventsToRemoteVideo(eventsParams, t)
|
||||
} else { // We own the video, we need to send a quick and dirty update to friends to notify the counts changed
|
||||
const qadusParams = []
|
||||
|
||||
const qadusParams = []
|
||||
if (likesToIncrement !== 0) {
|
||||
qadusParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.LIKES
|
||||
})
|
||||
}
|
||||
|
||||
if (likesToIncrement !== 0) {
|
||||
qadusParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.LIKES
|
||||
})
|
||||
}
|
||||
if (dislikesToIncrement !== 0) {
|
||||
qadusParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
|
||||
})
|
||||
}
|
||||
|
||||
if (dislikesToIncrement !== 0) {
|
||||
qadusParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
|
||||
})
|
||||
}
|
||||
|
||||
return quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username))
|
||||
.catch(err => {
|
||||
// This is just a debug because we will retry the insert
|
||||
logger.debug('Cannot add the user video rate.', err)
|
||||
throw err
|
||||
await quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
|
||||
}
|
||||
})
|
||||
|
||||
logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as express from 'express'
|
||||
import { join } from 'path'
|
||||
import * as validator from 'validator'
|
||||
import * as Promise from 'bluebird'
|
||||
import * as Bluebird from 'bluebird'
|
||||
|
||||
import { database as db } from '../initializers/database'
|
||||
import {
|
||||
|
@ -11,6 +11,7 @@ import {
|
|||
OPENGRAPH_AND_OEMBED_COMMENT
|
||||
} from '../initializers'
|
||||
import { root, readFileBufferPromise, escapeHTML } from '../helpers'
|
||||
import { asyncMiddleware } from '../middlewares'
|
||||
import { VideoInstance } from '../models'
|
||||
|
||||
const clientsRouter = express.Router()
|
||||
|
@ -21,7 +22,9 @@ const indexPath = join(distPath, 'index.html')
|
|||
|
||||
// Special route that add OpenGraph and oEmbed tags
|
||||
// Do not use a template engine for a so little thing
|
||||
clientsRouter.use('/videos/watch/:id', generateWatchHtmlPage)
|
||||
clientsRouter.use('/videos/watch/:id',
|
||||
asyncMiddleware(generateWatchHtmlPage)
|
||||
)
|
||||
|
||||
clientsRouter.use('/videos/embed', (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
res.sendFile(embedPath)
|
||||
|
@ -90,9 +93,9 @@ function addOpenGraphAndOEmbedTags (htmlStringPage: string, video: VideoInstance
|
|||
return htmlStringPage.replace(OPENGRAPH_AND_OEMBED_COMMENT, tagsString)
|
||||
}
|
||||
|
||||
function generateWatchHtmlPage (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
async function generateWatchHtmlPage (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const videoId = '' + req.params.id
|
||||
let videoPromise: Promise<VideoInstance>
|
||||
let videoPromise: Bluebird<VideoInstance>
|
||||
|
||||
// Let Angular application handle errors
|
||||
if (validator.isUUID(videoId, 4)) {
|
||||
|
@ -103,21 +106,19 @@ function generateWatchHtmlPage (req: express.Request, res: express.Response, nex
|
|||
return res.sendFile(indexPath)
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
let [ file, video ] = await Promise.all([
|
||||
readFileBufferPromise(indexPath),
|
||||
videoPromise
|
||||
])
|
||||
.then(([ file, video ]) => {
|
||||
file = file as Buffer
|
||||
video = video as VideoInstance
|
||||
|
||||
const html = file.toString()
|
||||
file = file as Buffer
|
||||
video = video as VideoInstance
|
||||
|
||||
// Let Angular application handle errors
|
||||
if (!video) return res.sendFile(indexPath)
|
||||
const html = file.toString()
|
||||
|
||||
const htmlStringPageWithTags = addOpenGraphAndOEmbedTags(html, video)
|
||||
res.set('Content-Type', 'text/html; charset=UTF-8').send(htmlStringPageWithTags)
|
||||
})
|
||||
.catch(err => next(err))
|
||||
// Let Angular application handle errors
|
||||
if (!video) return res.sendFile(indexPath)
|
||||
|
||||
const htmlStringPageWithTags = addOpenGraphAndOEmbedTags(html, video)
|
||||
res.set('Content-Type', 'text/html; charset=UTF-8').send(htmlStringPageWithTags)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
STATIC_PATHS
|
||||
} from '../initializers'
|
||||
import { VideosPreviewCache } from '../lib'
|
||||
import { asyncMiddleware } from '../middlewares'
|
||||
|
||||
const staticRouter = express.Router()
|
||||
|
||||
|
@ -39,7 +40,7 @@ staticRouter.use(
|
|||
// Video previews path for express
|
||||
staticRouter.use(
|
||||
STATIC_PATHS.PREVIEWS + ':uuid.jpg',
|
||||
getPreview
|
||||
asyncMiddleware(getPreview)
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -50,11 +51,9 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function getPreview (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
VideosPreviewCache.Instance.getPreviewPath(req.params.uuid)
|
||||
.then(path => {
|
||||
if (!path) return res.sendStatus(404)
|
||||
async function getPreview (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const path = await VideosPreviewCache.Instance.getPreviewPath(req.params.uuid)
|
||||
if (!path) return res.sendStatus(404)
|
||||
|
||||
return res.sendFile(path, { maxAge: STATIC_MAX_AGE })
|
||||
})
|
||||
return res.sendFile(path, { maxAge: STATIC_MAX_AGE })
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// TODO: import from ES6 when retry typing file will include errorFilter function
|
||||
import * as retry from 'async/retry'
|
||||
import * as Promise from 'bluebird'
|
||||
|
||||
import { logger } from './logger'
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import * as express from 'express'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import * as Promise from 'bluebird'
|
||||
|
||||
import { pseudoRandomBytesPromise } from './core-utils'
|
||||
|
@ -69,6 +70,13 @@ function computeResolutionsToTranscode (videoFileHeight: number) {
|
|||
return resolutionsEnabled
|
||||
}
|
||||
|
||||
function resetSequelizeInstance (instance: Sequelize.Instance<any>, savedFields: object) {
|
||||
Object.keys(savedFields).forEach(key => {
|
||||
const value = savedFields[key]
|
||||
instance.set(key, value)
|
||||
})
|
||||
}
|
||||
|
||||
type SortType = { sortModel: any, sortValue: string }
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -79,5 +87,6 @@ export {
|
|||
getFormattedObjects,
|
||||
isSignupAllowed,
|
||||
computeResolutionsToTranscode,
|
||||
resetSequelizeInstance,
|
||||
SortType
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ const sequelize = new Sequelize(dbname, username, password, {
|
|||
host: CONFIG.DATABASE.HOSTNAME,
|
||||
port: CONFIG.DATABASE.PORT,
|
||||
benchmark: isTestInstance(),
|
||||
isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.SERIALIZABLE,
|
||||
|
||||
logging: (message: string, benchmark: number) => {
|
||||
let newMessage = message
|
||||
|
|
|
@ -2,12 +2,11 @@ import * as Sequelize from 'sequelize'
|
|||
|
||||
import { addVideoChannelToFriends } from './friends'
|
||||
import { database as db } from '../initializers'
|
||||
import { logger } from '../helpers'
|
||||
import { AuthorInstance } from '../models'
|
||||
import { VideoChannelCreate } from '../../shared/models'
|
||||
|
||||
function createVideoChannel (videoChannelInfo: VideoChannelCreate, author: AuthorInstance, t: Sequelize.Transaction) {
|
||||
let videoChannelUUID = ''
|
||||
|
||||
async function createVideoChannel (videoChannelInfo: VideoChannelCreate, author: AuthorInstance, t: Sequelize.Transaction) {
|
||||
const videoChannelData = {
|
||||
name: videoChannelInfo.name,
|
||||
description: videoChannelInfo.description,
|
||||
|
@ -18,25 +17,34 @@ function createVideoChannel (videoChannelInfo: VideoChannelCreate, author: Autho
|
|||
const videoChannel = db.VideoChannel.build(videoChannelData)
|
||||
const options = { transaction: t }
|
||||
|
||||
return videoChannel.save(options)
|
||||
.then(videoChannelCreated => {
|
||||
// Do not forget to add Author information to the created video channel
|
||||
videoChannelCreated.Author = author
|
||||
videoChannelUUID = videoChannelCreated.uuid
|
||||
const videoChannelCreated = await videoChannel.save(options)
|
||||
|
||||
return videoChannelCreated
|
||||
})
|
||||
.then(videoChannel => {
|
||||
const remoteVideoChannel = videoChannel.toAddRemoteJSON()
|
||||
// Do not forget to add Author information to the created video channel
|
||||
videoChannelCreated.Author = author
|
||||
|
||||
// Now we'll add the video channel's meta data to our friends
|
||||
return addVideoChannelToFriends(remoteVideoChannel, t)
|
||||
})
|
||||
.then(() => videoChannelUUID) // Return video channel UUID
|
||||
const remoteVideoChannel = videoChannelCreated.toAddRemoteJSON()
|
||||
|
||||
// Now we'll add the video channel's meta data to our friends
|
||||
await addVideoChannelToFriends(remoteVideoChannel, t)
|
||||
|
||||
return videoChannelCreated
|
||||
}
|
||||
|
||||
async function fetchVideoChannelByHostAndUUID (podHost: string, uuid: string, t: Sequelize.Transaction) {
|
||||
try {
|
||||
const videoChannel = await db.VideoChannel.loadByHostAndUUID(podHost, uuid, t)
|
||||
if (!videoChannel) throw new Error('Video channel not found')
|
||||
|
||||
return videoChannel
|
||||
} catch (err) {
|
||||
logger.error('Cannot load video channel from host and uuid.', { error: err.stack, podHost, uuid })
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
createVideoChannel
|
||||
createVideoChannel,
|
||||
fetchVideoChannelByHostAndUUID
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
import { Request, Response, NextFunction } from 'express'
|
||||
|
||||
// Syntactic sugar to avoid try/catch in express controllers
|
||||
// Thanks: https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016
|
||||
function asyncMiddleware (fn: (req: Request, res: Response, next: NextFunction) => Promise<any>) {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
return Promise.resolve(fn(req, res, next))
|
||||
.catch(next)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
asyncMiddleware
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
export * from './validators'
|
||||
export * from './admin'
|
||||
export * from './async'
|
||||
export * from './oauth'
|
||||
export * from './pagination'
|
||||
export * from './pods'
|
||||
|
|
Loading…
Reference in New Issue