mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-05 02:39:33 +02:00
Move to promises
Closes https://github.com/Chocobozzz/PeerTube/issues/74
This commit is contained in:
parent
5fe7e89831
commit
6fcd19ba73
88 changed files with 1980 additions and 2505 deletions
|
@ -24,16 +24,17 @@ function getLocalClient (req: express.Request, res: express.Response, next: expr
|
|||
return res.type('json').status(403).end()
|
||||
}
|
||||
|
||||
db.OAuthClient.loadFirstClient(function (err, client) {
|
||||
if (err) return next(err)
|
||||
if (!client) return next(new Error('No client available.'))
|
||||
db.OAuthClient.loadFirstClient()
|
||||
.then(client => {
|
||||
if (!client) throw new Error('No client available.')
|
||||
|
||||
const json: OAuthClientLocal = {
|
||||
client_id: client.clientId,
|
||||
client_secret: client.clientSecret
|
||||
}
|
||||
res.json(json)
|
||||
})
|
||||
const json: OAuthClientLocal = {
|
||||
client_id: client.clientId,
|
||||
client_secret: client.clientSecret
|
||||
}
|
||||
res.json(json)
|
||||
})
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as express from 'express'
|
||||
import { waterfall } from 'async'
|
||||
|
||||
import { database as db } from '../../initializers/database'
|
||||
import { CONFIG } from '../../initializers'
|
||||
|
@ -57,65 +56,39 @@ export {
|
|||
function addPods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const informations = req.body
|
||||
|
||||
waterfall<string, Error>([
|
||||
function addPod (callback) {
|
||||
const pod = db.Pod.build(informations)
|
||||
pod.save().asCallback(function (err, podCreated) {
|
||||
// Be sure about the number of parameters for the callback
|
||||
return callback(err, podCreated)
|
||||
})
|
||||
},
|
||||
|
||||
function sendMyVideos (podCreated: PodInstance, callback) {
|
||||
sendOwnedVideosToPod(podCreated.id)
|
||||
|
||||
callback(null)
|
||||
},
|
||||
|
||||
function fetchMyCertificate (callback) {
|
||||
getMyPublicCert(function (err, cert) {
|
||||
if (err) {
|
||||
logger.error('Cannot read cert file.')
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
return callback(null, cert)
|
||||
})
|
||||
}
|
||||
], function (err, cert) {
|
||||
if (err) return next(err)
|
||||
|
||||
return res.json({ cert: cert, email: CONFIG.ADMIN.EMAIL })
|
||||
})
|
||||
const pod = db.Pod.build(informations)
|
||||
pod.save()
|
||||
.then(podCreated => {
|
||||
return sendOwnedVideosToPod(podCreated.id)
|
||||
})
|
||||
.then(() => {
|
||||
return getMyPublicCert()
|
||||
})
|
||||
.then(cert => {
|
||||
return res.json({ cert: cert, email: CONFIG.ADMIN.EMAIL })
|
||||
})
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function listPods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.Pod.list(function (err, podsList) {
|
||||
if (err) return next(err)
|
||||
|
||||
res.json(getFormatedObjects(podsList, podsList.length))
|
||||
})
|
||||
db.Pod.list()
|
||||
.then(podsList => res.json(getFormatedObjects(podsList, podsList.length)))
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function makeFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const hosts = req.body.hosts as string[]
|
||||
|
||||
makeFriends(hosts, function (err) {
|
||||
if (err) {
|
||||
logger.error('Could not make friends.', { error: err })
|
||||
return
|
||||
}
|
||||
|
||||
logger.info('Made friends!')
|
||||
})
|
||||
makeFriends(hosts)
|
||||
.then(() => logger.info('Made friends!'))
|
||||
.catch(err => logger.error('Could not make friends.', { error: err }))
|
||||
|
||||
// Don't wait the process that could be long
|
||||
res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function quitFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
quitFriends(function (err) {
|
||||
if (err) return next(err)
|
||||
|
||||
res.type('json').status(204).end()
|
||||
})
|
||||
quitFriends()
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import * as express from 'express'
|
||||
import * as waterfall from 'async/waterfall'
|
||||
|
||||
import { database as db } from '../../../initializers/database'
|
||||
import { checkSignature, signatureValidator } from '../../../middlewares'
|
||||
|
@ -24,17 +23,10 @@ export {
|
|||
function removePods (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const host = req.body.signature.host
|
||||
|
||||
waterfall([
|
||||
function loadPod (callback) {
|
||||
db.Pod.loadByHost(host, callback)
|
||||
},
|
||||
|
||||
function deletePod (pod, callback) {
|
||||
pod.destroy().asCallback(callback)
|
||||
}
|
||||
], function (err) {
|
||||
if (err) return next(err)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
db.Pod.loadByHost(host)
|
||||
.then(pod => {
|
||||
return pod.destroy()
|
||||
})
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import * as express from 'express'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { eachSeries, waterfall } from 'async'
|
||||
import * as Promise from 'bluebird'
|
||||
|
||||
import { database as db } from '../../../initializers/database'
|
||||
import {
|
||||
|
@ -16,20 +15,14 @@ import {
|
|||
remoteQaduVideosValidator,
|
||||
remoteEventsVideosValidator
|
||||
} from '../../../middlewares'
|
||||
import {
|
||||
logger,
|
||||
commitTransaction,
|
||||
retryTransactionWrapper,
|
||||
rollbackTransaction,
|
||||
startSerializableTransaction
|
||||
} from '../../../helpers'
|
||||
import { logger, retryTransactionWrapper } from '../../../helpers'
|
||||
import { quickAndDirtyUpdatesVideoToFriends } from '../../../lib'
|
||||
import { PodInstance, VideoInstance } from '../../../models'
|
||||
|
||||
const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS]
|
||||
|
||||
// Functions to call when processing a remote request
|
||||
const functionsHash = {}
|
||||
const functionsHash: { [ id: string ]: (...args) => Promise<any> } = {}
|
||||
functionsHash[ENDPOINT_ACTIONS.ADD] = addRemoteVideoRetryWrapper
|
||||
functionsHash[ENDPOINT_ACTIONS.UPDATE] = updateRemoteVideoRetryWrapper
|
||||
functionsHash[ENDPOINT_ACTIONS.REMOVE] = removeRemoteVideo
|
||||
|
@ -72,20 +65,19 @@ function remoteVideos (req: express.Request, res: express.Response, next: expres
|
|||
|
||||
// We need to process in the same order to keep consistency
|
||||
// TODO: optimization
|
||||
eachSeries(requests, function (request: any, callbackEach) {
|
||||
Promise.mapSeries(requests, (request: any) => {
|
||||
const data = request.data
|
||||
|
||||
// Get the function we need to call in order to process the request
|
||||
const fun = functionsHash[request.type]
|
||||
if (fun === undefined) {
|
||||
logger.error('Unkown remote request type %s.', request.type)
|
||||
return callbackEach(null)
|
||||
return
|
||||
}
|
||||
|
||||
fun.call(this, data, fromPod, callbackEach)
|
||||
}, function (err) {
|
||||
if (err) logger.error('Error managing remote videos.', { error: err })
|
||||
return fun.call(this, data, fromPod)
|
||||
})
|
||||
.catch(err => logger.error('Error managing remote videos.', { error: err }))
|
||||
|
||||
// We don't need to keep the other pod waiting
|
||||
return res.type('json').status(204).end()
|
||||
|
@ -95,13 +87,12 @@ function remoteVideosQadu (req: express.Request, res: express.Response, next: ex
|
|||
const requests = req.body.data
|
||||
const fromPod = res.locals.secure.pod
|
||||
|
||||
eachSeries(requests, function (request: any, callbackEach) {
|
||||
Promise.mapSeries(requests, (request: any) => {
|
||||
const videoData = request.data
|
||||
|
||||
quickAndDirtyUpdateVideoRetryWrapper(videoData, fromPod, callbackEach)
|
||||
}, function (err) {
|
||||
if (err) logger.error('Error managing remote videos.', { error: err })
|
||||
return quickAndDirtyUpdateVideoRetryWrapper(videoData, fromPod)
|
||||
})
|
||||
.catch(err => logger.error('Error managing remote videos.', { error: err }))
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
@ -110,414 +101,303 @@ function remoteVideosEvents (req: express.Request, res: express.Response, next:
|
|||
const requests = req.body.data
|
||||
const fromPod = res.locals.secure.pod
|
||||
|
||||
eachSeries(requests, function (request: any, callbackEach) {
|
||||
Promise.mapSeries(requests, (request: any) => {
|
||||
const eventData = request.data
|
||||
|
||||
processVideosEventsRetryWrapper(eventData, fromPod, callbackEach)
|
||||
}, function (err) {
|
||||
if (err) logger.error('Error managing remote videos.', { error: err })
|
||||
return processVideosEventsRetryWrapper(eventData, fromPod)
|
||||
})
|
||||
.catch(err => logger.error('Error managing remote videos.', { error: err }))
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
}
|
||||
|
||||
function processVideosEventsRetryWrapper (eventData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) {
|
||||
function processVideosEventsRetryWrapper (eventData: any, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ eventData, fromPod ],
|
||||
errorMessage: 'Cannot process videos events with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(processVideosEvents, options, finalCallback)
|
||||
return retryTransactionWrapper(processVideosEvents, options)
|
||||
}
|
||||
|
||||
function processVideosEvents (eventData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) {
|
||||
waterfall([
|
||||
startSerializableTransaction,
|
||||
function processVideosEvents (eventData: any, fromPod: PodInstance) {
|
||||
|
||||
function findVideo (t, callback) {
|
||||
fetchOwnedVideo(eventData.remoteId, function (err, videoInstance) {
|
||||
return callback(err, t, videoInstance)
|
||||
})
|
||||
},
|
||||
return db.sequelize.transaction(t => {
|
||||
return fetchOwnedVideo(eventData.remoteId)
|
||||
.then(videoInstance => {
|
||||
const options = { transaction: t }
|
||||
|
||||
function updateVideoIntoDB (t, videoInstance, callback) {
|
||||
const options = { transaction: t }
|
||||
let columnToUpdate
|
||||
let qaduType
|
||||
|
||||
let columnToUpdate
|
||||
let qaduType
|
||||
switch (eventData.eventType) {
|
||||
case REQUEST_VIDEO_EVENT_TYPES.VIEWS:
|
||||
columnToUpdate = 'views'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.VIEWS
|
||||
break
|
||||
|
||||
switch (eventData.eventType) {
|
||||
case REQUEST_VIDEO_EVENT_TYPES.VIEWS:
|
||||
columnToUpdate = 'views'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.VIEWS
|
||||
break
|
||||
case REQUEST_VIDEO_EVENT_TYPES.LIKES:
|
||||
columnToUpdate = 'likes'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.LIKES
|
||||
break
|
||||
|
||||
case REQUEST_VIDEO_EVENT_TYPES.LIKES:
|
||||
columnToUpdate = 'likes'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.LIKES
|
||||
break
|
||||
case REQUEST_VIDEO_EVENT_TYPES.DISLIKES:
|
||||
columnToUpdate = 'dislikes'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.DISLIKES
|
||||
break
|
||||
|
||||
case REQUEST_VIDEO_EVENT_TYPES.DISLIKES:
|
||||
columnToUpdate = 'dislikes'
|
||||
qaduType = REQUEST_VIDEO_QADU_TYPES.DISLIKES
|
||||
break
|
||||
|
||||
default:
|
||||
return callback(new Error('Unknown video event type.'))
|
||||
}
|
||||
|
||||
const query = {}
|
||||
query[columnToUpdate] = eventData.count
|
||||
|
||||
videoInstance.increment(query, options).asCallback(function (err) {
|
||||
return callback(err, t, videoInstance, qaduType)
|
||||
})
|
||||
},
|
||||
|
||||
function sendQaduToFriends (t, videoInstance, qaduType, callback) {
|
||||
const qadusParams = [
|
||||
{
|
||||
videoId: videoInstance.id,
|
||||
type: qaduType
|
||||
default:
|
||||
throw new Error('Unknown video event type.')
|
||||
}
|
||||
]
|
||||
|
||||
quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) {
|
||||
return callback(err, t)
|
||||
const query = {}
|
||||
query[columnToUpdate] = eventData.count
|
||||
|
||||
return videoInstance.increment(query, options).then(() => ({ videoInstance, qaduType }))
|
||||
})
|
||||
},
|
||||
.then(({ videoInstance, qaduType }) => {
|
||||
const qadusParams = [
|
||||
{
|
||||
videoId: videoInstance.id,
|
||||
type: qaduType
|
||||
}
|
||||
]
|
||||
|
||||
commitTransaction
|
||||
|
||||
], function (err: Error, t: Sequelize.Transaction) {
|
||||
if (err) {
|
||||
logger.debug('Cannot process a video event.', { error: err })
|
||||
return rollbackTransaction(err, t, finalCallback)
|
||||
}
|
||||
|
||||
logger.info('Remote video event processed for video %s.', eventData.remoteId)
|
||||
return finalCallback(null)
|
||||
return quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('Remote video event processed for video %s.', eventData.remoteId))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot process a video event.', { error: err })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
function quickAndDirtyUpdateVideoRetryWrapper (videoData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) {
|
||||
function quickAndDirtyUpdateVideoRetryWrapper (videoData: any, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoData, fromPod ],
|
||||
errorMessage: 'Cannot update quick and dirty the remote video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(quickAndDirtyUpdateVideo, options, finalCallback)
|
||||
return retryTransactionWrapper(quickAndDirtyUpdateVideo, options)
|
||||
}
|
||||
|
||||
function quickAndDirtyUpdateVideo (videoData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) {
|
||||
function quickAndDirtyUpdateVideo (videoData: any, fromPod: PodInstance) {
|
||||
let videoName
|
||||
|
||||
waterfall([
|
||||
startSerializableTransaction,
|
||||
return db.sequelize.transaction(t => {
|
||||
return fetchRemoteVideo(fromPod.host, videoData.remoteId)
|
||||
.then(videoInstance => {
|
||||
const options = { transaction: t }
|
||||
|
||||
function findVideo (t, callback) {
|
||||
fetchRemoteVideo(fromPod.host, videoData.remoteId, function (err, videoInstance) {
|
||||
return callback(err, t, videoInstance)
|
||||
videoName = videoInstance.name
|
||||
|
||||
if (videoData.views) {
|
||||
videoInstance.set('views', videoData.views)
|
||||
}
|
||||
|
||||
if (videoData.likes) {
|
||||
videoInstance.set('likes', videoData.likes)
|
||||
}
|
||||
|
||||
if (videoData.dislikes) {
|
||||
videoInstance.set('dislikes', videoData.dislikes)
|
||||
}
|
||||
|
||||
return videoInstance.save(options)
|
||||
})
|
||||
},
|
||||
|
||||
function updateVideoIntoDB (t, videoInstance, callback) {
|
||||
const options = { transaction: t }
|
||||
|
||||
videoName = videoInstance.name
|
||||
|
||||
if (videoData.views) {
|
||||
videoInstance.set('views', videoData.views)
|
||||
}
|
||||
|
||||
if (videoData.likes) {
|
||||
videoInstance.set('likes', videoData.likes)
|
||||
}
|
||||
|
||||
if (videoData.dislikes) {
|
||||
videoInstance.set('dislikes', videoData.dislikes)
|
||||
}
|
||||
|
||||
videoInstance.save(options).asCallback(function (err) {
|
||||
return callback(err, t)
|
||||
})
|
||||
},
|
||||
|
||||
commitTransaction
|
||||
|
||||
], function (err: Error, t: Sequelize.Transaction) {
|
||||
if (err) {
|
||||
logger.debug('Cannot quick and dirty update the remote video.', { error: err })
|
||||
return rollbackTransaction(err, t, finalCallback)
|
||||
}
|
||||
|
||||
logger.info('Remote video %s quick and dirty updated', videoName)
|
||||
return finalCallback(null)
|
||||
})
|
||||
.then(() => logger.info('Remote video %s quick and dirty updated', videoName))
|
||||
.catch(err => logger.debug('Cannot quick and dirty update the remote video.', { error: err }))
|
||||
}
|
||||
|
||||
// Handle retries on fail
|
||||
function addRemoteVideoRetryWrapper (videoToCreateData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) {
|
||||
function addRemoteVideoRetryWrapper (videoToCreateData: any, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoToCreateData, fromPod ],
|
||||
errorMessage: 'Cannot insert the remote video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(addRemoteVideo, options, finalCallback)
|
||||
return retryTransactionWrapper(addRemoteVideo, options)
|
||||
}
|
||||
|
||||
function addRemoteVideo (videoToCreateData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) {
|
||||
function addRemoteVideo (videoToCreateData: any, fromPod: PodInstance) {
|
||||
logger.debug('Adding remote video "%s".', videoToCreateData.remoteId)
|
||||
|
||||
waterfall([
|
||||
return db.sequelize.transaction(t => {
|
||||
return db.Video.loadByHostAndRemoteId(fromPod.host, videoToCreateData.remoteId)
|
||||
.then(video => {
|
||||
if (video) throw new Error('RemoteId and host pair is not unique.')
|
||||
|
||||
startSerializableTransaction,
|
||||
|
||||
function assertRemoteIdAndHostUnique (t, callback) {
|
||||
db.Video.loadByHostAndRemoteId(fromPod.host, videoToCreateData.remoteId, function (err, video) {
|
||||
if (err) return callback(err)
|
||||
|
||||
if (video) return callback(new Error('RemoteId and host pair is not unique.'))
|
||||
|
||||
return callback(null, t)
|
||||
return undefined
|
||||
})
|
||||
},
|
||||
.then(() => {
|
||||
const name = videoToCreateData.author
|
||||
const podId = fromPod.id
|
||||
// This author is from another pod so we do not associate a user
|
||||
const userId = null
|
||||
|
||||
function findOrCreateAuthor (t, callback) {
|
||||
const name = videoToCreateData.author
|
||||
const podId = fromPod.id
|
||||
// This author is from another pod so we do not associate a user
|
||||
const userId = null
|
||||
|
||||
db.Author.findOrCreateAuthor(name, podId, userId, t, function (err, authorInstance) {
|
||||
return callback(err, t, authorInstance)
|
||||
return db.Author.findOrCreateAuthor(name, podId, userId, t)
|
||||
})
|
||||
},
|
||||
.then(author => {
|
||||
const tags = videoToCreateData.tags
|
||||
|
||||
function findOrCreateTags (t, author, callback) {
|
||||
const tags = videoToCreateData.tags
|
||||
|
||||
db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
|
||||
return callback(err, t, author, tagInstances)
|
||||
return db.Tag.findOrCreateTags(tags, t).then(tagInstances => ({ author, tagInstances }))
|
||||
})
|
||||
},
|
||||
|
||||
function createVideoObject (t, author, tagInstances, callback) {
|
||||
const videoData = {
|
||||
name: videoToCreateData.name,
|
||||
remoteId: videoToCreateData.remoteId,
|
||||
extname: videoToCreateData.extname,
|
||||
infoHash: videoToCreateData.infoHash,
|
||||
category: videoToCreateData.category,
|
||||
licence: videoToCreateData.licence,
|
||||
language: videoToCreateData.language,
|
||||
nsfw: videoToCreateData.nsfw,
|
||||
description: videoToCreateData.description,
|
||||
authorId: author.id,
|
||||
duration: videoToCreateData.duration,
|
||||
createdAt: videoToCreateData.createdAt,
|
||||
// FIXME: updatedAt does not seems to be considered by Sequelize
|
||||
updatedAt: videoToCreateData.updatedAt,
|
||||
views: videoToCreateData.views,
|
||||
likes: videoToCreateData.likes,
|
||||
dislikes: videoToCreateData.dislikes
|
||||
}
|
||||
|
||||
const video = db.Video.build(videoData)
|
||||
|
||||
return callback(null, t, tagInstances, video)
|
||||
},
|
||||
|
||||
function generateThumbnail (t, tagInstances, video, callback) {
|
||||
db.Video.generateThumbnailFromData(video, videoToCreateData.thumbnailData, function (err) {
|
||||
if (err) {
|
||||
logger.error('Cannot generate thumbnail from data.', { error: err })
|
||||
return callback(err)
|
||||
.then(({ author, tagInstances }) => {
|
||||
const videoData = {
|
||||
name: videoToCreateData.name,
|
||||
remoteId: videoToCreateData.remoteId,
|
||||
extname: videoToCreateData.extname,
|
||||
infoHash: videoToCreateData.infoHash,
|
||||
category: videoToCreateData.category,
|
||||
licence: videoToCreateData.licence,
|
||||
language: videoToCreateData.language,
|
||||
nsfw: videoToCreateData.nsfw,
|
||||
description: videoToCreateData.description,
|
||||
authorId: author.id,
|
||||
duration: videoToCreateData.duration,
|
||||
createdAt: videoToCreateData.createdAt,
|
||||
// FIXME: updatedAt does not seems to be considered by Sequelize
|
||||
updatedAt: videoToCreateData.updatedAt,
|
||||
views: videoToCreateData.views,
|
||||
likes: videoToCreateData.likes,
|
||||
dislikes: videoToCreateData.dislikes
|
||||
}
|
||||
|
||||
return callback(err, t, tagInstances, video)
|
||||
const video = db.Video.build(videoData)
|
||||
return { tagInstances, video }
|
||||
})
|
||||
},
|
||||
|
||||
function insertVideoIntoDB (t, tagInstances, video, callback) {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
video.save(options).asCallback(function (err, videoCreated) {
|
||||
return callback(err, t, tagInstances, videoCreated)
|
||||
.then(({ tagInstances, video }) => {
|
||||
return db.Video.generateThumbnailFromData(video, videoToCreateData.thumbnailData).then(() => ({ tagInstances, video }))
|
||||
})
|
||||
},
|
||||
.then(({ tagInstances, video }) => {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
function associateTagsToVideo (t, tagInstances, video, callback) {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
video.setTags(tagInstances, options).asCallback(function (err) {
|
||||
return callback(err, t)
|
||||
return video.save(options).then(videoCreated => ({ tagInstances, videoCreated }))
|
||||
})
|
||||
},
|
||||
.then(({ tagInstances, videoCreated }) => {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
commitTransaction
|
||||
|
||||
], function (err: Error, t: Sequelize.Transaction) {
|
||||
if (err) {
|
||||
// This is just a debug because we will retry the insert
|
||||
logger.debug('Cannot insert the remote video.', { error: err })
|
||||
return rollbackTransaction(err, t, finalCallback)
|
||||
}
|
||||
|
||||
logger.info('Remote video %s inserted.', videoToCreateData.name)
|
||||
return finalCallback(null)
|
||||
return videoCreated.setTags(tagInstances, options)
|
||||
})
|
||||
})
|
||||
.then(() => logger.info('Remote video %s inserted.', videoToCreateData.name))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot insert the remote video.', { error: err })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
// Handle retries on fail
|
||||
function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: any, fromPod: PodInstance, finalCallback: (err: Error) => void) {
|
||||
function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: any, fromPod: PodInstance) {
|
||||
const options = {
|
||||
arguments: [ videoAttributesToUpdate, fromPod ],
|
||||
errorMessage: 'Cannot update the remote video with many retries'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(updateRemoteVideo, options, finalCallback)
|
||||
return retryTransactionWrapper(updateRemoteVideo, options)
|
||||
}
|
||||
|
||||
function updateRemoteVideo (videoAttributesToUpdate: any, fromPod: PodInstance, finalCallback: (err: Error) => void) {
|
||||
function updateRemoteVideo (videoAttributesToUpdate: any, fromPod: PodInstance) {
|
||||
logger.debug('Updating remote video "%s".', videoAttributesToUpdate.remoteId)
|
||||
|
||||
waterfall([
|
||||
return db.sequelize.transaction(t => {
|
||||
return fetchRemoteVideo(fromPod.host, videoAttributesToUpdate.remoteId)
|
||||
.then(videoInstance => {
|
||||
const tags = videoAttributesToUpdate.tags
|
||||
|
||||
startSerializableTransaction,
|
||||
|
||||
function findVideo (t, callback) {
|
||||
fetchRemoteVideo(fromPod.host, videoAttributesToUpdate.remoteId, function (err, videoInstance) {
|
||||
return callback(err, t, videoInstance)
|
||||
return db.Tag.findOrCreateTags(tags, t).then(tagInstances => ({ videoInstance, tagInstances }))
|
||||
})
|
||||
},
|
||||
.then(({ videoInstance, tagInstances }) => {
|
||||
const options = { transaction: t }
|
||||
|
||||
function findOrCreateTags (t, videoInstance, callback) {
|
||||
const tags = videoAttributesToUpdate.tags
|
||||
videoInstance.set('name', videoAttributesToUpdate.name)
|
||||
videoInstance.set('category', videoAttributesToUpdate.category)
|
||||
videoInstance.set('licence', videoAttributesToUpdate.licence)
|
||||
videoInstance.set('language', videoAttributesToUpdate.language)
|
||||
videoInstance.set('nsfw', videoAttributesToUpdate.nsfw)
|
||||
videoInstance.set('description', videoAttributesToUpdate.description)
|
||||
videoInstance.set('infoHash', videoAttributesToUpdate.infoHash)
|
||||
videoInstance.set('duration', videoAttributesToUpdate.duration)
|
||||
videoInstance.set('createdAt', videoAttributesToUpdate.createdAt)
|
||||
videoInstance.set('updatedAt', videoAttributesToUpdate.updatedAt)
|
||||
videoInstance.set('extname', videoAttributesToUpdate.extname)
|
||||
videoInstance.set('views', videoAttributesToUpdate.views)
|
||||
videoInstance.set('likes', videoAttributesToUpdate.likes)
|
||||
videoInstance.set('dislikes', videoAttributesToUpdate.dislikes)
|
||||
|
||||
db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
|
||||
return callback(err, t, videoInstance, tagInstances)
|
||||
return videoInstance.save(options).then(() => ({ videoInstance, tagInstances }))
|
||||
})
|
||||
},
|
||||
.then(({ videoInstance, tagInstances }) => {
|
||||
const options = { transaction: t }
|
||||
|
||||
function updateVideoIntoDB (t, videoInstance, tagInstances, callback) {
|
||||
const options = { transaction: t }
|
||||
|
||||
videoInstance.set('name', videoAttributesToUpdate.name)
|
||||
videoInstance.set('category', videoAttributesToUpdate.category)
|
||||
videoInstance.set('licence', videoAttributesToUpdate.licence)
|
||||
videoInstance.set('language', videoAttributesToUpdate.language)
|
||||
videoInstance.set('nsfw', videoAttributesToUpdate.nsfw)
|
||||
videoInstance.set('description', videoAttributesToUpdate.description)
|
||||
videoInstance.set('infoHash', videoAttributesToUpdate.infoHash)
|
||||
videoInstance.set('duration', videoAttributesToUpdate.duration)
|
||||
videoInstance.set('createdAt', videoAttributesToUpdate.createdAt)
|
||||
videoInstance.set('updatedAt', videoAttributesToUpdate.updatedAt)
|
||||
videoInstance.set('extname', videoAttributesToUpdate.extname)
|
||||
videoInstance.set('views', videoAttributesToUpdate.views)
|
||||
videoInstance.set('likes', videoAttributesToUpdate.likes)
|
||||
videoInstance.set('dislikes', videoAttributesToUpdate.dislikes)
|
||||
|
||||
videoInstance.save(options).asCallback(function (err) {
|
||||
return callback(err, t, videoInstance, tagInstances)
|
||||
return videoInstance.setTags(tagInstances, options)
|
||||
})
|
||||
},
|
||||
|
||||
function associateTagsToVideo (t, videoInstance, tagInstances, callback) {
|
||||
const options = { transaction: t }
|
||||
|
||||
videoInstance.setTags(tagInstances, options).asCallback(function (err) {
|
||||
return callback(err, t)
|
||||
})
|
||||
},
|
||||
|
||||
commitTransaction
|
||||
|
||||
], function (err: Error, t: Sequelize.Transaction) {
|
||||
if (err) {
|
||||
// This is just a debug because we will retry the insert
|
||||
logger.debug('Cannot update the remote video.', { error: err })
|
||||
return rollbackTransaction(err, t, finalCallback)
|
||||
}
|
||||
|
||||
logger.info('Remote video %s updated', videoAttributesToUpdate.name)
|
||||
return finalCallback(null)
|
||||
})
|
||||
.then(() => logger.info('Remote video %s updated', videoAttributesToUpdate.name))
|
||||
.catch(err => {
|
||||
// This is just a debug because we will retry the insert
|
||||
logger.debug('Cannot update the remote video.', { error: err })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
function removeRemoteVideo (videoToRemoveData: any, fromPod: PodInstance, callback: (err: Error) => void) {
|
||||
function removeRemoteVideo (videoToRemoveData: any, fromPod: PodInstance) {
|
||||
// We need the instance because we have to remove some other stuffs (thumbnail etc)
|
||||
fetchRemoteVideo(fromPod.host, videoToRemoveData.remoteId, function (err, video) {
|
||||
// Do not return the error, continue the process
|
||||
if (err) return callback(null)
|
||||
|
||||
logger.debug('Removing remote video %s.', video.remoteId)
|
||||
video.destroy().asCallback(function (err) {
|
||||
// Do not return the error, continue the process
|
||||
if (err) {
|
||||
logger.error('Cannot remove remote video with id %s.', videoToRemoveData.remoteId, { error: err })
|
||||
}
|
||||
|
||||
return callback(null)
|
||||
return fetchRemoteVideo(fromPod.host, videoToRemoveData.remoteId)
|
||||
.then(video => {
|
||||
logger.debug('Removing remote video %s.', video.remoteId)
|
||||
return video.destroy()
|
||||
})
|
||||
.catch(err => {
|
||||
logger.debug('Could not fetch remote video.', { host: fromPod.host, remoteId: videoToRemoveData.remoteId, error: err })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function reportAbuseRemoteVideo (reportData: any, fromPod: PodInstance, callback: (err: Error) => void) {
|
||||
fetchOwnedVideo(reportData.videoRemoteId, function (err, video) {
|
||||
if (err || !video) {
|
||||
if (!err) err = new Error('video not found')
|
||||
function reportAbuseRemoteVideo (reportData: any, fromPod: PodInstance) {
|
||||
return fetchOwnedVideo(reportData.videoRemoteId)
|
||||
.then(video => {
|
||||
logger.debug('Reporting remote abuse for video %s.', video.id)
|
||||
|
||||
logger.error('Cannot load video from id.', { error: err, id: reportData.videoRemoteId })
|
||||
// Do not return the error, continue the process
|
||||
return callback(null)
|
||||
}
|
||||
|
||||
logger.debug('Reporting remote abuse for video %s.', video.id)
|
||||
|
||||
const videoAbuseData = {
|
||||
reporterUsername: reportData.reporterUsername,
|
||||
reason: reportData.reportReason,
|
||||
reporterPodId: fromPod.id,
|
||||
videoId: video.id
|
||||
}
|
||||
|
||||
db.VideoAbuse.create(videoAbuseData).asCallback(function (err) {
|
||||
if (err) {
|
||||
logger.error('Cannot create remote abuse video.', { error: err })
|
||||
const videoAbuseData = {
|
||||
reporterUsername: reportData.reporterUsername,
|
||||
reason: reportData.reportReason,
|
||||
reporterPodId: fromPod.id,
|
||||
videoId: video.id
|
||||
}
|
||||
|
||||
return callback(null)
|
||||
return db.VideoAbuse.create(videoAbuseData)
|
||||
})
|
||||
})
|
||||
.catch(err => logger.error('Cannot create remote abuse video.', { error: err }))
|
||||
}
|
||||
|
||||
function fetchOwnedVideo (id: string, callback: (err: Error, video?: VideoInstance) => void) {
|
||||
db.Video.load(id, function (err, video) {
|
||||
if (err || !video) {
|
||||
if (!err) err = new Error('video not found')
|
||||
function fetchOwnedVideo (id: string) {
|
||||
return db.Video.load(id)
|
||||
.then(video => {
|
||||
if (!video) throw new Error('Video not found')
|
||||
|
||||
return video
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Cannot load owned video from id.', { error: err, id })
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
return callback(null, video)
|
||||
})
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
function fetchRemoteVideo (podHost: string, remoteId: string, callback: (err: Error, video?: VideoInstance) => void) {
|
||||
db.Video.loadByHostAndRemoteId(podHost, remoteId, function (err, video) {
|
||||
if (err || !video) {
|
||||
if (!err) err = new Error('video not found')
|
||||
function fetchRemoteVideo (podHost: string, remoteId: string) {
|
||||
return db.Video.loadByHostAndRemoteId(podHost, remoteId)
|
||||
.then(video => {
|
||||
if (!video) throw new Error('Video not found')
|
||||
|
||||
return video
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Cannot load video from host and remote id.', { error: err, podHost, remoteId })
|
||||
return callback(err)
|
||||
}
|
||||
|
||||
return callback(null, video)
|
||||
})
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as express from 'express'
|
||||
import { parallel } from 'async'
|
||||
import * as Promise from 'bluebird'
|
||||
|
||||
import {
|
||||
AbstractRequestScheduler,
|
||||
|
@ -27,33 +27,27 @@ export {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
function getRequestSchedulersStats (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
parallel({
|
||||
Promise.props({
|
||||
requestScheduler: buildRequestSchedulerStats(getRequestScheduler()),
|
||||
requestVideoQaduScheduler: buildRequestSchedulerStats(getRequestVideoQaduScheduler()),
|
||||
requestVideoEventScheduler: buildRequestSchedulerStats(getRequestVideoEventScheduler())
|
||||
}, function (err, result) {
|
||||
if (err) return next(err)
|
||||
|
||||
return res.json(result)
|
||||
})
|
||||
.then(result => res.json(result))
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function buildRequestSchedulerStats (requestScheduler: AbstractRequestScheduler) {
|
||||
return function (callback) {
|
||||
requestScheduler.remainingRequestsCount(function (err, count) {
|
||||
if (err) return callback(err)
|
||||
function buildRequestSchedulerStats (requestScheduler: AbstractRequestScheduler<any>) {
|
||||
return requestScheduler.remainingRequestsCount().then(count => {
|
||||
const result: RequestSchedulerStatsAttributes = {
|
||||
totalRequests: count,
|
||||
requestsLimitPods: requestScheduler.limitPods,
|
||||
requestsLimitPerPod: requestScheduler.limitPerPod,
|
||||
remainingMilliSeconds: requestScheduler.remainingMilliSeconds(),
|
||||
milliSecondsInterval: requestScheduler.requestInterval
|
||||
}
|
||||
|
||||
const result: RequestSchedulerStatsAttributes = {
|
||||
totalRequests: count,
|
||||
requestsLimitPods: requestScheduler.limitPods,
|
||||
requestsLimitPerPod: requestScheduler.limitPerPod,
|
||||
remainingMilliSeconds: requestScheduler.remainingMilliSeconds(),
|
||||
milliSecondsInterval: requestScheduler.requestInterval
|
||||
}
|
||||
|
||||
return callback(null, result)
|
||||
})
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import * as express from 'express'
|
||||
import { waterfall } from 'async'
|
||||
|
||||
import { database as db } from '../../initializers/database'
|
||||
import { CONFIG, USER_ROLES } from '../../initializers'
|
||||
import { USER_ROLES } from '../../initializers'
|
||||
import { logger, getFormatedObjects } from '../../helpers'
|
||||
import {
|
||||
authenticate,
|
||||
|
@ -87,78 +86,61 @@ function createUser (req: express.Request, res: express.Response, next: express.
|
|||
role: USER_ROLES.USER
|
||||
})
|
||||
|
||||
user.save().asCallback(function (err) {
|
||||
if (err) return next(err)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
user.save()
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function getUserInformation (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.User.loadByUsername(res.locals.oauth.token.user.username, function (err, user) {
|
||||
if (err) return next(err)
|
||||
|
||||
return res.json(user.toFormatedJSON())
|
||||
})
|
||||
db.User.loadByUsername(res.locals.oauth.token.user.username)
|
||||
.then(user => res.json(user.toFormatedJSON()))
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const videoId = '' + req.params.videoId
|
||||
const userId = +res.locals.oauth.token.User.id
|
||||
|
||||
db.UserVideoRate.load(userId, videoId, null, function (err, ratingObj) {
|
||||
if (err) return next(err)
|
||||
|
||||
const rating = ratingObj ? ratingObj.type : 'none'
|
||||
|
||||
const json: FormatedUserVideoRate = {
|
||||
videoId,
|
||||
rating
|
||||
}
|
||||
res.json(json)
|
||||
})
|
||||
db.UserVideoRate.load(userId, videoId, null)
|
||||
.then(ratingObj => {
|
||||
const rating = ratingObj ? ratingObj.type : 'none'
|
||||
const json: FormatedUserVideoRate = {
|
||||
videoId,
|
||||
rating
|
||||
}
|
||||
res.json(json)
|
||||
})
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.User.listForApi(req.query.start, req.query.count, req.query.sort, function (err, usersList, usersTotal) {
|
||||
if (err) return next(err)
|
||||
|
||||
res.json(getFormatedObjects(usersList, usersTotal))
|
||||
})
|
||||
db.User.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
.then(resultList => {
|
||||
res.json(getFormatedObjects(resultList.data, resultList.total))
|
||||
})
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
waterfall([
|
||||
function loadUser (callback) {
|
||||
db.User.loadById(req.params.id, callback)
|
||||
},
|
||||
|
||||
function deleteUser (user, callback) {
|
||||
user.destroy().asCallback(callback)
|
||||
}
|
||||
], function andFinally (err) {
|
||||
if (err) {
|
||||
db.User.loadById(req.params.id)
|
||||
.then(user => user.destroy())
|
||||
.then(() => res.sendStatus(204))
|
||||
.catch(err => {
|
||||
logger.error('Errors when removed the user.', { error: err })
|
||||
return next(err)
|
||||
}
|
||||
|
||||
return res.sendStatus(204)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.User.loadByUsername(res.locals.oauth.token.user.username, function (err, user) {
|
||||
if (err) return next(err)
|
||||
db.User.loadByUsername(res.locals.oauth.token.user.username)
|
||||
.then(user => {
|
||||
if (req.body.password) user.password = req.body.password
|
||||
if (req.body.displayNSFW !== undefined) user.displayNSFW = req.body.displayNSFW
|
||||
|
||||
if (req.body.password) user.password = req.body.password
|
||||
if (req.body.displayNSFW !== undefined) user.displayNSFW = req.body.displayNSFW
|
||||
|
||||
user.save().asCallback(function (err) {
|
||||
if (err) return next(err)
|
||||
|
||||
return res.sendStatus(204)
|
||||
return user.save()
|
||||
})
|
||||
})
|
||||
.then(() => res.sendStatus(204))
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function success (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
import * as express from 'express'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { waterfall } from 'async'
|
||||
|
||||
import { database as db } from '../../../initializers/database'
|
||||
import * as friends from '../../../lib/friends'
|
||||
import {
|
||||
logger,
|
||||
getFormatedObjects,
|
||||
retryTransactionWrapper,
|
||||
startSerializableTransaction,
|
||||
commitTransaction,
|
||||
rollbackTransaction
|
||||
retryTransactionWrapper
|
||||
} from '../../../helpers'
|
||||
import {
|
||||
authenticate,
|
||||
|
@ -21,6 +16,7 @@ import {
|
|||
setVideoAbusesSort,
|
||||
setPagination
|
||||
} from '../../../middlewares'
|
||||
import { VideoInstance } from '../../../models'
|
||||
|
||||
const abuseVideoRouter = express.Router()
|
||||
|
||||
|
@ -48,11 +44,9 @@ export {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
function listVideoAbuses (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort, function (err, abusesList, abusesTotal) {
|
||||
if (err) return next(err)
|
||||
|
||||
res.json(getFormatedObjects(abusesList, abusesTotal))
|
||||
})
|
||||
db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
.then(result => res.json(getFormatedObjects(result.data, result.total)))
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
|
@ -61,14 +55,12 @@ function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Respon
|
|||
errorMessage: 'Cannot report abuse to the video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(reportVideoAbuse, options, function (err) {
|
||||
if (err) return next(err)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
retryTransactionWrapper(reportVideoAbuse, options)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function reportVideoAbuse (req: express.Request, res: express.Response, finalCallback: (err: Error) => void) {
|
||||
function reportVideoAbuse (req: express.Request, res: express.Response) {
|
||||
const videoInstance = res.locals.video
|
||||
const reporterUsername = res.locals.oauth.token.User.username
|
||||
|
||||
|
@ -79,40 +71,26 @@ function reportVideoAbuse (req: express.Request, res: express.Response, finalCal
|
|||
reporterPodId: null // This is our pod that reported this abuse
|
||||
}
|
||||
|
||||
waterfall([
|
||||
return db.sequelize.transaction(t => {
|
||||
return db.VideoAbuse.create(abuse, { transaction: t })
|
||||
.then(abuse => {
|
||||
// We send the information to the destination pod
|
||||
if (videoInstance.isOwned() === false) {
|
||||
const reportData = {
|
||||
reporterUsername,
|
||||
reportReason: abuse.reason,
|
||||
videoRemoteId: videoInstance.remoteId
|
||||
}
|
||||
|
||||
startSerializableTransaction,
|
||||
|
||||
function createAbuse (t, callback) {
|
||||
db.VideoAbuse.create(abuse).asCallback(function (err, abuse) {
|
||||
return callback(err, t, abuse)
|
||||
})
|
||||
},
|
||||
|
||||
function sendToFriendsIfNeeded (t, abuse, callback) {
|
||||
// We send the information to the destination pod
|
||||
if (videoInstance.isOwned() === false) {
|
||||
const reportData = {
|
||||
reporterUsername,
|
||||
reportReason: abuse.reason,
|
||||
videoRemoteId: videoInstance.remoteId
|
||||
return friends.reportAbuseVideoToFriend(reportData, videoInstance, t).then(() => videoInstance)
|
||||
}
|
||||
|
||||
friends.reportAbuseVideoToFriend(reportData, videoInstance)
|
||||
}
|
||||
|
||||
return callback(null, t)
|
||||
},
|
||||
|
||||
commitTransaction
|
||||
|
||||
], function andFinally (err: Error, t: Sequelize.Transaction) {
|
||||
if (err) {
|
||||
logger.debug('Cannot update the video.', { error: err })
|
||||
return rollbackTransaction(err, t, finalCallback)
|
||||
}
|
||||
|
||||
logger.info('Abuse report for video %s created.', videoInstance.name)
|
||||
return finalCallback(null)
|
||||
return videoInstance
|
||||
})
|
||||
})
|
||||
.then((videoInstance: VideoInstance) => logger.info('Abuse report for video %s created.', videoInstance.name))
|
||||
.catch(err => {
|
||||
logger.debug('Cannot update the video.', { error: err })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
|
|
@ -32,12 +32,10 @@ function addVideoToBlacklist (req: express.Request, res: express.Response, next:
|
|||
videoId: videoInstance.id
|
||||
}
|
||||
|
||||
db.BlacklistedVideo.create(toCreate).asCallback(function (err) {
|
||||
if (err) {
|
||||
db.BlacklistedVideo.create(toCreate)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => {
|
||||
logger.error('Errors when blacklisting video ', { error: err })
|
||||
return next(err)
|
||||
}
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import * as express from 'express'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import * as fs from 'fs'
|
||||
import * as Promise from 'bluebird'
|
||||
import * as multer from 'multer'
|
||||
import * as path from 'path'
|
||||
import { waterfall } from 'async'
|
||||
|
||||
import { database as db } from '../../../initializers/database'
|
||||
import {
|
||||
|
@ -35,13 +33,12 @@ import {
|
|||
} from '../../../middlewares'
|
||||
import {
|
||||
logger,
|
||||
commitTransaction,
|
||||
retryTransactionWrapper,
|
||||
rollbackTransaction,
|
||||
startSerializableTransaction,
|
||||
generateRandomString,
|
||||
getFormatedObjects
|
||||
getFormatedObjects,
|
||||
renamePromise
|
||||
} from '../../../helpers'
|
||||
import { TagInstance } from '../../../models'
|
||||
|
||||
import { abuseVideoRouter } from './abuse'
|
||||
import { blacklistRouter } from './blacklist'
|
||||
|
@ -60,10 +57,15 @@ const storage = multer.diskStorage({
|
|||
if (file.mimetype === 'video/webm') extension = 'webm'
|
||||
else if (file.mimetype === 'video/mp4') extension = 'mp4'
|
||||
else if (file.mimetype === 'video/ogg') extension = 'ogv'
|
||||
generateRandomString(16, function (err, randomString) {
|
||||
const fieldname = err ? undefined : randomString
|
||||
cb(null, fieldname + '.' + extension)
|
||||
})
|
||||
generateRandomString(16)
|
||||
.then(randomString => {
|
||||
const filename = randomString
|
||||
cb(null, filename + '.' + extension)
|
||||
})
|
||||
.catch(err => {
|
||||
logger.error('Cannot generate random string for file name.', { error: err })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -144,125 +146,97 @@ function addVideoRetryWrapper (req: express.Request, res: express.Response, next
|
|||
errorMessage: 'Cannot insert the video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(addVideo, options, function (err) {
|
||||
if (err) return next(err)
|
||||
|
||||
// TODO : include Location of the new video -> 201
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
retryTransactionWrapper(addVideo, options)
|
||||
.then(() => {
|
||||
// TODO : include Location of the new video -> 201
|
||||
res.type('json').status(204).end()
|
||||
})
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function addVideo (req: express.Request, res: express.Response, videoFile: Express.Multer.File, finalCallback: (err: Error) => void) {
|
||||
function addVideo (req: express.Request, res: express.Response, videoFile: Express.Multer.File) {
|
||||
const videoInfos = req.body
|
||||
|
||||
waterfall([
|
||||
return db.sequelize.transaction(t => {
|
||||
const user = res.locals.oauth.token.User
|
||||
|
||||
startSerializableTransaction,
|
||||
const name = user.username
|
||||
// null because it is OUR pod
|
||||
const podId = null
|
||||
const userId = user.id
|
||||
|
||||
function findOrCreateAuthor (t, callback) {
|
||||
const user = res.locals.oauth.token.User
|
||||
return db.Author.findOrCreateAuthor(name, podId, userId, t)
|
||||
.then(author => {
|
||||
const tags = videoInfos.tags
|
||||
if (!tags) return { author, tagInstances: undefined }
|
||||
|
||||
const name = user.username
|
||||
// null because it is OUR pod
|
||||
const podId = null
|
||||
const userId = user.id
|
||||
|
||||
db.Author.findOrCreateAuthor(name, podId, userId, t, function (err, authorInstance) {
|
||||
return callback(err, t, authorInstance)
|
||||
return db.Tag.findOrCreateTags(tags, t).then(tagInstances => ({ author, tagInstances }))
|
||||
})
|
||||
},
|
||||
.then(({ author, tagInstances }) => {
|
||||
const videoData = {
|
||||
name: videoInfos.name,
|
||||
remoteId: null,
|
||||
extname: path.extname(videoFile.filename),
|
||||
category: videoInfos.category,
|
||||
licence: videoInfos.licence,
|
||||
language: videoInfos.language,
|
||||
nsfw: videoInfos.nsfw,
|
||||
description: videoInfos.description,
|
||||
duration: videoFile['duration'], // duration was added by a previous middleware
|
||||
authorId: author.id
|
||||
}
|
||||
|
||||
function findOrCreateTags (t, author, callback) {
|
||||
const tags = videoInfos.tags
|
||||
|
||||
db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
|
||||
return callback(err, t, author, tagInstances)
|
||||
const video = db.Video.build(videoData)
|
||||
return { author, tagInstances, video }
|
||||
})
|
||||
},
|
||||
.then(({ author, tagInstances, video }) => {
|
||||
const videoDir = CONFIG.STORAGE.VIDEOS_DIR
|
||||
const source = path.join(videoDir, videoFile.filename)
|
||||
const destination = path.join(videoDir, video.getVideoFilename())
|
||||
|
||||
function createVideoObject (t, author, tagInstances, callback) {
|
||||
const videoData = {
|
||||
name: videoInfos.name,
|
||||
remoteId: null,
|
||||
extname: path.extname(videoFile.filename),
|
||||
category: videoInfos.category,
|
||||
licence: videoInfos.licence,
|
||||
language: videoInfos.language,
|
||||
nsfw: videoInfos.nsfw,
|
||||
description: videoInfos.description,
|
||||
duration: videoFile['duration'], // duration was added by a previous middleware
|
||||
authorId: author.id
|
||||
}
|
||||
|
||||
const video = db.Video.build(videoData)
|
||||
|
||||
return callback(null, t, author, tagInstances, video)
|
||||
},
|
||||
|
||||
// Set the videoname the same as the id
|
||||
function renameVideoFile (t, author, tagInstances, video, callback) {
|
||||
const videoDir = CONFIG.STORAGE.VIDEOS_DIR
|
||||
const source = path.join(videoDir, videoFile.filename)
|
||||
const destination = path.join(videoDir, video.getVideoFilename())
|
||||
|
||||
fs.rename(source, destination, function (err) {
|
||||
if (err) return callback(err)
|
||||
|
||||
// This is important in case if there is another attempt
|
||||
videoFile.filename = video.getVideoFilename()
|
||||
return callback(null, t, author, tagInstances, video)
|
||||
return renamePromise(source, destination)
|
||||
.then(() => {
|
||||
// This is important in case if there is another attempt in the retry process
|
||||
videoFile.filename = video.getVideoFilename()
|
||||
return { author, tagInstances, video }
|
||||
})
|
||||
})
|
||||
},
|
||||
.then(({ author, tagInstances, video }) => {
|
||||
const options = { transaction: t }
|
||||
|
||||
function insertVideoIntoDB (t, author, tagInstances, video, callback) {
|
||||
const options = { transaction: t }
|
||||
return video.save(options)
|
||||
.then(videoCreated => {
|
||||
// Do not forget to add Author informations to the created video
|
||||
videoCreated.Author = author
|
||||
|
||||
// Add tags association
|
||||
video.save(options).asCallback(function (err, videoCreated) {
|
||||
if (err) return callback(err)
|
||||
|
||||
// Do not forget to add Author informations to the created video
|
||||
videoCreated.Author = author
|
||||
|
||||
return callback(err, t, tagInstances, videoCreated)
|
||||
return { tagInstances, video: videoCreated }
|
||||
})
|
||||
})
|
||||
},
|
||||
.then(({ tagInstances, video }) => {
|
||||
if (!tagInstances) return video
|
||||
|
||||
function associateTagsToVideo (t, tagInstances, video, callback) {
|
||||
const options = { transaction: t }
|
||||
|
||||
video.setTags(tagInstances, options).asCallback(function (err) {
|
||||
video.Tags = tagInstances
|
||||
|
||||
return callback(err, t, video)
|
||||
const options = { transaction: t }
|
||||
return video.setTags(tagInstances, options)
|
||||
.then(() => {
|
||||
video.Tags = tagInstances
|
||||
return video
|
||||
})
|
||||
})
|
||||
},
|
||||
.then(video => {
|
||||
// Let transcoding job send the video to friends because the videofile extension might change
|
||||
if (CONFIG.TRANSCODING.ENABLED === true) return undefined
|
||||
|
||||
function sendToFriends (t, video, callback) {
|
||||
// Let transcoding job send the video to friends because the videofile extension might change
|
||||
if (CONFIG.TRANSCODING.ENABLED === true) return callback(null, t)
|
||||
|
||||
video.toAddRemoteJSON(function (err, remoteVideo) {
|
||||
if (err) return callback(err)
|
||||
|
||||
// Now we'll add the video's meta data to our friends
|
||||
addVideoToFriends(remoteVideo, t, function (err) {
|
||||
return callback(err, t)
|
||||
})
|
||||
return video.toAddRemoteJSON()
|
||||
.then(remoteVideo => {
|
||||
// Now we'll add the video's meta data to our friends
|
||||
return addVideoToFriends(remoteVideo, t)
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
commitTransaction
|
||||
|
||||
], function andFinally (err: Error, t: Sequelize.Transaction) {
|
||||
if (err) {
|
||||
// This is just a debug because we will retry the insert
|
||||
logger.debug('Cannot insert the video.', { error: err })
|
||||
return rollbackTransaction(err, t, finalCallback)
|
||||
}
|
||||
|
||||
logger.info('Video with name %s created.', videoInfos.name)
|
||||
return finalCallback(null)
|
||||
})
|
||||
.then(() => logger.info('Video with name %s created.', videoInfos.name))
|
||||
.catch((err: Error) => {
|
||||
logger.debug('Cannot insert the video.', { error: err.stack })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -272,92 +246,75 @@ function updateVideoRetryWrapper (req: express.Request, res: express.Response, n
|
|||
errorMessage: 'Cannot update the video with many retries.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(updateVideo, options, function (err) {
|
||||
if (err) return next(err)
|
||||
|
||||
// TODO : include Location of the new video -> 201
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
retryTransactionWrapper(updateVideo, options)
|
||||
.then(() => {
|
||||
// TODO : include Location of the new video -> 201
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function updateVideo (req: express.Request, res: express.Response, finalCallback: (err: Error) => void) {
|
||||
function updateVideo (req: express.Request, res: express.Response) {
|
||||
const videoInstance = res.locals.video
|
||||
const videoFieldsSave = videoInstance.toJSON()
|
||||
const videoInfosToUpdate = req.body
|
||||
|
||||
waterfall([
|
||||
|
||||
startSerializableTransaction,
|
||||
|
||||
function findOrCreateTags (t, callback) {
|
||||
if (videoInfosToUpdate.tags) {
|
||||
db.Tag.findOrCreateTags(videoInfosToUpdate.tags, t, function (err, tagInstances) {
|
||||
return callback(err, t, tagInstances)
|
||||
})
|
||||
} else {
|
||||
return callback(null, t, null)
|
||||
}
|
||||
},
|
||||
|
||||
function updateVideoIntoDB (t, tagInstances, callback) {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
if (videoInfosToUpdate.name !== undefined) videoInstance.set('name', videoInfosToUpdate.name)
|
||||
if (videoInfosToUpdate.category !== undefined) videoInstance.set('category', videoInfosToUpdate.category)
|
||||
if (videoInfosToUpdate.licence !== undefined) videoInstance.set('licence', videoInfosToUpdate.licence)
|
||||
if (videoInfosToUpdate.language !== undefined) videoInstance.set('language', videoInfosToUpdate.language)
|
||||
if (videoInfosToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfosToUpdate.nsfw)
|
||||
if (videoInfosToUpdate.description !== undefined) videoInstance.set('description', videoInfosToUpdate.description)
|
||||
|
||||
videoInstance.save(options).asCallback(function (err) {
|
||||
return callback(err, t, tagInstances)
|
||||
})
|
||||
},
|
||||
|
||||
function associateTagsToVideo (t, tagInstances, callback) {
|
||||
if (tagInstances) {
|
||||
const options = { transaction: t }
|
||||
|
||||
videoInstance.setTags(tagInstances, options).asCallback(function (err) {
|
||||
videoInstance.Tags = tagInstances
|
||||
|
||||
return callback(err, t)
|
||||
})
|
||||
} else {
|
||||
return callback(null, t)
|
||||
}
|
||||
},
|
||||
|
||||
function sendToFriends (t, callback) {
|
||||
const json = videoInstance.toUpdateRemoteJSON()
|
||||
|
||||
// Now we'll update the video's meta data to our friends
|
||||
updateVideoToFriends(json, t, function (err) {
|
||||
return callback(err, t)
|
||||
})
|
||||
},
|
||||
|
||||
commitTransaction
|
||||
|
||||
], function andFinally (err: Error, t: Sequelize.Transaction) {
|
||||
if (err) {
|
||||
logger.debug('Cannot update the video.', { error: err })
|
||||
|
||||
// Force fields we want to update
|
||||
// If the transaction is retried, sequelize will think the object has not changed
|
||||
// So it will skip the SQL request, even if the last one was ROLLBACKed!
|
||||
Object.keys(videoFieldsSave).forEach(function (key) {
|
||||
const value = videoFieldsSave[key]
|
||||
videoInstance.set(key, value)
|
||||
})
|
||||
|
||||
return rollbackTransaction(err, t, finalCallback)
|
||||
return db.sequelize.transaction(t => {
|
||||
let tagsPromise: Promise<TagInstance[]>
|
||||
if (!videoInfosToUpdate.tags) {
|
||||
tagsPromise = Promise.resolve(null)
|
||||
} else {
|
||||
tagsPromise = db.Tag.findOrCreateTags(videoInfosToUpdate.tags, t)
|
||||
}
|
||||
|
||||
return tagsPromise
|
||||
.then(tagInstances => {
|
||||
const options = {
|
||||
transaction: t
|
||||
}
|
||||
|
||||
if (videoInfosToUpdate.name !== undefined) videoInstance.set('name', videoInfosToUpdate.name)
|
||||
if (videoInfosToUpdate.category !== undefined) videoInstance.set('category', videoInfosToUpdate.category)
|
||||
if (videoInfosToUpdate.licence !== undefined) videoInstance.set('licence', videoInfosToUpdate.licence)
|
||||
if (videoInfosToUpdate.language !== undefined) videoInstance.set('language', videoInfosToUpdate.language)
|
||||
if (videoInfosToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfosToUpdate.nsfw)
|
||||
if (videoInfosToUpdate.description !== undefined) videoInstance.set('description', videoInfosToUpdate.description)
|
||||
|
||||
return videoInstance.save(options).then(() => tagInstances)
|
||||
})
|
||||
.then(tagInstances => {
|
||||
if (!tagInstances) return
|
||||
|
||||
const options = { transaction: t }
|
||||
return videoInstance.setTags(tagInstances, options)
|
||||
.then(() => {
|
||||
videoInstance.Tags = tagInstances
|
||||
|
||||
return
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
const json = videoInstance.toUpdateRemoteJSON()
|
||||
|
||||
// Now we'll update the video's meta data to our friends
|
||||
return updateVideoToFriends(json, t)
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('Video with name %s updated.', videoInstance.name)
|
||||
return finalCallback(null)
|
||||
})
|
||||
.catch(err => {
|
||||
logger.debug('Cannot update the video.', { error: err })
|
||||
|
||||
// Force fields we want to update
|
||||
// If the transaction is retried, sequelize will think the object has not changed
|
||||
// So it will skip the SQL request, even if the last one was ROLLBACKed!
|
||||
Object.keys(videoFieldsSave).forEach(function (key) {
|
||||
const value = videoFieldsSave[key]
|
||||
videoInstance.set(key, value)
|
||||
})
|
||||
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -366,20 +323,17 @@ function getVideo (req: express.Request, res: express.Response, next: express.Ne
|
|||
|
||||
if (videoInstance.isOwned()) {
|
||||
// The increment is done directly in the database, not using the instance value
|
||||
videoInstance.increment('views').asCallback(function (err) {
|
||||
if (err) {
|
||||
logger.error('Cannot add view to video %d.', videoInstance.id)
|
||||
return
|
||||
}
|
||||
|
||||
// FIXME: make a real view system
|
||||
// For example, only add a view when a user watch a video during 30s etc
|
||||
const qaduParams = {
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.VIEWS
|
||||
}
|
||||
quickAndDirtyUpdateVideoToFriends(qaduParams)
|
||||
})
|
||||
videoInstance.increment('views')
|
||||
.then(() => {
|
||||
// FIXME: make a real view system
|
||||
// For example, only add a view when a user watch a video during 30s etc
|
||||
const qaduParams = {
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.VIEWS
|
||||
}
|
||||
return quickAndDirtyUpdateVideoToFriends(qaduParams)
|
||||
})
|
||||
.catch(err => logger.error('Cannot add view to video %d.', videoInstance.id, { error: err }))
|
||||
} else {
|
||||
// Just send the event to our friends
|
||||
const eventParams = {
|
||||
|
@ -394,33 +348,24 @@ function getVideo (req: express.Request, res: express.Response, next: express.Ne
|
|||
}
|
||||
|
||||
function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
db.Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) {
|
||||
if (err) return next(err)
|
||||
|
||||
res.json(getFormatedObjects(videosList, videosTotal))
|
||||
})
|
||||
db.Video.listForApi(req.query.start, req.query.count, req.query.sort)
|
||||
.then(result => res.json(getFormatedObjects(result.data, result.total)))
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function removeVideo (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||
const videoInstance = res.locals.video
|
||||
|
||||
videoInstance.destroy().asCallback(function (err) {
|
||||
if (err) {
|
||||
videoInstance.destroy()
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => {
|
||||
logger.error('Errors when removed the video.', { error: err })
|
||||
return next(err)
|
||||
}
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
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,
|
||||
function (err, videosList, videosTotal) {
|
||||
if (err) return next(err)
|
||||
|
||||
res.json(getFormatedObjects(videosList, videosTotal))
|
||||
}
|
||||
)
|
||||
db.Video.searchAndPopulateAuthorAndPodAndTags(req.params.value, req.query.field, req.query.start, req.query.count, req.query.sort)
|
||||
.then(result => res.json(getFormatedObjects(result.data, result.total)))
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
import * as express from 'express'
|
||||
import * as Sequelize from 'sequelize'
|
||||
import { waterfall } from 'async'
|
||||
|
||||
import { database as db } from '../../../initializers/database'
|
||||
import {
|
||||
logger,
|
||||
retryTransactionWrapper,
|
||||
startSerializableTransaction,
|
||||
commitTransaction,
|
||||
rollbackTransaction
|
||||
retryTransactionWrapper
|
||||
} from '../../../helpers'
|
||||
import {
|
||||
VIDEO_RATE_TYPES,
|
||||
|
@ -46,137 +41,109 @@ function rateVideoRetryWrapper (req: express.Request, res: express.Response, nex
|
|||
errorMessage: 'Cannot update the user video rate.'
|
||||
}
|
||||
|
||||
retryTransactionWrapper(rateVideo, options, function (err) {
|
||||
if (err) return next(err)
|
||||
|
||||
return res.type('json').status(204).end()
|
||||
})
|
||||
retryTransactionWrapper(rateVideo, options)
|
||||
.then(() => res.type('json').status(204).end())
|
||||
.catch(err => next(err))
|
||||
}
|
||||
|
||||
function rateVideo (req: express.Request, res: express.Response, finalCallback: (err: Error) => void) {
|
||||
function rateVideo (req: express.Request, res: express.Response) {
|
||||
const rateType = req.body.rating
|
||||
const videoInstance = res.locals.video
|
||||
const userInstance = res.locals.oauth.token.User
|
||||
|
||||
waterfall([
|
||||
startSerializableTransaction,
|
||||
return db.sequelize.transaction(t => {
|
||||
return db.UserVideoRate.load(userInstance.id, videoInstance.id, t)
|
||||
.then(previousRate => {
|
||||
const options = { transaction: t }
|
||||
|
||||
function findPreviousRate (t, callback) {
|
||||
db.UserVideoRate.load(userInstance.id, videoInstance.id, t, function (err, previousRate) {
|
||||
return callback(err, t, previousRate)
|
||||
let likesToIncrement = 0
|
||||
let dislikesToIncrement = 0
|
||||
|
||||
if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
|
||||
else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
|
||||
|
||||
// There was a previous rate, update it
|
||||
if (previousRate) {
|
||||
// We will remove the previous rate, so we will need to remove it from the video attribute
|
||||
if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
|
||||
else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
|
||||
|
||||
previousRate.type = rateType
|
||||
|
||||
return previousRate.save(options).then(() => ({ t, likesToIncrement, dislikesToIncrement }))
|
||||
} else { // There was not a previous rate, insert a new one
|
||||
const query = {
|
||||
userId: userInstance.id,
|
||||
videoId: videoInstance.id,
|
||||
type: rateType
|
||||
}
|
||||
|
||||
return db.UserVideoRate.create(query, options).then(() => ({ likesToIncrement, dislikesToIncrement }))
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
function insertUserRateIntoDB (t, previousRate, callback) {
|
||||
const options = { transaction: t }
|
||||
|
||||
let likesToIncrement = 0
|
||||
let dislikesToIncrement = 0
|
||||
|
||||
if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
|
||||
else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
|
||||
|
||||
// There was a previous rate, update it
|
||||
if (previousRate) {
|
||||
// We will remove the previous rate, so we will need to remove it from the video attribute
|
||||
if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
|
||||
else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
|
||||
|
||||
previousRate.type = rateType
|
||||
|
||||
previousRate.save(options).asCallback(function (err) {
|
||||
return callback(err, t, likesToIncrement, dislikesToIncrement)
|
||||
})
|
||||
} else { // There was not a previous rate, insert a new one
|
||||
const query = {
|
||||
userId: userInstance.id,
|
||||
videoId: videoInstance.id,
|
||||
type: rateType
|
||||
.then(({ likesToIncrement, dislikesToIncrement }) => {
|
||||
const options = { transaction: t }
|
||||
const incrementQuery = {
|
||||
likes: likesToIncrement,
|
||||
dislikes: dislikesToIncrement
|
||||
}
|
||||
|
||||
db.UserVideoRate.create(query, options).asCallback(function (err) {
|
||||
return callback(err, t, likesToIncrement, dislikesToIncrement)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
function updateVideoAttributeDB (t, likesToIncrement, dislikesToIncrement, callback) {
|
||||
const options = { transaction: t }
|
||||
const incrementQuery = {
|
||||
likes: likesToIncrement,
|
||||
dislikes: dislikesToIncrement
|
||||
}
|
||||
|
||||
// Even if we do not own the video we increment the attributes
|
||||
// It is usefull for the user to have a feedback
|
||||
videoInstance.increment(incrementQuery, options).asCallback(function (err) {
|
||||
return callback(err, t, likesToIncrement, dislikesToIncrement)
|
||||
// Even if we do not own the video we increment the attributes
|
||||
// It is usefull for the user to have a feedback
|
||||
return videoInstance.increment(incrementQuery, options).then(() => ({ likesToIncrement, dislikesToIncrement }))
|
||||
})
|
||||
},
|
||||
.then(({ likesToIncrement, dislikesToIncrement }) => {
|
||||
// No need for an event type, we own the video
|
||||
if (videoInstance.isOwned()) return { likesToIncrement, dislikesToIncrement }
|
||||
|
||||
function sendEventsToFriendsIfNeeded (t, likesToIncrement, dislikesToIncrement, callback) {
|
||||
// No need for an event type, we own the video
|
||||
if (videoInstance.isOwned()) return callback(null, t, likesToIncrement, dislikesToIncrement)
|
||||
const eventsParams = []
|
||||
|
||||
const eventsParams = []
|
||||
if (likesToIncrement !== 0) {
|
||||
eventsParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
|
||||
count: likesToIncrement
|
||||
})
|
||||
}
|
||||
|
||||
if (likesToIncrement !== 0) {
|
||||
eventsParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
|
||||
count: likesToIncrement
|
||||
})
|
||||
}
|
||||
if (dislikesToIncrement !== 0) {
|
||||
eventsParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
|
||||
count: dislikesToIncrement
|
||||
})
|
||||
}
|
||||
|
||||
if (dislikesToIncrement !== 0) {
|
||||
eventsParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
|
||||
count: dislikesToIncrement
|
||||
})
|
||||
}
|
||||
|
||||
addEventsToRemoteVideo(eventsParams, t, function (err) {
|
||||
return callback(err, t, likesToIncrement, dislikesToIncrement)
|
||||
return addEventsToRemoteVideo(eventsParams, t).then(() => ({ likesToIncrement, dislikesToIncrement }))
|
||||
})
|
||||
},
|
||||
.then(({ likesToIncrement, dislikesToIncrement }) => {
|
||||
// We do not own the video, there is no need to send a quick and dirty update to friends
|
||||
// Our rate was already sent by the addEvent function
|
||||
if (videoInstance.isOwned() === false) return undefined
|
||||
|
||||
function sendQaduToFriendsIfNeeded (t, likesToIncrement, dislikesToIncrement, callback) {
|
||||
// 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 callback(null, t)
|
||||
const qadusParams = []
|
||||
|
||||
const qadusParams = []
|
||||
if (likesToIncrement !== 0) {
|
||||
qadusParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.LIKES
|
||||
})
|
||||
}
|
||||
|
||||
if (likesToIncrement !== 0) {
|
||||
qadusParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.LIKES
|
||||
})
|
||||
}
|
||||
if (dislikesToIncrement !== 0) {
|
||||
qadusParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
|
||||
})
|
||||
}
|
||||
|
||||
if (dislikesToIncrement !== 0) {
|
||||
qadusParams.push({
|
||||
videoId: videoInstance.id,
|
||||
type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
|
||||
})
|
||||
}
|
||||
|
||||
quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) {
|
||||
return callback(err, t)
|
||||
return quickAndDirtyUpdatesVideoToFriends(qadusParams, t)
|
||||
})
|
||||
},
|
||||
|
||||
commitTransaction
|
||||
|
||||
], function (err: Error, t: Sequelize.Transaction) {
|
||||
if (err) {
|
||||
// This is just a debug because we will retry the insert
|
||||
logger.debug('Cannot add the user video rate.', { error: err })
|
||||
return rollbackTransaction(err, t, finalCallback)
|
||||
}
|
||||
|
||||
logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username)
|
||||
return finalCallback(null)
|
||||
})
|
||||
.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.', { error: err })
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue