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