First typescript iteration

This commit is contained in:
Chocobozzz 2017-05-15 22:22:03 +02:00
parent d5f345ed4c
commit 65fcc3119c
113 changed files with 1961 additions and 1784 deletions

1
.gitignore vendored
View File

@ -16,3 +16,4 @@
/ffmpeg/ /ffmpeg/
/*.sublime-project /*.sublime-project
/*.sublime-workspace /*.sublime-workspace
/dist

View File

@ -70,15 +70,31 @@
"safe-buffer": "^5.0.1", "safe-buffer": "^5.0.1",
"scripty": "^1.5.0", "scripty": "^1.5.0",
"sequelize": "^3.27.0", "sequelize": "^3.27.0",
"typescript": "~2.2.0",
"winston": "^2.1.1", "winston": "^2.1.1",
"ws": "^2.0.0" "ws": "^2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@types/async": "^2.0.40",
"@types/bcrypt": "^1.0.0",
"@types/body-parser": "^1.16.3",
"@types/config": "^0.0.32",
"@types/express": "^4.0.35",
"@types/lodash": "^4.14.64",
"@types/mkdirp": "^0.3.29",
"@types/morgan": "^1.7.32",
"@types/node": "^7.0.18",
"@types/request": "^0.0.43",
"@types/sequelize": "3",
"@types/winston": "^2.3.2",
"@types/ws": "^0.0.41",
"chai": "^3.3.0", "chai": "^3.3.0",
"commander": "^2.9.0", "commander": "^2.9.0",
"mocha": "^3.0.1", "mocha": "^3.0.1",
"standard": "^10.0.0", "standard": "^10.0.0",
"supertest": "^3.0.0", "supertest": "^3.0.0",
"tslint": "^5.2.0",
"tslint-config-standard": "^5.0.2",
"webtorrent": "^0.98.0" "webtorrent": "^0.98.0"
}, },
"standard": { "standard": {

View File

@ -1,14 +1,14 @@
'use strict'
// ----------- Node modules ----------- // ----------- Node modules -----------
const bodyParser = require('body-parser') import bodyParser = require('body-parser')
const express = require('express') import express = require('express')
const expressValidator = require('express-validator') const expressValidator = require('express-validator')
const http = require('http') import http = require('http')
const morgan = require('morgan') import morgan = require('morgan')
const path = require('path') import path = require('path')
const TrackerServer = require('bittorrent-tracker').Server import bittorrentTracker = require('bittorrent-tracker')
const WebSocketServer = require('ws').Server import { Server as WebSocketServer } from 'ws'
const TrackerServer = bittorrentTracker.Server
process.title = 'peertube' process.title = 'peertube'
@ -16,70 +16,62 @@ process.title = 'peertube'
const app = express() const app = express()
// ----------- Database ----------- // ----------- Database -----------
const constants = require('./server/initializers/constants') // Do not use barels because we don't want to load all modules here (we need to initialize database first)
const logger = require('./server/helpers/logger') import { logger } from './server/helpers/logger'
import { API_VERSION, CONFIG } from './server/initializers/constants'
// Initialize database and models // Initialize database and models
const db = require('./server/initializers/database') const db = require('./server/initializers/database')
db.init(onDatabaseInitDone) db.init(onDatabaseInitDone)
// ----------- Checker ----------- // ----------- Checker -----------
const checker = require('./server/initializers/checker') import { checkMissedConfig, checkFFmpeg, checkConfig } from './server/initializers/checker'
const missed = checker.checkMissedConfig() const missed = checkMissedConfig()
if (missed.length !== 0) { if (missed.length !== 0) {
throw new Error('Miss some configurations keys : ' + missed) throw new Error('Miss some configurations keys : ' + missed)
} }
checker.checkFFmpeg(function (err) { checkFFmpeg(function (err) {
if (err) { if (err) {
throw err throw err
} }
}) })
const errorMessage = checker.checkConfig() const errorMessage = checkConfig()
if (errorMessage !== null) { if (errorMessage !== null) {
throw new Error(errorMessage) throw new Error(errorMessage)
} }
// ----------- PeerTube modules ----------- // ----------- PeerTube modules -----------
const customValidators = require('./server/helpers/custom-validators') import { migrate, installApplication } from './server/initializers'
const friends = require('./server/lib/friends') import { JobScheduler, activateSchedulers } from './server/lib'
const installer = require('./server/initializers/installer') import * as customValidators from './server/helpers/custom-validators'
const migrator = require('./server/initializers/migrator') import { apiRouter, clientsRouter, staticRouter } from './server/controllers'
const jobScheduler = require('./server/lib/jobs/job-scheduler')
const routes = require('./server/controllers')
// ----------- Command line ----------- // ----------- Command line -----------
// ----------- App ----------- // ----------- App -----------
// For the logger // For the logger
app.use(morgan('combined', { stream: logger.stream })) // app.use(morgan('combined', { stream: logger.stream }))
// For body requests // For body requests
app.use(bodyParser.json({ limit: '500kb' })) app.use(bodyParser.json({ limit: '500kb' }))
app.use(bodyParser.urlencoded({ extended: false })) app.use(bodyParser.urlencoded({ extended: false }))
// Validate some params for the API // Validate some params for the API
app.use(expressValidator({ app.use(expressValidator({
customValidators: Object.assign( customValidators: customValidators
{},
customValidators.misc,
customValidators.pods,
customValidators.users,
customValidators.videos,
customValidators.remote.videos
)
})) }))
// ----------- Views, routes and static files ----------- // ----------- Views, routes and static files -----------
// API // API
const apiRoute = '/api/' + constants.API_VERSION const apiRoute = '/api/' + API_VERSION
app.use(apiRoute, routes.api) app.use(apiRoute, apiRouter)
// Client files // Client files
app.use('/', routes.client) app.use('/', clientsRouter)
// Static files // Static files
app.use('/', routes.static) app.use('/', staticRouter)
// Always serve index client page (the client is a single page application, let it handle routing) // Always serve index client page (the client is a single page application, let it handle routing)
app.use('/*', function (req, res, next) { app.use('/*', function (req, res, next) {
@ -114,7 +106,7 @@ wss.on('connection', function (ws) {
// Catch 404 and forward to error handler // Catch 404 and forward to error handler
app.use(function (req, res, next) { app.use(function (req, res, next) {
const err = new Error('Not Found') const err = new Error('Not Found')
err.status = 404 err['status'] = 404
next(err) next(err)
}) })
@ -126,29 +118,25 @@ app.use(function (err, req, res, next) {
// ----------- Run ----------- // ----------- Run -----------
function onDatabaseInitDone () { function onDatabaseInitDone () {
const port = constants.CONFIG.LISTEN.PORT const port = CONFIG.LISTEN.PORT
// Run the migration scripts if needed // Run the migration scripts if needed
migrator.migrate(function (err) { migrate(function (err) {
if (err) throw err if (err) throw err
installer.installApplication(function (err) { installApplication(function (err) {
if (err) throw err if (err) throw err
// ----------- Make the server listening ----------- // ----------- Make the server listening -----------
server.listen(port, function () { server.listen(port, function () {
// Activate the communication with friends // Activate the communication with friends
friends.activate() activateSchedulers()
// Activate job scheduler // Activate job scheduler
jobScheduler.activate() JobScheduler.Instance.activate()
logger.info('Server listening on port %d', port) logger.info('Server listening on port %d', port)
logger.info('Webserver: %s', constants.CONFIG.WEBSERVER.URL) logger.info('Webserver: %s', CONFIG.WEBSERVER.URL)
app.emit('ready')
}) })
}) })
}) })
} }
module.exports = app

View File

@ -1,19 +1,17 @@
'use strict' import express = require('express')
const express = require('express') import { CONFIG } from '../../initializers';
import { logger } from '../../helpers'
const constants = require('../../initializers/constants')
const db = require('../../initializers/database') const db = require('../../initializers/database')
const logger = require('../../helpers/logger')
const router = express.Router() const clientsRouter = express.Router()
router.get('/local', getLocalClient) clientsRouter.get('/local', getLocalClient)
// Get the client credentials for the PeerTube front end // Get the client credentials for the PeerTube front end
function getLocalClient (req, res, next) { function getLocalClient (req, res, next) {
const serverHostname = constants.CONFIG.WEBSERVER.HOSTNAME const serverHostname = CONFIG.WEBSERVER.HOSTNAME
const serverPort = constants.CONFIG.WEBSERVER.PORT const serverPort = CONFIG.WEBSERVER.PORT
let headerHostShouldBe = serverHostname let headerHostShouldBe = serverHostname
if (serverPort !== 80 && serverPort !== 443) { if (serverPort !== 80 && serverPort !== 443) {
headerHostShouldBe += ':' + serverPort headerHostShouldBe += ':' + serverPort
@ -38,4 +36,6 @@ function getLocalClient (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
clientsRouter
}

View File

@ -1,22 +0,0 @@
'use strict'
const express = require('express')
const constants = require('../../initializers/constants')
const router = express.Router()
router.get('/', getConfig)
// Get the client credentials for the PeerTube front end
function getConfig (req, res, next) {
res.json({
signup: {
enabled: constants.CONFIG.SIGNUP.ENABLED
}
})
}
// ---------------------------------------------------------------------------
module.exports = router

View File

@ -0,0 +1,22 @@
import express = require('express')
import { CONFIG } from '../../initializers';
const configRouter = express.Router()
configRouter.get('/', getConfig)
// Get the client credentials for the PeerTube front end
function getConfig (req, res, next) {
res.json({
signup: {
enabled: CONFIG.SIGNUP.ENABLED
}
})
}
// ---------------------------------------------------------------------------
export {
configRouter
}

View File

@ -1,35 +0,0 @@
'use strict'
const express = require('express')
const utils = require('../../helpers/utils')
const router = express.Router()
const clientsController = require('./clients')
const configController = require('./config')
const podsController = require('./pods')
const remoteController = require('./remote')
const requestsController = require('./requests')
const usersController = require('./users')
const videosController = require('./videos')
router.use('/clients', clientsController)
router.use('/config', configController)
router.use('/pods', podsController)
router.use('/remote', remoteController)
router.use('/requests', requestsController)
router.use('/users', usersController)
router.use('/videos', videosController)
router.use('/ping', pong)
router.use('/*', utils.badRequest)
// ---------------------------------------------------------------------------
module.exports = router
// ---------------------------------------------------------------------------
function pong (req, res, next) {
return res.send('pong').status(200).end()
}

View File

@ -0,0 +1,33 @@
import express = require('express')
import { badRequest } from '../../helpers'
import { clientsRouter } from './clients'
import { configRouter } from './config'
import { podsRouter } from './pods'
import { remoteRouter } from './remote'
import { requestsRouter } from './requests'
import { usersRouter } from './users'
import { videosRouter } from './videos'
const apiRouter = express.Router()
apiRouter.use('/clients', clientsRouter)
apiRouter.use('/config', configRouter)
apiRouter.use('/pods', podsRouter)
apiRouter.use('/remote', remoteRouter)
apiRouter.use('/requests', requestsRouter)
apiRouter.use('/users', usersRouter)
apiRouter.use('/videos', videosRouter)
apiRouter.use('/ping', pong)
apiRouter.use('/*', badRequest)
// ---------------------------------------------------------------------------
export { apiRouter }
// ---------------------------------------------------------------------------
function pong (req, res, next) {
return res.send('pong').status(200).end()
}

View File

@ -1,109 +0,0 @@
'use strict'
const express = require('express')
const waterfall = require('async/waterfall')
const db = require('../../initializers/database')
const constants = require('../../initializers/constants')
const logger = require('../../helpers/logger')
const peertubeCrypto = require('../../helpers/peertube-crypto')
const utils = require('../../helpers/utils')
const friends = require('../../lib/friends')
const middlewares = require('../../middlewares')
const admin = middlewares.admin
const oAuth = middlewares.oauth
const podsMiddleware = middlewares.pods
const validators = middlewares.validators.pods
const router = express.Router()
router.get('/', listPods)
router.post('/',
podsMiddleware.setBodyHostPort, // We need to modify the host before running the validator!
validators.podsAdd,
addPods
)
router.post('/makefriends',
oAuth.authenticate,
admin.ensureIsAdmin,
validators.makeFriends,
podsMiddleware.setBodyHostsPort,
makeFriends
)
router.get('/quitfriends',
oAuth.authenticate,
admin.ensureIsAdmin,
quitFriends
)
// ---------------------------------------------------------------------------
module.exports = router
// ---------------------------------------------------------------------------
function addPods (req, res, next) {
const informations = req.body
waterfall([
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, callback) {
friends.sendOwnedVideosToPod(podCreated.id)
callback(null)
},
function fetchMyCertificate (callback) {
peertubeCrypto.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: constants.CONFIG.ADMIN.EMAIL })
})
}
function listPods (req, res, next) {
db.Pod.list(function (err, podsList) {
if (err) return next(err)
res.json(utils.getFormatedObjects(podsList, podsList.length))
})
}
function makeFriends (req, res, next) {
const hosts = req.body.hosts
friends.makeFriends(hosts, function (err) {
if (err) {
logger.error('Could not make friends.', { error: err })
return
}
logger.info('Made friends!')
})
res.type('json').status(204).end()
}
function quitFriends (req, res, next) {
friends.quitFriends(function (err) {
if (err) return next(err)
res.type('json').status(204).end()
})
}

View File

@ -0,0 +1,118 @@
import express = require('express')
import { waterfall } from 'async'
const db = require('../../initializers/database')
import { CONFIG } from '../../initializers'
import {
logger,
getMyPublicCert,
getFormatedObjects
} from '../../helpers'
import {
sendOwnedVideosToPod,
makeFriends,
quitFriends
} from '../../lib'
import {
podsAddValidator,
authenticate,
ensureIsAdmin,
makeFriendsValidator,
setBodyHostPort,
setBodyHostsPort
} from '../../middlewares'
const podsRouter = express.Router()
podsRouter.get('/', listPods)
podsRouter.post('/',
setBodyHostPort, // We need to modify the host before running the validator!
podsAddValidator,
addPods
)
podsRouter.post('/makefriends',
authenticate,
ensureIsAdmin,
makeFriendsValidator,
setBodyHostsPort,
makeFriends
)
podsRouter.get('/quitfriends',
authenticate,
ensureIsAdmin,
quitFriends
)
// ---------------------------------------------------------------------------
export {
podsRouter
}
// ---------------------------------------------------------------------------
function addPods (req, res, next) {
const informations = req.body
waterfall([
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, 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 })
})
}
function listPods (req, res, next) {
db.Pod.list(function (err, podsList) {
if (err) return next(err)
res.json(getFormatedObjects(podsList, podsList.length))
})
}
function makeFriendsController (req, res, next) {
const hosts = req.body.hosts
makeFriends(hosts, function (err) {
if (err) {
logger.error('Could not make friends.', { error: err })
return
}
logger.info('Made friends!')
})
res.type('json').status(204).end()
}
function quitFriendsController (req, res, next) {
quitFriends(function (err) {
if (err) return next(err)
res.type('json').status(204).end()
})
}

View File

@ -1,18 +0,0 @@
'use strict'
const express = require('express')
const utils = require('../../../helpers/utils')
const router = express.Router()
const podsRemoteController = require('./pods')
const videosRemoteController = require('./videos')
router.use('/pods', podsRemoteController)
router.use('/videos', videosRemoteController)
router.use('/*', utils.badRequest)
// ---------------------------------------------------------------------------
module.exports = router

View File

@ -0,0 +1,18 @@
import express = require('express')
import { badRequest } from '../../../helpers'
import { remotePodsRouter } from './pods'
import { remoteVideosRouter } from './videos'
const remoteRouter = express.Router()
remoteRouter.use('/pods', remotePodsRouter)
remoteRouter.use('/videos', remoteVideosRouter)
remoteRouter.use('/*', badRequest)
// ---------------------------------------------------------------------------
export {
remoteRouter
}

View File

@ -1,25 +1,23 @@
'use strict' import express = require('express')
import { waterfall } from 'async/waterfall'
const express = require('express')
const waterfall = require('async/waterfall')
const db = require('../../../initializers/database') const db = require('../../../initializers/database')
const middlewares = require('../../../middlewares') import { checkSignature, signatureValidator } from '../../../middlewares'
const checkSignature = middlewares.secure.checkSignature
const signatureValidator = middlewares.validators.remote.signature
const router = express.Router() const remotePodsRouter = express.Router()
// Post because this is a secured request // Post because this is a secured request
router.post('/remove', remotePodsRouter.post('/remove',
signatureValidator.signature, signatureValidator,
checkSignature, checkSignature,
removePods removePods
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
remotePodsRouter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1,20 +1,30 @@
'use strict' import express = require('express')
import { eachSeries, waterfall } from 'async'
const eachSeries = require('async/eachSeries')
const express = require('express')
const waterfall = require('async/waterfall')
const db = require('../../../initializers/database') const db = require('../../../initializers/database')
const constants = require('../../../initializers/constants') import {
const middlewares = require('../../../middlewares') REQUEST_ENDPOINT_ACTIONS,
const secureMiddleware = middlewares.secure REQUEST_ENDPOINTS,
const videosValidators = middlewares.validators.remote.videos REQUEST_VIDEO_EVENT_TYPES,
const signatureValidators = middlewares.validators.remote.signature REQUEST_VIDEO_QADU_TYPES
const logger = require('../../../helpers/logger') } from '../../../initializers'
const friends = require('../../../lib/friends') import {
const databaseUtils = require('../../../helpers/database-utils') checkSignature,
signatureValidator,
remoteVideosValidator,
remoteQaduVideosValidator,
remoteEventsVideosValidator
} from '../../../middlewares'
import {
logger,
commitTransaction,
retryTransactionWrapper,
rollbackTransaction,
startSerializableTransaction
} from '../../../helpers'
import { quickAndDirtyUpdatesVideoToFriends } from '../../../lib'
const ENDPOINT_ACTIONS = constants.REQUEST_ENDPOINT_ACTIONS[constants.REQUEST_ENDPOINTS.VIDEOS] const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS]
// Functions to call when processing a remote request // Functions to call when processing a remote request
const functionsHash = {} const functionsHash = {}
@ -23,32 +33,34 @@ functionsHash[ENDPOINT_ACTIONS.UPDATE] = updateRemoteVideoRetryWrapper
functionsHash[ENDPOINT_ACTIONS.REMOVE] = removeRemoteVideo functionsHash[ENDPOINT_ACTIONS.REMOVE] = removeRemoteVideo
functionsHash[ENDPOINT_ACTIONS.REPORT_ABUSE] = reportAbuseRemoteVideo functionsHash[ENDPOINT_ACTIONS.REPORT_ABUSE] = reportAbuseRemoteVideo
const router = express.Router() const remoteVideosRouter = express.Router()
router.post('/', remoteVideosRouter.post('/',
signatureValidators.signature, signatureValidator,
secureMiddleware.checkSignature, checkSignature,
videosValidators.remoteVideos, remoteVideosValidator,
remoteVideos remoteVideos
) )
router.post('/qadu', remoteVideosRouter.post('/qadu',
signatureValidators.signature, signatureValidator,
secureMiddleware.checkSignature, checkSignature,
videosValidators.remoteQaduVideos, remoteQaduVideosValidator,
remoteVideosQadu remoteVideosQadu
) )
router.post('/events', remoteVideosRouter.post('/events',
signatureValidators.signature, signatureValidator,
secureMiddleware.checkSignature, checkSignature,
videosValidators.remoteEventsVideos, remoteEventsVideosValidator,
remoteVideosEvents remoteVideosEvents
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
remoteVideosRouter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -58,7 +70,7 @@ function remoteVideos (req, res, next) {
// We need to process in the same order to keep consistency // We need to process in the same order to keep consistency
// TODO: optimization // TODO: optimization
eachSeries(requests, function (request, callbackEach) { eachSeries(requests, function (request: any, callbackEach) {
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
@ -81,7 +93,7 @@ function remoteVideosQadu (req, res, next) {
const requests = req.body.data const requests = req.body.data
const fromPod = res.locals.secure.pod const fromPod = res.locals.secure.pod
eachSeries(requests, function (request, callbackEach) { eachSeries(requests, function (request: any, callbackEach) {
const videoData = request.data const videoData = request.data
quickAndDirtyUpdateVideoRetryWrapper(videoData, fromPod, callbackEach) quickAndDirtyUpdateVideoRetryWrapper(videoData, fromPod, callbackEach)
@ -96,7 +108,7 @@ function remoteVideosEvents (req, res, next) {
const requests = req.body.data const requests = req.body.data
const fromPod = res.locals.secure.pod const fromPod = res.locals.secure.pod
eachSeries(requests, function (request, callbackEach) { eachSeries(requests, function (request: any, callbackEach) {
const eventData = request.data const eventData = request.data
processVideosEventsRetryWrapper(eventData, fromPod, callbackEach) processVideosEventsRetryWrapper(eventData, fromPod, callbackEach)
@ -113,12 +125,12 @@ function processVideosEventsRetryWrapper (eventData, fromPod, finalCallback) {
errorMessage: 'Cannot process videos events with many retries.' errorMessage: 'Cannot process videos events with many retries.'
} }
databaseUtils.retryTransactionWrapper(processVideosEvents, options, finalCallback) retryTransactionWrapper(processVideosEvents, options, finalCallback)
} }
function processVideosEvents (eventData, fromPod, finalCallback) { function processVideosEvents (eventData, fromPod, finalCallback) {
waterfall([ waterfall([
databaseUtils.startSerializableTransaction, startSerializableTransaction,
function findVideo (t, callback) { function findVideo (t, callback) {
fetchOwnedVideo(eventData.remoteId, function (err, videoInstance) { fetchOwnedVideo(eventData.remoteId, function (err, videoInstance) {
@ -133,19 +145,19 @@ function processVideosEvents (eventData, fromPod, finalCallback) {
let qaduType let qaduType
switch (eventData.eventType) { switch (eventData.eventType) {
case constants.REQUEST_VIDEO_EVENT_TYPES.VIEWS: case REQUEST_VIDEO_EVENT_TYPES.VIEWS:
columnToUpdate = 'views' columnToUpdate = 'views'
qaduType = constants.REQUEST_VIDEO_QADU_TYPES.VIEWS qaduType = REQUEST_VIDEO_QADU_TYPES.VIEWS
break break
case constants.REQUEST_VIDEO_EVENT_TYPES.LIKES: case REQUEST_VIDEO_EVENT_TYPES.LIKES:
columnToUpdate = 'likes' columnToUpdate = 'likes'
qaduType = constants.REQUEST_VIDEO_QADU_TYPES.LIKES qaduType = REQUEST_VIDEO_QADU_TYPES.LIKES
break break
case constants.REQUEST_VIDEO_EVENT_TYPES.DISLIKES: case REQUEST_VIDEO_EVENT_TYPES.DISLIKES:
columnToUpdate = 'dislikes' columnToUpdate = 'dislikes'
qaduType = constants.REQUEST_VIDEO_QADU_TYPES.DISLIKES qaduType = REQUEST_VIDEO_QADU_TYPES.DISLIKES
break break
default: default:
@ -168,17 +180,17 @@ function processVideosEvents (eventData, fromPod, finalCallback) {
} }
] ]
friends.quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) { quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) {
return callback(err, t) return callback(err, t)
}) })
}, },
databaseUtils.commitTransaction commitTransaction
], function (err, t) { ], function (err, t) {
if (err) { if (err) {
logger.debug('Cannot process a video event.', { error: err }) logger.debug('Cannot process a video event.', { error: err })
return databaseUtils.rollbackTransaction(err, t, finalCallback) return rollbackTransaction(err, t, finalCallback)
} }
logger.info('Remote video event processed for video %s.', eventData.remoteId) logger.info('Remote video event processed for video %s.', eventData.remoteId)
@ -192,14 +204,14 @@ function quickAndDirtyUpdateVideoRetryWrapper (videoData, fromPod, finalCallback
errorMessage: 'Cannot update quick and dirty the remote video with many retries.' errorMessage: 'Cannot update quick and dirty the remote video with many retries.'
} }
databaseUtils.retryTransactionWrapper(quickAndDirtyUpdateVideo, options, finalCallback) retryTransactionWrapper(quickAndDirtyUpdateVideo, options, finalCallback)
} }
function quickAndDirtyUpdateVideo (videoData, fromPod, finalCallback) { function quickAndDirtyUpdateVideo (videoData, fromPod, finalCallback) {
let videoName let videoName
waterfall([ waterfall([
databaseUtils.startSerializableTransaction, startSerializableTransaction,
function findVideo (t, callback) { function findVideo (t, callback) {
fetchRemoteVideo(fromPod.host, videoData.remoteId, function (err, videoInstance) { fetchRemoteVideo(fromPod.host, videoData.remoteId, function (err, videoInstance) {
@ -229,12 +241,12 @@ function quickAndDirtyUpdateVideo (videoData, fromPod, finalCallback) {
}) })
}, },
databaseUtils.commitTransaction commitTransaction
], function (err, t) { ], function (err, t) {
if (err) { if (err) {
logger.debug('Cannot quick and dirty update the remote video.', { error: err }) logger.debug('Cannot quick and dirty update the remote video.', { error: err })
return databaseUtils.rollbackTransaction(err, t, finalCallback) return rollbackTransaction(err, t, finalCallback)
} }
logger.info('Remote video %s quick and dirty updated', videoName) logger.info('Remote video %s quick and dirty updated', videoName)
@ -249,7 +261,7 @@ function addRemoteVideoRetryWrapper (videoToCreateData, fromPod, finalCallback)
errorMessage: 'Cannot insert the remote video with many retries.' errorMessage: 'Cannot insert the remote video with many retries.'
} }
databaseUtils.retryTransactionWrapper(addRemoteVideo, options, finalCallback) retryTransactionWrapper(addRemoteVideo, options, finalCallback)
} }
function addRemoteVideo (videoToCreateData, fromPod, finalCallback) { function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
@ -257,7 +269,7 @@ function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
waterfall([ waterfall([
databaseUtils.startSerializableTransaction, startSerializableTransaction,
function assertRemoteIdAndHostUnique (t, callback) { function assertRemoteIdAndHostUnique (t, callback) {
db.Video.loadByHostAndRemoteId(fromPod.host, videoToCreateData.remoteId, function (err, video) { db.Video.loadByHostAndRemoteId(fromPod.host, videoToCreateData.remoteId, function (err, video) {
@ -345,13 +357,13 @@ function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
}) })
}, },
databaseUtils.commitTransaction commitTransaction
], function (err, t) { ], function (err, t) {
if (err) { if (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 insert the remote video.', { error: err }) logger.debug('Cannot insert the remote video.', { error: err })
return databaseUtils.rollbackTransaction(err, t, finalCallback) return rollbackTransaction(err, t, finalCallback)
} }
logger.info('Remote video %s inserted.', videoToCreateData.name) logger.info('Remote video %s inserted.', videoToCreateData.name)
@ -366,7 +378,7 @@ function updateRemoteVideoRetryWrapper (videoAttributesToUpdate, fromPod, finalC
errorMessage: 'Cannot update the remote video with many retries' errorMessage: 'Cannot update the remote video with many retries'
} }
databaseUtils.retryTransactionWrapper(updateRemoteVideo, options, finalCallback) retryTransactionWrapper(updateRemoteVideo, options, finalCallback)
} }
function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) { function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
@ -374,7 +386,7 @@ function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
waterfall([ waterfall([
databaseUtils.startSerializableTransaction, startSerializableTransaction,
function findVideo (t, callback) { function findVideo (t, callback) {
fetchRemoteVideo(fromPod.host, videoAttributesToUpdate.remoteId, function (err, videoInstance) { fetchRemoteVideo(fromPod.host, videoAttributesToUpdate.remoteId, function (err, videoInstance) {
@ -421,13 +433,13 @@ function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
}) })
}, },
databaseUtils.commitTransaction commitTransaction
], function (err, t) { ], function (err, t) {
if (err) { if (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.', { error: err }) logger.debug('Cannot update the remote video.', { error: err })
return databaseUtils.rollbackTransaction(err, t, finalCallback) return rollbackTransaction(err, t, finalCallback)
} }
logger.info('Remote video %s updated', videoAttributesToUpdate.name) logger.info('Remote video %s updated', videoAttributesToUpdate.name)

View File

@ -1,32 +1,34 @@
'use strict' import express = require('express')
import { parallel } from 'async'
const express = require('express') import {
const parallel = require('async/parallel') getRequestScheduler,
getRequestVideoQaduScheduler,
getRequestVideoEventScheduler
} from '../../lib'
import { authenticate, ensureIsAdmin } from '../../middlewares'
const friends = require('../../lib/friends') const requestsRouter = express.Router()
const middlewares = require('../../middlewares')
const admin = middlewares.admin
const oAuth = middlewares.oauth
const router = express.Router() requestsRouter.get('/stats',
authenticate,
router.get('/stats', ensureIsAdmin,
oAuth.authenticate,
admin.ensureIsAdmin,
getStatsRequests getStatsRequests
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
requestsRouter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function getStatsRequests (req, res, next) { function getStatsRequests (req, res, next) {
parallel({ parallel({
requestScheduler: buildRequestSchedulerFunction(friends.getRequestScheduler()), requestScheduler: buildRequestSchedulerFunction(getRequestScheduler()),
requestVideoQaduScheduler: buildRequestSchedulerFunction(friends.getRequestVideoQaduScheduler()), requestVideoQaduScheduler: buildRequestSchedulerFunction(getRequestVideoQaduScheduler()),
requestVideoEventScheduler: buildRequestSchedulerFunction(friends.getRequestVideoEventScheduler()) requestVideoEventScheduler: buildRequestSchedulerFunction(getRequestVideoEventScheduler())
}, function (err, result) { }, function (err, result) {
if (err) return next(err) if (err) return next(err)

View File

@ -1,79 +1,83 @@
'use strict' import express = require('express')
import { waterfall } from 'async'
const express = require('express')
const waterfall = require('async/waterfall')
const constants = require('../../initializers/constants')
const db = require('../../initializers/database') const db = require('../../initializers/database')
const logger = require('../../helpers/logger') import { CONFIG, USER_ROLES } from '../../initializers'
const utils = require('../../helpers/utils') import { logger, getFormatedObjects } from '../../helpers'
const middlewares = require('../../middlewares') import {
const admin = middlewares.admin authenticate,
const oAuth = middlewares.oauth ensureIsAdmin,
const pagination = middlewares.pagination usersAddValidator,
const sort = middlewares.sort usersUpdateValidator,
const validatorsPagination = middlewares.validators.pagination usersRemoveValidator,
const validatorsSort = middlewares.validators.sort usersVideoRatingValidator,
const validatorsUsers = middlewares.validators.users paginationValidator,
setPagination,
usersSortValidator,
setUsersSort,
token
} from '../../middlewares'
const router = express.Router() const usersRouter = express.Router()
router.get('/me', usersRouter.get('/me',
oAuth.authenticate, authenticate,
getUserInformation getUserInformation
) )
router.get('/me/videos/:videoId/rating', usersRouter.get('/me/videos/:videoId/rating',
oAuth.authenticate, authenticate,
validatorsUsers.usersVideoRating, usersVideoRatingValidator,
getUserVideoRating getUserVideoRating
) )
router.get('/', usersRouter.get('/',
validatorsPagination.pagination, paginationValidator,
validatorsSort.usersSort, usersSortValidator,
sort.setUsersSort, setUsersSort,
pagination.setPagination, setPagination,
listUsers listUsers
) )
router.post('/', usersRouter.post('/',
oAuth.authenticate, authenticate,
admin.ensureIsAdmin, ensureIsAdmin,
validatorsUsers.usersAdd, usersAddValidator,
createUser createUser
) )
router.post('/register', usersRouter.post('/register',
ensureRegistrationEnabled, ensureRegistrationEnabled,
validatorsUsers.usersAdd, usersAddValidator,
createUser createUser
) )
router.put('/:id', usersRouter.put('/:id',
oAuth.authenticate, authenticate,
validatorsUsers.usersUpdate, usersUpdateValidator,
updateUser updateUser
) )
router.delete('/:id', usersRouter.delete('/:id',
oAuth.authenticate, authenticate,
admin.ensureIsAdmin, ensureIsAdmin,
validatorsUsers.usersRemove, usersRemoveValidator,
removeUser removeUser
) )
router.post('/token', oAuth.token, success) usersRouter.post('/token', token, success)
// TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged, implement revoke token route // TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged, implement revoke token route
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
usersRouter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function ensureRegistrationEnabled (req, res, next) { function ensureRegistrationEnabled (req, res, next) {
const registrationEnabled = constants.CONFIG.SIGNUP.ENABLED const registrationEnabled = CONFIG.SIGNUP.ENABLED
if (registrationEnabled === true) { if (registrationEnabled === true) {
return next() return next()
@ -88,7 +92,7 @@ function createUser (req, res, next) {
password: req.body.password, password: req.body.password,
email: req.body.email, email: req.body.email,
displayNSFW: false, displayNSFW: false,
role: constants.USER_ROLES.USER role: USER_ROLES.USER
}) })
user.save().asCallback(function (err, createdUser) { user.save().asCallback(function (err, createdUser) {
@ -126,7 +130,7 @@ function listUsers (req, res, next) {
db.User.listForApi(req.query.start, req.query.count, req.query.sort, function (err, usersList, usersTotal) { db.User.listForApi(req.query.start, req.query.count, req.query.sort, function (err, usersList, usersTotal) {
if (err) return next(err) if (err) return next(err)
res.json(utils.getFormatedObjects(usersList, usersTotal)) res.json(getFormatedObjects(usersList, usersTotal))
}) })
} }

View File

@ -1,43 +1,48 @@
'use strict' import express = require('express')
import { waterfall } from 'async'
const express = require('express')
const waterfall = require('async/waterfall')
const db = require('../../../initializers/database') const db = require('../../../initializers/database')
const logger = require('../../../helpers/logger') import friends = require('../../../lib/friends')
const friends = require('../../../lib/friends') import {
const middlewares = require('../../../middlewares') logger,
const admin = middlewares.admin getFormatedObjects,
const oAuth = middlewares.oauth retryTransactionWrapper,
const pagination = middlewares.pagination startSerializableTransaction,
const validators = middlewares.validators commitTransaction,
const validatorsPagination = validators.pagination rollbackTransaction
const validatorsSort = validators.sort } from '../../../helpers'
const validatorsVideos = validators.videos import {
const sort = middlewares.sort authenticate,
const databaseUtils = require('../../../helpers/database-utils') ensureIsAdmin,
const utils = require('../../../helpers/utils') paginationValidator,
videoAbuseReportValidator,
videoAbusesSortValidator,
setVideoAbusesSort,
setPagination
} from '../../../middlewares'
const router = express.Router() const abuseVideoRouter = express.Router()
router.get('/abuse', abuseVideoRouter.get('/abuse',
oAuth.authenticate, authenticate,
admin.ensureIsAdmin, ensureIsAdmin,
validatorsPagination.pagination, paginationValidator,
validatorsSort.videoAbusesSort, videoAbusesSortValidator,
sort.setVideoAbusesSort, setVideoAbusesSort,
pagination.setPagination, setPagination,
listVideoAbuses listVideoAbuses
) )
router.post('/:id/abuse', abuseVideoRouter.post('/:id/abuse',
oAuth.authenticate, authenticate,
validatorsVideos.videoAbuseReport, videoAbuseReportValidator,
reportVideoAbuseRetryWrapper reportVideoAbuseRetryWrapper
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
abuseVideoRouter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -45,7 +50,7 @@ function listVideoAbuses (req, res, next) {
db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort, function (err, abusesList, abusesTotal) { db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort, function (err, abusesList, abusesTotal) {
if (err) return next(err) if (err) return next(err)
res.json(utils.getFormatedObjects(abusesList, abusesTotal)) res.json(getFormatedObjects(abusesList, abusesTotal))
}) })
} }
@ -55,7 +60,7 @@ function reportVideoAbuseRetryWrapper (req, res, next) {
errorMessage: 'Cannot report abuse to the video with many retries.' errorMessage: 'Cannot report abuse to the video with many retries.'
} }
databaseUtils.retryTransactionWrapper(reportVideoAbuse, options, function (err) { retryTransactionWrapper(reportVideoAbuse, options, function (err) {
if (err) return next(err) if (err) return next(err)
return res.type('json').status(204).end() return res.type('json').status(204).end()
@ -75,7 +80,7 @@ function reportVideoAbuse (req, res, finalCallback) {
waterfall([ waterfall([
databaseUtils.startSerializableTransaction, startSerializableTransaction,
function createAbuse (t, callback) { function createAbuse (t, callback) {
db.VideoAbuse.create(abuse).asCallback(function (err, abuse) { db.VideoAbuse.create(abuse).asCallback(function (err, abuse) {
@ -98,12 +103,12 @@ function reportVideoAbuse (req, res, finalCallback) {
return callback(null, t) return callback(null, t)
}, },
databaseUtils.commitTransaction commitTransaction
], function andFinally (err, t) { ], function andFinally (err, t) {
if (err) { if (err) {
logger.debug('Cannot update the video.', { error: err }) logger.debug('Cannot update the video.', { error: err })
return databaseUtils.rollbackTransaction(err, t, finalCallback) return rollbackTransaction(err, t, finalCallback)
} }
logger.info('Abuse report for video %s created.', videoInstance.name) logger.info('Abuse report for video %s created.', videoInstance.name)

View File

@ -1,27 +1,27 @@
'use strict' import express = require('express')
const express = require('express')
const db = require('../../../initializers/database') const db = require('../../../initializers/database')
const logger = require('../../../helpers/logger') import { logger } from '../../../helpers'
const middlewares = require('../../../middlewares') import {
const admin = middlewares.admin authenticate,
const oAuth = middlewares.oauth ensureIsAdmin,
const validators = middlewares.validators videosBlacklistValidator
const validatorsVideos = validators.videos } from '../../../middlewares'
const router = express.Router() const blacklistRouter = express.Router()
router.post('/:id/blacklist', blacklistRouter.post('/:id/blacklist',
oAuth.authenticate, authenticate,
admin.ensureIsAdmin, ensureIsAdmin,
validatorsVideos.videosBlacklist, videosBlacklistValidator,
addVideoToBlacklist addVideoToBlacklist
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
blacklistRouter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1,37 +1,57 @@
'use strict' import express = require('express')
import fs = require('fs')
import multer = require('multer')
import path = require('path')
import { waterfall } from 'async'
const express = require('express')
const fs = require('fs')
const multer = require('multer')
const path = require('path')
const waterfall = require('async/waterfall')
const constants = require('../../../initializers/constants')
const db = require('../../../initializers/database') const db = require('../../../initializers/database')
const logger = require('../../../helpers/logger') import {
const friends = require('../../../lib/friends') CONFIG,
const middlewares = require('../../../middlewares') REQUEST_VIDEO_QADU_TYPES,
const oAuth = middlewares.oauth REQUEST_VIDEO_EVENT_TYPES,
const pagination = middlewares.pagination VIDEO_CATEGORIES,
const validators = middlewares.validators VIDEO_LICENCES,
const validatorsPagination = validators.pagination VIDEO_LANGUAGES
const validatorsSort = validators.sort } from '../../../initializers'
const validatorsVideos = validators.videos import {
const search = middlewares.search addEventToRemoteVideo,
const sort = middlewares.sort quickAndDirtyUpdateVideoToFriends,
const databaseUtils = require('../../../helpers/database-utils') addVideoToFriends,
const utils = require('../../../helpers/utils') updateVideoToFriends
} from '../../../lib'
import {
authenticate,
paginationValidator,
videosSortValidator,
setVideosSort,
setPagination,
setVideosSearch,
videosUpdateValidator,
videosSearchValidator,
videosAddValidator,
videosGetValidator,
videosRemoveValidator
} from '../../../middlewares'
import {
logger,
commitTransaction,
retryTransactionWrapper,
rollbackTransaction,
startSerializableTransaction,
generateRandomString,
getFormatedObjects
} from '../../../helpers'
const abuseController = require('./abuse') import { abuseVideoRouter } from './abuse'
const blacklistController = require('./blacklist') import { blacklistRouter } from './blacklist'
const rateController = require('./rate') import { rateVideoRouter } from './rate'
const router = express.Router() const videosRouter = express.Router()
// multer configuration // multer configuration
const storage = multer.diskStorage({ const storage = multer.diskStorage({
destination: function (req, file, cb) { destination: function (req, file, cb) {
cb(null, constants.CONFIG.STORAGE.VIDEOS_DIR) cb(null, CONFIG.STORAGE.VIDEOS_DIR)
}, },
filename: function (req, file, cb) { filename: function (req, file, cb) {
@ -39,7 +59,7 @@ const storage = multer.diskStorage({
if (file.mimetype === 'video/webm') extension = 'webm' if (file.mimetype === 'video/webm') extension = 'webm'
else if (file.mimetype === 'video/mp4') extension = 'mp4' else if (file.mimetype === 'video/mp4') extension = 'mp4'
else if (file.mimetype === 'video/ogg') extension = 'ogv' else if (file.mimetype === 'video/ogg') extension = 'ogv'
utils.generateRandomString(16, function (err, randomString) { generateRandomString(16, function (err, randomString) {
const fieldname = err ? undefined : randomString const fieldname = err ? undefined : randomString
cb(null, fieldname + '.' + extension) cb(null, fieldname + '.' + extension)
}) })
@ -48,70 +68,72 @@ const storage = multer.diskStorage({
const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }]) const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }])
router.use('/', abuseController) videosRouter.use('/', abuseVideoRouter)
router.use('/', blacklistController) videosRouter.use('/', blacklistRouter)
router.use('/', rateController) videosRouter.use('/', rateVideoRouter)
router.get('/categories', listVideoCategories) videosRouter.get('/categories', listVideoCategories)
router.get('/licences', listVideoLicences) videosRouter.get('/licences', listVideoLicences)
router.get('/languages', listVideoLanguages) videosRouter.get('/languages', listVideoLanguages)
router.get('/', videosRouter.get('/',
validatorsPagination.pagination, paginationValidator,
validatorsSort.videosSort, videosSortValidator,
sort.setVideosSort, setVideosSort,
pagination.setPagination, setPagination,
listVideos listVideos
) )
router.put('/:id', videosRouter.put('/:id',
oAuth.authenticate, authenticate,
reqFiles, reqFiles,
validatorsVideos.videosUpdate, videosUpdateValidator,
updateVideoRetryWrapper updateVideoRetryWrapper
) )
router.post('/', videosRouter.post('/',
oAuth.authenticate, authenticate,
reqFiles, reqFiles,
validatorsVideos.videosAdd, videosAddValidator,
addVideoRetryWrapper addVideoRetryWrapper
) )
router.get('/:id', videosRouter.get('/:id',
validatorsVideos.videosGet, videosGetValidator,
getVideo getVideo
) )
router.delete('/:id', videosRouter.delete('/:id',
oAuth.authenticate, authenticate,
validatorsVideos.videosRemove, videosRemoveValidator,
removeVideo removeVideo
) )
router.get('/search/:value', videosRouter.get('/search/:value',
validatorsVideos.videosSearch, videosSearchValidator,
validatorsPagination.pagination, paginationValidator,
validatorsSort.videosSort, videosSortValidator,
sort.setVideosSort, setVideosSort,
pagination.setPagination, setPagination,
search.setVideosSearch, setVideosSearch,
searchVideos searchVideos
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
videosRouter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function listVideoCategories (req, res, next) { function listVideoCategories (req, res, next) {
res.json(constants.VIDEO_CATEGORIES) res.json(VIDEO_CATEGORIES)
} }
function listVideoLicences (req, res, next) { function listVideoLicences (req, res, next) {
res.json(constants.VIDEO_LICENCES) res.json(VIDEO_LICENCES)
} }
function listVideoLanguages (req, res, next) { function listVideoLanguages (req, res, next) {
res.json(constants.VIDEO_LANGUAGES) res.json(VIDEO_LANGUAGES)
} }
// 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
@ -122,7 +144,7 @@ function addVideoRetryWrapper (req, res, next) {
errorMessage: 'Cannot insert the video with many retries.' errorMessage: 'Cannot insert the video with many retries.'
} }
databaseUtils.retryTransactionWrapper(addVideo, options, function (err) { retryTransactionWrapper(addVideo, options, function (err) {
if (err) return next(err) if (err) return next(err)
// TODO : include Location of the new video -> 201 // TODO : include Location of the new video -> 201
@ -135,7 +157,7 @@ function addVideo (req, res, videoFile, finalCallback) {
waterfall([ waterfall([
databaseUtils.startSerializableTransaction, startSerializableTransaction,
function findOrCreateAuthor (t, callback) { function findOrCreateAuthor (t, callback) {
const user = res.locals.oauth.token.User const user = res.locals.oauth.token.User
@ -179,7 +201,7 @@ function addVideo (req, res, videoFile, finalCallback) {
// Set the videoname the same as the id // Set the videoname the same as the id
function renameVideoFile (t, author, tagInstances, video, callback) { function renameVideoFile (t, author, tagInstances, video, callback) {
const videoDir = constants.CONFIG.STORAGE.VIDEOS_DIR const videoDir = CONFIG.STORAGE.VIDEOS_DIR
const source = path.join(videoDir, videoFile.filename) const source = path.join(videoDir, videoFile.filename)
const destination = path.join(videoDir, video.getVideoFilename()) const destination = path.join(videoDir, video.getVideoFilename())
@ -218,25 +240,25 @@ function addVideo (req, res, videoFile, finalCallback) {
function sendToFriends (t, video, callback) { function sendToFriends (t, video, callback) {
// Let transcoding job send the video to friends because the videofile extension might change // Let transcoding job send the video to friends because the videofile extension might change
if (constants.CONFIG.TRANSCODING.ENABLED === true) return callback(null, t) if (CONFIG.TRANSCODING.ENABLED === true) return callback(null, t)
video.toAddRemoteJSON(function (err, remoteVideo) { video.toAddRemoteJSON(function (err, remoteVideo) {
if (err) return callback(err) if (err) return callback(err)
// Now we'll add the video's meta data to our friends // Now we'll add the video's meta data to our friends
friends.addVideoToFriends(remoteVideo, t, function (err) { addVideoToFriends(remoteVideo, t, function (err) {
return callback(err, t) return callback(err, t)
}) })
}) })
}, },
databaseUtils.commitTransaction commitTransaction
], function andFinally (err, t) { ], function andFinally (err, t) {
if (err) { if (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 insert the video.', { error: err }) logger.debug('Cannot insert the video.', { error: err })
return databaseUtils.rollbackTransaction(err, t, finalCallback) return rollbackTransaction(err, t, finalCallback)
} }
logger.info('Video with name %s created.', videoInfos.name) logger.info('Video with name %s created.', videoInfos.name)
@ -250,7 +272,7 @@ function updateVideoRetryWrapper (req, res, next) {
errorMessage: 'Cannot update the video with many retries.' errorMessage: 'Cannot update the video with many retries.'
} }
databaseUtils.retryTransactionWrapper(updateVideo, options, function (err) { retryTransactionWrapper(updateVideo, options, function (err) {
if (err) return next(err) if (err) return next(err)
// TODO : include Location of the new video -> 201 // TODO : include Location of the new video -> 201
@ -265,7 +287,7 @@ function updateVideo (req, res, finalCallback) {
waterfall([ waterfall([
databaseUtils.startSerializableTransaction, startSerializableTransaction,
function findOrCreateTags (t, callback) { function findOrCreateTags (t, callback) {
if (videoInfosToUpdate.tags) { if (videoInfosToUpdate.tags) {
@ -312,12 +334,12 @@ function updateVideo (req, res, finalCallback) {
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
friends.updateVideoToFriends(json, t, function (err) { updateVideoToFriends(json, t, function (err) {
return callback(err, t) return callback(err, t)
}) })
}, },
databaseUtils.commitTransaction commitTransaction
], function andFinally (err, t) { ], function andFinally (err, t) {
if (err) { if (err) {
@ -331,7 +353,7 @@ function updateVideo (req, res, finalCallback) {
videoInstance.set(key, value) videoInstance.set(key, value)
}) })
return databaseUtils.rollbackTransaction(err, t, finalCallback) return rollbackTransaction(err, t, finalCallback)
} }
logger.info('Video with name %s updated.', videoInfosToUpdate.name) logger.info('Video with name %s updated.', videoInfosToUpdate.name)
@ -354,17 +376,17 @@ function getVideo (req, res, next) {
// 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
const qaduParams = { const qaduParams = {
videoId: videoInstance.id, videoId: videoInstance.id,
type: constants.REQUEST_VIDEO_QADU_TYPES.VIEWS type: REQUEST_VIDEO_QADU_TYPES.VIEWS
} }
friends.quickAndDirtyUpdateVideoToFriends(qaduParams) quickAndDirtyUpdateVideoToFriends(qaduParams)
}) })
} else { } else {
// Just send the event to our friends // Just send the event to our friends
const eventParams = { const eventParams = {
videoId: videoInstance.id, videoId: videoInstance.id,
type: constants.REQUEST_VIDEO_EVENT_TYPES.VIEWS type: REQUEST_VIDEO_EVENT_TYPES.VIEWS
} }
friends.addEventToRemoteVideo(eventParams) addEventToRemoteVideo(eventParams)
} }
// Do not wait the view system // Do not wait the view system
@ -375,7 +397,7 @@ function listVideos (req, res, next) {
db.Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) { db.Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) {
if (err) return next(err) if (err) return next(err)
res.json(utils.getFormatedObjects(videosList, videosTotal)) res.json(getFormatedObjects(videosList, videosTotal))
}) })
} }
@ -398,7 +420,7 @@ function searchVideos (req, res, next) {
function (err, videosList, videosTotal) { function (err, videosList, videosTotal) {
if (err) return next(err) if (err) return next(err)
res.json(utils.getFormatedObjects(videosList, videosTotal)) res.json(getFormatedObjects(videosList, videosTotal))
} }
) )
} }

View File

@ -1,29 +1,41 @@
'use strict' import express = require('express')
import { waterfall } from 'async'
const express = require('express')
const waterfall = require('async/waterfall')
const constants = require('../../../initializers/constants')
const db = require('../../../initializers/database') const db = require('../../../initializers/database')
const logger = require('../../../helpers/logger') import {
const friends = require('../../../lib/friends') logger,
const middlewares = require('../../../middlewares') retryTransactionWrapper,
const oAuth = middlewares.oauth startSerializableTransaction,
const validators = middlewares.validators commitTransaction,
const validatorsVideos = validators.videos rollbackTransaction
const databaseUtils = require('../../../helpers/database-utils') } from '../../../helpers'
import {
VIDEO_RATE_TYPES,
REQUEST_VIDEO_EVENT_TYPES,
REQUEST_VIDEO_QADU_TYPES
} from '../../../initializers'
import {
addEventsToRemoteVideo,
quickAndDirtyUpdatesVideoToFriends
} from '../../../lib'
import {
authenticate,
videoRateValidator
} from '../../../middlewares'
const router = express.Router() const rateVideoRouter = express.Router()
router.put('/:id/rate', rateVideoRouter.put('/:id/rate',
oAuth.authenticate, authenticate,
validatorsVideos.videoRate, videoRateValidator,
rateVideoRetryWrapper rateVideoRetryWrapper
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
rateVideoRouter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -33,7 +45,7 @@ function rateVideoRetryWrapper (req, res, next) {
errorMessage: 'Cannot update the user video rate.' errorMessage: 'Cannot update the user video rate.'
} }
databaseUtils.retryTransactionWrapper(rateVideo, options, function (err) { retryTransactionWrapper(rateVideo, options, function (err) {
if (err) return next(err) if (err) return next(err)
return res.type('json').status(204).end() return res.type('json').status(204).end()
@ -46,7 +58,7 @@ function rateVideo (req, res, finalCallback) {
const userInstance = res.locals.oauth.token.User const userInstance = res.locals.oauth.token.User
waterfall([ waterfall([
databaseUtils.startSerializableTransaction, startSerializableTransaction,
function findPreviousRate (t, callback) { function findPreviousRate (t, callback) {
db.UserVideoRate.load(userInstance.id, videoInstance.id, t, function (err, previousRate) { db.UserVideoRate.load(userInstance.id, videoInstance.id, t, function (err, previousRate) {
@ -60,14 +72,14 @@ function rateVideo (req, res, finalCallback) {
let likesToIncrement = 0 let likesToIncrement = 0
let dislikesToIncrement = 0 let dislikesToIncrement = 0
if (rateType === constants.VIDEO_RATE_TYPES.LIKE) likesToIncrement++ if (rateType === VIDEO_RATE_TYPES.LIKE) likesToIncrement++
else if (rateType === constants.VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++ else if (rateType === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement++
// 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 remove it from the video attribute // We will remove the previous rate, so we will need to remove it from the video attribute
if (previousRate.type === constants.VIDEO_RATE_TYPES.LIKE) likesToIncrement-- if (previousRate.type === VIDEO_RATE_TYPES.LIKE) likesToIncrement--
else if (previousRate.type === constants.VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement-- else if (previousRate.type === VIDEO_RATE_TYPES.DISLIKE) dislikesToIncrement--
previousRate.type = rateType previousRate.type = rateType
@ -110,7 +122,7 @@ function rateVideo (req, res, finalCallback) {
if (likesToIncrement !== 0) { if (likesToIncrement !== 0) {
eventsParams.push({ eventsParams.push({
videoId: videoInstance.id, videoId: videoInstance.id,
type: constants.REQUEST_VIDEO_EVENT_TYPES.LIKES, type: REQUEST_VIDEO_EVENT_TYPES.LIKES,
count: likesToIncrement count: likesToIncrement
}) })
} }
@ -118,12 +130,12 @@ function rateVideo (req, res, finalCallback) {
if (dislikesToIncrement !== 0) { if (dislikesToIncrement !== 0) {
eventsParams.push({ eventsParams.push({
videoId: videoInstance.id, videoId: videoInstance.id,
type: constants.REQUEST_VIDEO_EVENT_TYPES.DISLIKES, type: REQUEST_VIDEO_EVENT_TYPES.DISLIKES,
count: dislikesToIncrement count: dislikesToIncrement
}) })
} }
friends.addEventsToRemoteVideo(eventsParams, t, function (err) { addEventsToRemoteVideo(eventsParams, t, function (err) {
return callback(err, t, likesToIncrement, dislikesToIncrement) return callback(err, t, likesToIncrement, dislikesToIncrement)
}) })
}, },
@ -138,29 +150,29 @@ function rateVideo (req, res, finalCallback) {
if (likesToIncrement !== 0) { if (likesToIncrement !== 0) {
qadusParams.push({ qadusParams.push({
videoId: videoInstance.id, videoId: videoInstance.id,
type: constants.REQUEST_VIDEO_QADU_TYPES.LIKES type: REQUEST_VIDEO_QADU_TYPES.LIKES
}) })
} }
if (dislikesToIncrement !== 0) { if (dislikesToIncrement !== 0) {
qadusParams.push({ qadusParams.push({
videoId: videoInstance.id, videoId: videoInstance.id,
type: constants.REQUEST_VIDEO_QADU_TYPES.DISLIKES type: REQUEST_VIDEO_QADU_TYPES.DISLIKES
}) })
} }
friends.quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) { quickAndDirtyUpdatesVideoToFriends(qadusParams, t, function (err) {
return callback(err, t) return callback(err, t)
}) })
}, },
databaseUtils.commitTransaction commitTransaction
], function (err, t) { ], function (err, t) {
if (err) { if (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 add the user video rate.', { error: err }) logger.debug('Cannot add the user video rate.', { error: err })
return databaseUtils.rollbackTransaction(err, t, finalCallback) return rollbackTransaction(err, t, finalCallback)
} }
logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username) logger.info('User video rate for video %s of user %s updated.', videoInstance.name, userInstance.username)

View File

@ -1,40 +1,48 @@
'use strict' import { parallel } from 'async'
import express = require('express')
import fs = require('fs')
import { join } from 'path'
import expressValidator = require('express-validator')
// TODO: use .validator when express-validator typing will have validator field
const validator = expressValidator['validator']
const parallel = require('async/parallel')
const express = require('express')
const fs = require('fs')
const path = require('path')
const validator = require('express-validator').validator
const constants = require('../initializers/constants')
const db = require('../initializers/database') const db = require('../initializers/database')
import {
CONFIG,
REMOTE_SCHEME,
STATIC_PATHS,
STATIC_MAX_AGE
} from '../initializers'
const router = express.Router() const clientsRouter = express.Router()
// TODO: move to constants
const opengraphComment = '<!-- opengraph tags -->' const opengraphComment = '<!-- opengraph tags -->'
const distPath = path.join(__dirname, '..', '..', 'client/dist') const distPath = join(__dirname, '..', '..', 'client/dist')
const embedPath = path.join(distPath, 'standalone/videos/embed.html') const embedPath = join(distPath, 'standalone/videos/embed.html')
const indexPath = path.join(distPath, 'index.html') const indexPath = join(distPath, 'index.html')
// Special route that add OpenGraph tags // Special route that add OpenGraph tags
// Do not use a template engine for a so little thing // Do not use a template engine for a so little thing
router.use('/videos/watch/:id', generateWatchHtmlPage) clientsRouter.use('/videos/watch/:id', generateWatchHtmlPage)
router.use('/videos/embed', function (req, res, next) { clientsRouter.use('/videos/embed', function (req, res, next) {
res.sendFile(embedPath) res.sendFile(embedPath)
}) })
// Static HTML/CSS/JS client files // Static HTML/CSS/JS client files
router.use('/client', express.static(distPath, { maxAge: constants.STATIC_MAX_AGE })) clientsRouter.use('/client', express.static(distPath, { maxAge: STATIC_MAX_AGE }))
// 404 for static files not found // 404 for static files not found
router.use('/client/*', function (req, res, next) { clientsRouter.use('/client/*', function (req, res, next) {
res.sendStatus(404) res.sendStatus(404)
}) })
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = router export {
clientsRouter
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -42,16 +50,16 @@ function addOpenGraphTags (htmlStringPage, video) {
let basePreviewUrlHttp let basePreviewUrlHttp
if (video.isOwned()) { if (video.isOwned()) {
basePreviewUrlHttp = constants.CONFIG.WEBSERVER.URL basePreviewUrlHttp = CONFIG.WEBSERVER.URL
} else { } else {
basePreviewUrlHttp = constants.REMOTE_SCHEME.HTTP + '://' + video.Author.Pod.host basePreviewUrlHttp = REMOTE_SCHEME.HTTP + '://' + video.Author.Pod.host
} }
// We fetch the remote preview (bigger than the thumbnail) // We fetch the remote preview (bigger than the thumbnail)
// This should not overhead the remote server since social websites put in a cache the OpenGraph tags // This should not overhead the remote server since social websites put in a cache the OpenGraph tags
// We can't use the thumbnail because these social websites want bigger images (> 200x200 for Facebook for example) // We can't use the thumbnail because these social websites want bigger images (> 200x200 for Facebook for example)
const previewUrl = basePreviewUrlHttp + constants.STATIC_PATHS.PREVIEWS + video.getPreviewName() const previewUrl = basePreviewUrlHttp + STATIC_PATHS.PREVIEWS + video.getPreviewName()
const videoUrl = constants.CONFIG.WEBSERVER.URL + '/videos/watch/' + video.id const videoUrl = CONFIG.WEBSERVER.URL + '/videos/watch/' + video.id
const metaTags = { const metaTags = {
'og:type': 'video', 'og:type': 'video',
@ -95,11 +103,11 @@ function generateWatchHtmlPage (req, res, next) {
video: function (callback) { video: function (callback) {
db.Video.loadAndPopulateAuthorAndPodAndTags(videoId, callback) db.Video.loadAndPopulateAuthorAndPodAndTags(videoId, callback)
} }
}, function (err, results) { }, function (err, result: any) {
if (err) return next(err) if (err) return next(err)
const html = results.file.toString() const html = result.file.toString()
const video = results.video const video = result.video
// Let Angular application handle errors // Let Angular application handle errors
if (!video) return res.sendFile(indexPath) if (!video) return res.sendFile(indexPath)

View File

@ -1,11 +0,0 @@
'use strict'
const apiController = require('./api/')
const clientController = require('./client')
const staticController = require('./static')
module.exports = {
api: apiController,
client: clientController,
static: staticController
}

View File

@ -0,0 +1,3 @@
export * from './static';
export * from './client';
export * from './api';

View File

@ -1,45 +0,0 @@
'use strict'
const express = require('express')
const cors = require('cors')
const constants = require('../initializers/constants')
const router = express.Router()
/*
Cors is very important to let other pods access torrent and video files
*/
const torrentsPhysicalPath = constants.CONFIG.STORAGE.TORRENTS_DIR
router.use(
constants.STATIC_PATHS.TORRENTS,
cors(),
express.static(torrentsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE })
)
// Videos path for webseeding
const videosPhysicalPath = constants.CONFIG.STORAGE.VIDEOS_DIR
router.use(
constants.STATIC_PATHS.WEBSEED,
cors(),
express.static(videosPhysicalPath, { maxAge: constants.STATIC_MAX_AGE })
)
// Thumbnails path for express
const thumbnailsPhysicalPath = constants.CONFIG.STORAGE.THUMBNAILS_DIR
router.use(
constants.STATIC_PATHS.THUMBNAILS,
express.static(thumbnailsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE })
)
// Video previews path for express
const previewsPhysicalPath = constants.CONFIG.STORAGE.PREVIEWS_DIR
router.use(
constants.STATIC_PATHS.PREVIEWS,
express.static(previewsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE })
)
// ---------------------------------------------------------------------------
module.exports = router

View File

@ -0,0 +1,49 @@
import express = require('express')
import cors = require('cors')
import {
CONFIG,
STATIC_MAX_AGE,
STATIC_PATHS
} from '../initializers'
const staticRouter = express.Router()
/*
Cors is very important to let other pods access torrent and video files
*/
const torrentsPhysicalPath = CONFIG.STORAGE.TORRENTS_DIR
staticRouter.use(
STATIC_PATHS.TORRENTS,
cors(),
express.static(torrentsPhysicalPath, { maxAge: STATIC_MAX_AGE })
)
// Videos path for webseeding
const videosPhysicalPath = CONFIG.STORAGE.VIDEOS_DIR
staticRouter.use(
STATIC_PATHS.WEBSEED,
cors(),
express.static(videosPhysicalPath, { maxAge: STATIC_MAX_AGE })
)
// Thumbnails path for express
const thumbnailsPhysicalPath = CONFIG.STORAGE.THUMBNAILS_DIR
staticRouter.use(
STATIC_PATHS.THUMBNAILS,
express.static(thumbnailsPhysicalPath, { maxAge: STATIC_MAX_AGE })
)
// Video previews path for express
const previewsPhysicalPath = CONFIG.STORAGE.PREVIEWS_DIR
staticRouter.use(
STATIC_PATHS.PREVIEWS,
express.static(previewsPhysicalPath, { maxAge: STATIC_MAX_AGE })
)
// ---------------------------------------------------------------------------
export {
staticRouter
}

View File

@ -1,19 +0,0 @@
'use strict'
const miscValidators = require('./misc')
const podsValidators = require('./pods')
const remoteValidators = require('./remote')
const usersValidators = require('./users')
const videosValidators = require('./videos')
const validators = {
misc: miscValidators,
pods: podsValidators,
remote: remoteValidators,
users: usersValidators,
videos: videosValidators
}
// ---------------------------------------------------------------------------
module.exports = validators

View File

@ -0,0 +1,6 @@
export * from './remote'
export * from './misc'
export * from './pods'
export * from './pods'
export * from './users'
export * from './videos'

View File

@ -1,10 +1,3 @@
'use strict'
const miscValidators = {
exists,
isArray
}
function exists (value) { function exists (value) {
return value !== undefined && value !== null return value !== undefined && value !== null
} }
@ -15,4 +8,7 @@ function isArray (value) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = miscValidators export {
exists,
isArray
}

View File

@ -1,20 +1,15 @@
'use strict' import expressValidator = require('express-validator')
// TODO: use .validator when express-validator typing will have validator field
const validator = expressValidator['validator']
const validator = require('express-validator').validator import { isArray } from './misc'
const miscValidators = require('./misc')
const podsValidators = {
isEachUniqueHostValid,
isHostValid
}
function isHostValid (host) { function isHostValid (host) {
return validator.isURL(host) && host.split('://').length === 1 return validator.isURL(host) && host.split('://').length === 1
} }
function isEachUniqueHostValid (hosts) { function isEachUniqueHostValid (hosts) {
return miscValidators.isArray(hosts) && return isArray(hosts) &&
hosts.length !== 0 && hosts.length !== 0 &&
hosts.every(function (host) { hosts.every(function (host) {
return isHostValid(host) && hosts.indexOf(host) === hosts.lastIndexOf(host) return isHostValid(host) && hosts.indexOf(host) === hosts.lastIndexOf(host)
@ -23,4 +18,7 @@ function isEachUniqueHostValid (hosts) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = podsValidators export {
isEachUniqueHostValid,
isHostValid
}

View File

@ -1,11 +0,0 @@
'use strict'
const remoteVideosValidators = require('./videos')
const validators = {
videos: remoteVideosValidators
}
// ---------------------------------------------------------------------------
module.exports = validators

View File

@ -0,0 +1 @@
export * from './videos';

View File

@ -1,118 +0,0 @@
'use strict'
const has = require('lodash/has')
const values = require('lodash/values')
const constants = require('../../../initializers/constants')
const videosValidators = require('../videos')
const miscValidators = require('../misc')
const ENDPOINT_ACTIONS = constants.REQUEST_ENDPOINT_ACTIONS[constants.REQUEST_ENDPOINTS.VIDEOS]
const remoteVideosValidators = {
isEachRemoteRequestVideosValid,
isEachRemoteRequestVideosQaduValid,
isEachRemoteRequestVideosEventsValid
}
function isEachRemoteRequestVideosValid (requests) {
return miscValidators.isArray(requests) &&
requests.every(function (request) {
const video = request.data
if (!video) return false
return (
isRequestTypeAddValid(request.type) &&
isCommonVideoAttributesValid(video) &&
videosValidators.isVideoAuthorValid(video.author) &&
videosValidators.isVideoThumbnailDataValid(video.thumbnailData)
) ||
(
isRequestTypeUpdateValid(request.type) &&
isCommonVideoAttributesValid(video)
) ||
(
isRequestTypeRemoveValid(request.type) &&
videosValidators.isVideoRemoteIdValid(video.remoteId)
) ||
(
isRequestTypeReportAbuseValid(request.type) &&
videosValidators.isVideoRemoteIdValid(request.data.videoRemoteId) &&
videosValidators.isVideoAbuseReasonValid(request.data.reportReason) &&
videosValidators.isVideoAbuseReporterUsernameValid(request.data.reporterUsername)
)
})
}
function isEachRemoteRequestVideosQaduValid (requests) {
return miscValidators.isArray(requests) &&
requests.every(function (request) {
const video = request.data
if (!video) return false
return (
videosValidators.isVideoRemoteIdValid(video.remoteId) &&
(has(video, 'views') === false || videosValidators.isVideoViewsValid) &&
(has(video, 'likes') === false || videosValidators.isVideoLikesValid) &&
(has(video, 'dislikes') === false || videosValidators.isVideoDislikesValid)
)
})
}
function isEachRemoteRequestVideosEventsValid (requests) {
return miscValidators.isArray(requests) &&
requests.every(function (request) {
const eventData = request.data
if (!eventData) return false
return (
videosValidators.isVideoRemoteIdValid(eventData.remoteId) &&
values(constants.REQUEST_VIDEO_EVENT_TYPES).indexOf(eventData.eventType) !== -1 &&
videosValidators.isVideoEventCountValid(eventData.count)
)
})
}
// ---------------------------------------------------------------------------
module.exports = remoteVideosValidators
// ---------------------------------------------------------------------------
function isCommonVideoAttributesValid (video) {
return videosValidators.isVideoDateValid(video.createdAt) &&
videosValidators.isVideoDateValid(video.updatedAt) &&
videosValidators.isVideoCategoryValid(video.category) &&
videosValidators.isVideoLicenceValid(video.licence) &&
videosValidators.isVideoLanguageValid(video.language) &&
videosValidators.isVideoNSFWValid(video.nsfw) &&
videosValidators.isVideoDescriptionValid(video.description) &&
videosValidators.isVideoDurationValid(video.duration) &&
videosValidators.isVideoInfoHashValid(video.infoHash) &&
videosValidators.isVideoNameValid(video.name) &&
videosValidators.isVideoTagsValid(video.tags) &&
videosValidators.isVideoRemoteIdValid(video.remoteId) &&
videosValidators.isVideoExtnameValid(video.extname) &&
videosValidators.isVideoViewsValid(video.views) &&
videosValidators.isVideoLikesValid(video.likes) &&
videosValidators.isVideoDislikesValid(video.dislikes)
}
function isRequestTypeAddValid (value) {
return value === ENDPOINT_ACTIONS.ADD
}
function isRequestTypeUpdateValid (value) {
return value === ENDPOINT_ACTIONS.UPDATE
}
function isRequestTypeRemoveValid (value) {
return value === ENDPOINT_ACTIONS.REMOVE
}
function isRequestTypeReportAbuseValid (value) {
return value === ENDPOINT_ACTIONS.REPORT_ABUSE
}

View File

@ -0,0 +1,138 @@
import { has, values } from 'lodash'
import {
REQUEST_ENDPOINTS,
REQUEST_ENDPOINT_ACTIONS,
REQUEST_VIDEO_EVENT_TYPES
} from '../../../initializers'
import { isArray } from '../misc'
import {
isVideoAuthorValid,
isVideoThumbnailDataValid,
isVideoRemoteIdValid,
isVideoAbuseReasonValid,
isVideoAbuseReporterUsernameValid,
isVideoViewsValid,
isVideoLikesValid,
isVideoDislikesValid,
isVideoEventCountValid,
isVideoDateValid,
isVideoCategoryValid,
isVideoLicenceValid,
isVideoLanguageValid,
isVideoNSFWValid,
isVideoDescriptionValid,
isVideoDurationValid,
isVideoInfoHashValid,
isVideoNameValid,
isVideoTagsValid,
isVideoExtnameValid
} from '../videos'
const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS]
function isEachRemoteRequestVideosValid (requests) {
return isArray(requests) &&
requests.every(function (request) {
const video = request.data
if (!video) return false
return (
isRequestTypeAddValid(request.type) &&
isCommonVideoAttributesValid(video) &&
isVideoAuthorValid(video.author) &&
isVideoThumbnailDataValid(video.thumbnailData)
) ||
(
isRequestTypeUpdateValid(request.type) &&
isCommonVideoAttributesValid(video)
) ||
(
isRequestTypeRemoveValid(request.type) &&
isVideoRemoteIdValid(video.remoteId)
) ||
(
isRequestTypeReportAbuseValid(request.type) &&
isVideoRemoteIdValid(request.data.videoRemoteId) &&
isVideoAbuseReasonValid(request.data.reportReason) &&
isVideoAbuseReporterUsernameValid(request.data.reporterUsername)
)
})
}
function isEachRemoteRequestVideosQaduValid (requests) {
return isArray(requests) &&
requests.every(function (request) {
const video = request.data
if (!video) return false
return (
isVideoRemoteIdValid(video.remoteId) &&
(has(video, 'views') === false || isVideoViewsValid) &&
(has(video, 'likes') === false || isVideoLikesValid) &&
(has(video, 'dislikes') === false || isVideoDislikesValid)
)
})
}
function isEachRemoteRequestVideosEventsValid (requests) {
return isArray(requests) &&
requests.every(function (request) {
const eventData = request.data
if (!eventData) return false
return (
isVideoRemoteIdValid(eventData.remoteId) &&
values(REQUEST_VIDEO_EVENT_TYPES).indexOf(eventData.eventType) !== -1 &&
isVideoEventCountValid(eventData.count)
)
})
}
// ---------------------------------------------------------------------------
export {
isEachRemoteRequestVideosValid,
isEachRemoteRequestVideosQaduValid,
isEachRemoteRequestVideosEventsValid
}
// ---------------------------------------------------------------------------
function isCommonVideoAttributesValid (video) {
return isVideoDateValid(video.createdAt) &&
isVideoDateValid(video.updatedAt) &&
isVideoCategoryValid(video.category) &&
isVideoLicenceValid(video.licence) &&
isVideoLanguageValid(video.language) &&
isVideoNSFWValid(video.nsfw) &&
isVideoDescriptionValid(video.description) &&
isVideoDurationValid(video.duration) &&
isVideoInfoHashValid(video.infoHash) &&
isVideoNameValid(video.name) &&
isVideoTagsValid(video.tags) &&
isVideoRemoteIdValid(video.remoteId) &&
isVideoExtnameValid(video.extname) &&
isVideoViewsValid(video.views) &&
isVideoLikesValid(video.likes) &&
isVideoDislikesValid(video.dislikes)
}
function isRequestTypeAddValid (value) {
return value === ENDPOINT_ACTIONS.ADD
}
function isRequestTypeUpdateValid (value) {
return value === ENDPOINT_ACTIONS.UPDATE
}
function isRequestTypeRemoveValid (value) {
return value === ENDPOINT_ACTIONS.REMOVE
}
function isRequestTypeReportAbuseValid (value) {
return value === ENDPOINT_ACTIONS.REPORT_ABUSE
}

View File

@ -1,24 +1,17 @@
'use strict' import { values } from 'lodash'
import expressValidator = require('express-validator')
// TODO: use .validator when express-validator typing will have validator field
const validator = expressValidator['validator']
const validator = require('express-validator').validator import { CONSTRAINTS_FIELDS, USER_ROLES } from '../../initializers'
const values = require('lodash/values') const USERS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.USERS
const constants = require('../../initializers/constants')
const USERS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.USERS
const usersValidators = {
isUserPasswordValid,
isUserRoleValid,
isUserUsernameValid,
isUserDisplayNSFWValid
}
function isUserPasswordValid (value) { function isUserPasswordValid (value) {
return validator.isLength(value, USERS_CONSTRAINTS_FIELDS.PASSWORD) return validator.isLength(value, USERS_CONSTRAINTS_FIELDS.PASSWORD)
} }
function isUserRoleValid (value) { function isUserRoleValid (value) {
return values(constants.USER_ROLES).indexOf(value) !== -1 return values(USER_ROLES).indexOf(value) !== -1
} }
function isUserUsernameValid (value) { function isUserUsernameValid (value) {
@ -33,4 +26,9 @@ function isUserDisplayNSFWValid (value) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = usersValidators export {
isUserPasswordValid,
isUserRoleValid,
isUserUsernameValid,
isUserDisplayNSFWValid
}

View File

@ -1,43 +1,24 @@
'use strict' import { values } from 'lodash'
import expressValidator = require('express-validator')
// TODO: use .validator when express-validator typing will have validator field
const validator = expressValidator['validator']
const validator = require('express-validator').validator import {
const values = require('lodash/values') CONSTRAINTS_FIELDS,
VIDEO_CATEGORIES,
VIDEO_LICENCES,
VIDEO_LANGUAGES,
VIDEO_RATE_TYPES
} from '../../initializers'
import { isUserUsernameValid } from './users'
import { isArray } from './misc'
const constants = require('../../initializers/constants') const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
const usersValidators = require('./users') const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
const miscValidators = require('./misc') const VIDEO_EVENTS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_EVENTS
const VIDEOS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEOS
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEO_ABUSES
const VIDEO_EVENTS_CONSTRAINTS_FIELDS = constants.CONSTRAINTS_FIELDS.VIDEO_EVENTS
const videosValidators = {
isVideoAuthorValid,
isVideoDateValid,
isVideoCategoryValid,
isVideoLicenceValid,
isVideoLanguageValid,
isVideoNSFWValid,
isVideoDescriptionValid,
isVideoDurationValid,
isVideoInfoHashValid,
isVideoNameValid,
isVideoTagsValid,
isVideoThumbnailValid,
isVideoThumbnailDataValid,
isVideoExtnameValid,
isVideoRemoteIdValid,
isVideoAbuseReasonValid,
isVideoAbuseReporterUsernameValid,
isVideoFile,
isVideoViewsValid,
isVideoLikesValid,
isVideoRatingTypeValid,
isVideoDislikesValid,
isVideoEventCountValid
}
function isVideoAuthorValid (value) { function isVideoAuthorValid (value) {
return usersValidators.isUserUsernameValid(value) return isUserUsernameValid(value)
} }
function isVideoDateValid (value) { function isVideoDateValid (value) {
@ -45,15 +26,15 @@ function isVideoDateValid (value) {
} }
function isVideoCategoryValid (value) { function isVideoCategoryValid (value) {
return constants.VIDEO_CATEGORIES[value] !== undefined return VIDEO_CATEGORIES[value] !== undefined
} }
function isVideoLicenceValid (value) { function isVideoLicenceValid (value) {
return constants.VIDEO_LICENCES[value] !== undefined return VIDEO_LICENCES[value] !== undefined
} }
function isVideoLanguageValid (value) { function isVideoLanguageValid (value) {
return value === null || constants.VIDEO_LANGUAGES[value] !== undefined return value === null || VIDEO_LANGUAGES[value] !== undefined
} }
function isVideoNSFWValid (value) { function isVideoNSFWValid (value) {
@ -81,7 +62,7 @@ function isVideoNameValid (value) {
} }
function isVideoTagsValid (tags) { function isVideoTagsValid (tags) {
return miscValidators.isArray(tags) && return isArray(tags) &&
validator.isInt(tags.length, VIDEOS_CONSTRAINTS_FIELDS.TAGS) && validator.isInt(tags.length, VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
tags.every(function (tag) { tags.every(function (tag) {
return validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG) return validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
@ -105,7 +86,7 @@ function isVideoAbuseReasonValid (value) {
} }
function isVideoAbuseReporterUsernameValid (value) { function isVideoAbuseReporterUsernameValid (value) {
return usersValidators.isUserUsernameValid(value) return isUserUsernameValid(value)
} }
function isVideoViewsValid (value) { function isVideoViewsValid (value) {
@ -125,7 +106,7 @@ function isVideoEventCountValid (value) {
} }
function isVideoRatingTypeValid (value) { function isVideoRatingTypeValid (value) {
return values(constants.VIDEO_RATE_TYPES).indexOf(value) !== -1 return values(VIDEO_RATE_TYPES).indexOf(value) !== -1
} }
function isVideoFile (value, files) { function isVideoFile (value, files) {
@ -145,4 +126,28 @@ function isVideoFile (value, files) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = videosValidators export {
isVideoAuthorValid,
isVideoDateValid,
isVideoCategoryValid,
isVideoLicenceValid,
isVideoLanguageValid,
isVideoNSFWValid,
isVideoDescriptionValid,
isVideoDurationValid,
isVideoInfoHashValid,
isVideoNameValid,
isVideoTagsValid,
isVideoThumbnailValid,
isVideoThumbnailDataValid,
isVideoExtnameValid,
isVideoRemoteIdValid,
isVideoAbuseReasonValid,
isVideoAbuseReporterUsernameValid,
isVideoFile,
isVideoViewsValid,
isVideoLikesValid,
isVideoRatingTypeValid,
isVideoDislikesValid,
isVideoEventCountValid
}

View File

@ -1,17 +1,8 @@
'use strict' // TODO: import from ES6 when retry typing file will include errorFilter function
import retry = require('async/retry')
const retry = require('async/retry')
const db = require('../initializers/database') const db = require('../initializers/database')
const logger = require('./logger') import { logger } from './logger'
const utils = {
commitTransaction,
retryTransactionWrapper,
rollbackTransaction,
startSerializableTransaction,
transactionRetryer
}
function commitTransaction (t, callback) { function commitTransaction (t, callback) {
return t.commit().asCallback(callback) return t.commit().asCallback(callback)
@ -33,7 +24,7 @@ function rollbackTransaction (err, t, callback) {
function retryTransactionWrapper (functionToRetry, options, finalCallback) { function retryTransactionWrapper (functionToRetry, options, finalCallback) {
const args = options.arguments ? options.arguments : [] const args = options.arguments ? options.arguments : []
utils.transactionRetryer( transactionRetryer(
function (callback) { function (callback) {
return functionToRetry.apply(this, args.concat([ callback ])) return functionToRetry.apply(this, args.concat([ callback ]))
}, },
@ -69,4 +60,10 @@ function startSerializableTransaction (callback) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = utils export {
commitTransaction,
retryTransactionWrapper,
rollbackTransaction,
startSerializableTransaction,
transactionRetryer
}

6
server/helpers/index.ts Normal file
View File

@ -0,0 +1,6 @@
export * from './logger'
export * from './custom-validators'
export * from './database-utils'
export * from './peertube-crypto'
export * from './requests'
export * from './utils'

View File

@ -1,23 +1,21 @@
// Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/ // Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/
'use strict' import mkdirp = require('mkdirp')
import path = require('path')
import winston = require('winston')
const mkdirp = require('mkdirp') // Do not use barrel (dependencies issues)
const path = require('path') import { CONFIG } from '../initializers/constants'
const winston = require('winston')
winston.emitErrs = true
const constants = require('../initializers/constants') const label = CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT
const label = constants.CONFIG.WEBSERVER.HOSTNAME + ':' + constants.CONFIG.WEBSERVER.PORT
// Create the directory if it does not exist // Create the directory if it does not exist
mkdirp.sync(constants.CONFIG.STORAGE.LOG_DIR) mkdirp.sync(CONFIG.STORAGE.LOG_DIR)
const logger = new winston.Logger({ const logger = new winston.Logger({
transports: [ transports: [
new winston.transports.File({ new winston.transports.File({
level: 'debug', level: 'debug',
filename: path.join(constants.CONFIG.STORAGE.LOG_DIR, 'all-logs.log'), filename: path.join(CONFIG.STORAGE.LOG_DIR, 'all-logs.log'),
handleExceptions: true, handleExceptions: true,
json: true, json: true,
maxsize: 5242880, maxsize: 5242880,
@ -38,12 +36,13 @@ const logger = new winston.Logger({
exitOnError: true exitOnError: true
}) })
logger.stream = { // TODO: useful?
write: function (message, encoding) { // logger.stream = {
logger.info(message) // write: function (message) {
} // logger.info(message)
} // }
// }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = logger export { logger }

View File

@ -1,26 +1,21 @@
'use strict' import crypto = require('crypto')
import bcrypt = require('bcrypt')
import fs = require('fs')
import openssl = require('openssl-wrapper')
import { join } from 'path'
const crypto = require('crypto') import {
const bcrypt = require('bcrypt') SIGNATURE_ALGORITHM,
const fs = require('fs') SIGNATURE_ENCODING,
const openssl = require('openssl-wrapper') PRIVATE_CERT_NAME,
const pathUtils = require('path') CONFIG,
BCRYPT_SALT_SIZE,
const constants = require('../initializers/constants') PUBLIC_CERT_NAME
const logger = require('./logger') } from '../initializers'
import { logger } from './logger'
const peertubeCrypto = {
checkSignature,
comparePassword,
createCertsIfNotExist,
cryptPassword,
getMyPrivateCert,
getMyPublicCert,
sign
}
function checkSignature (publicKey, data, hexSignature) { function checkSignature (publicKey, data, hexSignature) {
const verify = crypto.createVerify(constants.SIGNATURE_ALGORITHM) const verify = crypto.createVerify(SIGNATURE_ALGORITHM)
let dataString let dataString
if (typeof data === 'string') { if (typeof data === 'string') {
@ -36,12 +31,12 @@ function checkSignature (publicKey, data, hexSignature) {
verify.update(dataString, 'utf8') verify.update(dataString, 'utf8')
const isValid = verify.verify(publicKey, hexSignature, constants.SIGNATURE_ENCODING) const isValid = verify.verify(publicKey, hexSignature, SIGNATURE_ENCODING)
return isValid return isValid
} }
function sign (data) { function sign (data) {
const sign = crypto.createSign(constants.SIGNATURE_ALGORITHM) const sign = crypto.createSign(SIGNATURE_ALGORITHM)
let dataString let dataString
if (typeof data === 'string') { if (typeof data === 'string') {
@ -58,9 +53,9 @@ function sign (data) {
sign.update(dataString, 'utf8') sign.update(dataString, 'utf8')
// TODO: make async // TODO: make async
const certPath = pathUtils.join(constants.CONFIG.STORAGE.CERT_DIR, constants.PRIVATE_CERT_NAME) const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME)
const myKey = fs.readFileSync(certPath) const myKey = fs.readFileSync(certPath)
const signature = sign.sign(myKey, constants.SIGNATURE_ENCODING) const signature = sign.sign(myKey.toString(), SIGNATURE_ENCODING)
return signature return signature
} }
@ -88,7 +83,7 @@ function createCertsIfNotExist (callback) {
} }
function cryptPassword (password, callback) { function cryptPassword (password, callback) {
bcrypt.genSalt(constants.BCRYPT_SALT_SIZE, function (err, salt) { bcrypt.genSalt(BCRYPT_SALT_SIZE, function (err, salt) {
if (err) return callback(err) if (err) return callback(err)
bcrypt.hash(password, salt, function (err, hash) { bcrypt.hash(password, salt, function (err, hash) {
@ -98,23 +93,31 @@ function cryptPassword (password, callback) {
} }
function getMyPrivateCert (callback) { function getMyPrivateCert (callback) {
const certPath = pathUtils.join(constants.CONFIG.STORAGE.CERT_DIR, constants.PRIVATE_CERT_NAME) const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME)
fs.readFile(certPath, 'utf8', callback) fs.readFile(certPath, 'utf8', callback)
} }
function getMyPublicCert (callback) { function getMyPublicCert (callback) {
const certPath = pathUtils.join(constants.CONFIG.STORAGE.CERT_DIR, constants.PUBLIC_CERT_NAME) const certPath = join(CONFIG.STORAGE.CERT_DIR, PUBLIC_CERT_NAME)
fs.readFile(certPath, 'utf8', callback) fs.readFile(certPath, 'utf8', callback)
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = peertubeCrypto export {
checkSignature,
comparePassword,
createCertsIfNotExist,
cryptPassword,
getMyPrivateCert,
getMyPublicCert,
sign
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function certsExist (callback) { function certsExist (callback) {
const certPath = pathUtils.join(constants.CONFIG.STORAGE.CERT_DIR, constants.PRIVATE_CERT_NAME) const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME)
fs.access(certPath, function (err) { fs.access(certPath, function (err) {
// If there is an error the certificates do not exist // If there is an error the certificates do not exist
const exists = !err const exists = !err
@ -134,7 +137,7 @@ function createCerts (callback) {
logger.info('Generating a RSA key...') logger.info('Generating a RSA key...')
const privateCertPath = pathUtils.join(constants.CONFIG.STORAGE.CERT_DIR, constants.PRIVATE_CERT_NAME) const privateCertPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME)
const genRsaOptions = { const genRsaOptions = {
'out': privateCertPath, 'out': privateCertPath,
'2048': false '2048': false
@ -148,7 +151,7 @@ function createCerts (callback) {
logger.info('RSA key generated.') logger.info('RSA key generated.')
logger.info('Managing public key...') logger.info('Managing public key...')
const publicCertPath = pathUtils.join(constants.CONFIG.STORAGE.CERT_DIR, 'peertube.pub') const publicCertPath = join(CONFIG.STORAGE.CERT_DIR, 'peertube.pub')
const rsaOptions = { const rsaOptions = {
'in': privateCertPath, 'in': privateCertPath,
'pubout': true, 'pubout': true,

View File

@ -1,21 +1,18 @@
'use strict' import replay = require('request-replay')
import request = require('request')
const replay = require('request-replay') import {
const request = require('request') RETRY_REQUESTS,
REMOTE_SCHEME,
const constants = require('../initializers/constants') CONFIG
const peertubeCrypto = require('./peertube-crypto') } from '../initializers'
import { sign } from './peertube-crypto'
const requests = {
makeRetryRequest,
makeSecureRequest
}
function makeRetryRequest (params, callback) { function makeRetryRequest (params, callback) {
replay( replay(
request(params, callback), request(params, callback),
{ {
retries: constants.RETRY_REQUESTS, retries: RETRY_REQUESTS,
factor: 3, factor: 3,
maxTimeout: Infinity, maxTimeout: Infinity,
errorCodes: [ 'EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED' ] errorCodes: [ 'EADDRINFO', 'ETIMEDOUT', 'ECONNRESET', 'ESOCKETTIMEDOUT', 'ENOTFOUND', 'ECONNREFUSED' ]
@ -25,18 +22,17 @@ function makeRetryRequest (params, callback) {
function makeSecureRequest (params, callback) { function makeSecureRequest (params, callback) {
const requestParams = { const requestParams = {
url: constants.REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path url: REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path,
json: {}
} }
if (params.method !== 'POST') { if (params.method !== 'POST') {
return callback(new Error('Cannot make a secure request with a non POST method.')) return callback(new Error('Cannot make a secure request with a non POST method.'))
} }
requestParams.json = {}
// Add signature if it is specified in the params // Add signature if it is specified in the params
if (params.sign === true) { if (params.sign === true) {
const host = constants.CONFIG.WEBSERVER.HOST const host = CONFIG.WEBSERVER.HOST
let dataToSign let dataToSign
if (params.data) { if (params.data) {
@ -47,22 +43,23 @@ function makeSecureRequest (params, callback) {
dataToSign = host dataToSign = host
} }
requestParams.json.signature = { requestParams.json['signature'] = {
host, // Which host we pretend to be host, // Which host we pretend to be
signature: peertubeCrypto.sign(dataToSign) signature: sign(dataToSign)
} }
} }
// If there are data informations // If there are data informations
if (params.data) { if (params.data) {
requestParams.json.data = params.data requestParams.json['data'] = params.data
} }
console.log(requestParams.json.data)
request.post(requestParams, callback) request.post(requestParams, callback)
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = requests export {
makeRetryRequest,
makeSecureRequest
}

View File

@ -1,24 +1,13 @@
'use strict' import { pseudoRandomBytes } from 'crypto'
const crypto = require('crypto') import { logger } from './logger'
const logger = require('./logger')
const utils = {
badRequest,
createEmptyCallback,
cleanForExit,
generateRandomString,
isTestInstance,
getFormatedObjects
}
function badRequest (req, res, next) { function badRequest (req, res, next) {
res.type('json').status(400).end() res.type('json').status(400).end()
} }
function generateRandomString (size, callback) { function generateRandomString (size, callback) {
crypto.pseudoRandomBytes(size, function (err, raw) { pseudoRandomBytes(size, function (err, raw) {
if (err) return callback(err) if (err) return callback(err)
callback(null, raw.toString('hex')) callback(null, raw.toString('hex'))
@ -55,4 +44,11 @@ function getFormatedObjects (objects, objectsTotal) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = utils export {
badRequest,
createEmptyCallback,
cleanForExit,
generateRandomString,
isTestInstance,
getFormatedObjects
}

View File

@ -1,17 +1,7 @@
'use strict' import config = require('config')
const config = require('config')
const constants = require('./constants')
const db = require('./database') const db = require('./database')
import { CONFIG } from './constants'
const checker = {
checkConfig,
checkFFmpeg,
checkMissedConfig,
clientsExist,
usersExist
}
// Some checks on configuration files // Some checks on configuration files
function checkConfig () { function checkConfig () {
@ -50,7 +40,7 @@ function checkFFmpeg (callback) {
Ffmpeg.getAvailableCodecs(function (err, codecs) { Ffmpeg.getAvailableCodecs(function (err, codecs) {
if (err) return callback(err) if (err) return callback(err)
if (constants.CONFIG.TRANSCODING.ENABLED === false) return callback(null) if (CONFIG.TRANSCODING.ENABLED === false) return callback(null)
const canEncode = [ 'libx264' ] const canEncode = [ 'libx264' ]
canEncode.forEach(function (codec) { canEncode.forEach(function (codec) {
@ -85,4 +75,10 @@ function usersExist (callback) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = checker export {
checkConfig,
checkFFmpeg,
checkMissedConfig,
clientsExist,
usersExist
}

View File

@ -1,7 +1,5 @@
'use strict' import config = require('config')
import { join } from 'path'
const config = require('config')
const path = require('path')
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -36,38 +34,40 @@ const OAUTH_LIFETIME = {
const CONFIG = { const CONFIG = {
LISTEN: { LISTEN: {
PORT: config.get('listen.port') PORT: config.get<number>('listen.port')
}, },
DATABASE: { DATABASE: {
DBNAME: 'peertube' + config.get('database.suffix'), DBNAME: 'peertube' + config.get<string>('database.suffix'),
HOSTNAME: config.get('database.hostname'), HOSTNAME: config.get<string>('database.hostname'),
PORT: config.get('database.port'), PORT: config.get<number>('database.port'),
USERNAME: config.get('database.username'), USERNAME: config.get<string>('database.username'),
PASSWORD: config.get('database.password') PASSWORD: config.get<string>('database.password')
}, },
STORAGE: { STORAGE: {
CERT_DIR: path.join(__dirname, '..', '..', config.get('storage.certs')), CERT_DIR: join(__dirname, '..', '..', config.get<string>('storage.certs')),
LOG_DIR: path.join(__dirname, '..', '..', config.get('storage.logs')), LOG_DIR: join(__dirname, '..', '..', config.get<string>('storage.logs')),
VIDEOS_DIR: path.join(__dirname, '..', '..', config.get('storage.videos')), VIDEOS_DIR: join(__dirname, '..', '..', config.get<string>('storage.videos')),
THUMBNAILS_DIR: path.join(__dirname, '..', '..', config.get('storage.thumbnails')), THUMBNAILS_DIR: join(__dirname, '..', '..', config.get<string>('storage.thumbnails')),
PREVIEWS_DIR: path.join(__dirname, '..', '..', config.get('storage.previews')), PREVIEWS_DIR: join(__dirname, '..', '..', config.get<string>('storage.previews')),
TORRENTS_DIR: path.join(__dirname, '..', '..', config.get('storage.torrents')) TORRENTS_DIR: join(__dirname, '..', '..', config.get<string>('storage.torrents'))
}, },
WEBSERVER: { WEBSERVER: {
SCHEME: config.get('webserver.https') === true ? 'https' : 'http', SCHEME: config.get<boolean>('webserver.https') === true ? 'https' : 'http',
WS: config.get('webserver.https') === true ? 'wss' : 'ws', WS: config.get<boolean>('webserver.https') === true ? 'wss' : 'ws',
HOSTNAME: config.get('webserver.hostname'), HOSTNAME: config.get<string>('webserver.hostname'),
PORT: config.get('webserver.port') PORT: config.get<number>('webserver.port'),
URL: '',
HOST: ''
}, },
ADMIN: { ADMIN: {
EMAIL: config.get('admin.email') EMAIL: config.get<string>('admin.email')
}, },
SIGNUP: { SIGNUP: {
ENABLED: config.get('signup.enabled') ENABLED: config.get<boolean>('signup.enabled')
}, },
TRANSCODING: { TRANSCODING: {
ENABLED: config.get('transcoding.enabled'), ENABLED: config.get<boolean>('transcoding.enabled'),
THREADS: config.get('transcoding.threads') THREADS: config.get<number>('transcoding.threads')
} }
} }
CONFIG.WEBSERVER.URL = CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT CONFIG.WEBSERVER.URL = CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT
@ -283,12 +283,12 @@ if (isTestInstance() === true) {
JOBS_FETCHING_INTERVAL = 10000 JOBS_FETCHING_INTERVAL = 10000
REMOTE_SCHEME.HTTP = 'http' REMOTE_SCHEME.HTTP = 'http'
REMOTE_SCHEME.WS = 'ws' REMOTE_SCHEME.WS = 'ws'
STATIC_MAX_AGE = 0 STATIC_MAX_AGE = '0'
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = { export {
API_VERSION, API_VERSION,
BCRYPT_SALT_SIZE, BCRYPT_SALT_SIZE,
CONFIG, CONFIG,

View File

@ -1,24 +1,23 @@
'use strict' import fs = require('fs')
import { join } from 'path'
import Sequelize = require('sequelize')
const fs = require('fs') import { CONFIG } from './constants'
const path = require('path') // Do not use barrel, we need to load database first
const Sequelize = require('sequelize') import { logger } from '../helpers/logger'
import { isTestInstance } from '../helpers/utils'
const constants = require('../initializers/constants') const dbname = CONFIG.DATABASE.DBNAME
const logger = require('../helpers/logger') const username = CONFIG.DATABASE.USERNAME
const utils = require('../helpers/utils') const password = CONFIG.DATABASE.PASSWORD
const database = {} const database: any = {}
const dbname = constants.CONFIG.DATABASE.DBNAME
const username = constants.CONFIG.DATABASE.USERNAME
const password = constants.CONFIG.DATABASE.PASSWORD
const sequelize = new Sequelize(dbname, username, password, { const sequelize = new Sequelize(dbname, username, password, {
dialect: 'postgres', dialect: 'postgres',
host: constants.CONFIG.DATABASE.HOSTNAME, host: CONFIG.DATABASE.HOSTNAME,
port: constants.CONFIG.DATABASE.PORT, port: CONFIG.DATABASE.PORT,
benchmark: utils.isTestInstance(), benchmark: isTestInstance(),
logging: function (message, benchmark) { logging: function (message, benchmark) {
let newMessage = message let newMessage = message
@ -31,24 +30,16 @@ const sequelize = new Sequelize(dbname, username, password, {
}) })
database.sequelize = sequelize database.sequelize = sequelize
database.Sequelize = Sequelize
database.init = init
// --------------------------------------------------------------------------- database.init = function (silent, callback) {
module.exports = database
// ---------------------------------------------------------------------------
function init (silent, callback) {
if (!callback) { if (!callback) {
callback = silent callback = silent
silent = false silent = false
} }
if (!callback) callback = function () {} if (!callback) callback = function () { /* empty */ }
const modelDirectory = path.join(__dirname, '..', 'models') const modelDirectory = join(__dirname, '..', 'models')
fs.readdir(modelDirectory, function (err, files) { fs.readdir(modelDirectory, function (err, files) {
if (err) throw err if (err) throw err
@ -59,9 +50,9 @@ function init (silent, callback) {
return true return true
}) })
.forEach(function (file) { .forEach(function (file) {
const model = sequelize.import(path.join(modelDirectory, file)) const model = sequelize.import(join(modelDirectory, file))
database[model.name] = model database[model['name']] = model
}) })
Object.keys(database).forEach(function (modelName) { Object.keys(database).forEach(function (modelName) {
@ -75,3 +66,7 @@ function init (silent, callback) {
return callback(null) return callback(null)
}) })
} }
// ---------------------------------------------------------------------------
module.exports = database

View File

@ -0,0 +1,6 @@
// Constants first, databse in second!
export * from './constants'
export * from './database'
export * from './checker'
export * from './installer'
export * from './migrator'

View File

@ -1,21 +1,13 @@
'use strict' import { join } from 'path'
import config = require('config')
import { each, series } from 'async'
import mkdirp = require('mkdirp')
import passwordGenerator = require('password-generator')
const config = require('config')
const each = require('async/each')
const mkdirp = require('mkdirp')
const passwordGenerator = require('password-generator')
const path = require('path')
const series = require('async/series')
const checker = require('./checker')
const constants = require('./constants')
const db = require('./database') const db = require('./database')
const logger = require('../helpers/logger') import { USER_ROLES, CONFIG, LAST_MIGRATION_VERSION } from './constants'
const peertubeCrypto = require('../helpers/peertube-crypto') import { clientsExist, usersExist } from './checker'
import { logger, createCertsIfNotExist } from '../helpers'
const installer = {
installApplication
}
function installApplication (callback) { function installApplication (callback) {
series([ series([
@ -29,7 +21,7 @@ function installApplication (callback) {
}, },
function createCertificates (callbackAsync) { function createCertificates (callbackAsync) {
peertubeCrypto.createCertsIfNotExist(callbackAsync) createCertsIfNotExist(callbackAsync)
}, },
function createOAuthClient (callbackAsync) { function createOAuthClient (callbackAsync) {
@ -44,7 +36,9 @@ function installApplication (callback) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = installer export {
installApplication
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -53,12 +47,12 @@ function createDirectoriesIfNotExist (callback) {
each(Object.keys(storages), function (key, callbackEach) { each(Object.keys(storages), function (key, callbackEach) {
const dir = storages[key] const dir = storages[key]
mkdirp(path.join(__dirname, '..', '..', dir), callbackEach) mkdirp(join(__dirname, '..', '..', dir), callbackEach)
}, callback) }, callback)
} }
function createOAuthClientIfNotExist (callback) { function createOAuthClientIfNotExist (callback) {
checker.clientsExist(function (err, exist) { clientsExist(function (err, exist) {
if (err) return callback(err) if (err) return callback(err)
// Nothing to do, clients already exist // Nothing to do, clients already exist
@ -86,7 +80,7 @@ function createOAuthClientIfNotExist (callback) {
} }
function createOAuthAdminIfNotExist (callback) { function createOAuthAdminIfNotExist (callback) {
checker.usersExist(function (err, exist) { usersExist(function (err, exist) {
if (err) return callback(err) if (err) return callback(err)
// Nothing to do, users already exist // Nothing to do, users already exist
@ -95,9 +89,9 @@ function createOAuthAdminIfNotExist (callback) {
logger.info('Creating the administrator.') logger.info('Creating the administrator.')
const username = 'root' const username = 'root'
const role = constants.USER_ROLES.ADMIN const role = USER_ROLES.ADMIN
const email = constants.CONFIG.ADMIN.EMAIL const email = CONFIG.ADMIN.EMAIL
const createOptions = {} const createOptions: { validate?: boolean } = {}
let password = '' let password = ''
// Do not generate a random password for tests // Do not generate a random password for tests
@ -128,7 +122,7 @@ function createOAuthAdminIfNotExist (callback) {
logger.info('User password: ' + password) logger.info('User password: ' + password)
logger.info('Creating Application table.') logger.info('Creating Application table.')
db.Application.create({ migrationVersion: constants.LAST_MIGRATION_VERSION }).asCallback(callback) db.Application.create({ migrationVersion: LAST_MIGRATION_VERSION }).asCallback(callback)
}) })
}) })
} }

View File

@ -1,9 +1,7 @@
'use strict' import { waterfall } from 'async'
const waterfall = require('async/waterfall')
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -36,6 +34,11 @@ exports.up = function (utils, finalCallback) {
], finalCallback) ], finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,9 +1,7 @@
'use strict' import { waterfall } from 'async'
const waterfall = require('async/waterfall')
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -36,6 +34,11 @@ exports.up = function (utils, finalCallback) {
], finalCallback) ], finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,7 +1,5 @@
'use strict'
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -14,6 +12,11 @@ exports.up = function (utils, finalCallback) {
q.addColumn('Videos', 'views', data, { transaction: utils.transaction }).asCallback(finalCallback) q.addColumn('Videos', 'views', data, { transaction: utils.transaction }).asCallback(finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,7 +1,5 @@
'use strict'
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -14,6 +12,11 @@ exports.up = function (utils, finalCallback) {
q.addColumn('Videos', 'likes', data, { transaction: utils.transaction }).asCallback(finalCallback) q.addColumn('Videos', 'likes', data, { transaction: utils.transaction }).asCallback(finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,7 +1,5 @@
'use strict'
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -14,6 +12,11 @@ exports.up = function (utils, finalCallback) {
q.addColumn('Videos', 'dislikes', data, { transaction: utils.transaction }).asCallback(finalCallback) q.addColumn('Videos', 'dislikes', data, { transaction: utils.transaction }).asCallback(finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,9 +1,7 @@
'use strict' import { waterfall } from 'async'
const waterfall = require('async/waterfall')
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -29,6 +27,11 @@ exports.up = function (utils, finalCallback) {
], finalCallback) ], finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,9 +1,7 @@
'use strict' import { waterfall } from 'async'
const waterfall = require('async/waterfall')
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -29,6 +27,11 @@ exports.up = function (utils, finalCallback) {
], finalCallback) ], finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,9 +1,7 @@
'use strict' import { waterfall } from 'async'
const waterfall = require('async/waterfall')
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -29,6 +27,11 @@ exports.up = function (utils, finalCallback) {
], finalCallback) ], finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,7 +1,5 @@
'use strict'
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -14,6 +12,11 @@ exports.up = function (utils, finalCallback) {
q.addColumn('Users', 'displayNSFW', data, { transaction: utils.transaction }).asCallback(finalCallback) q.addColumn('Users', 'displayNSFW', data, { transaction: utils.transaction }).asCallback(finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,7 +1,5 @@
'use strict'
// utils = { transaction, queryInterface, sequelize, Sequelize } // utils = { transaction, queryInterface, sequelize, Sequelize }
exports.up = function (utils, finalCallback) { function up (utils, finalCallback) {
const q = utils.queryInterface const q = utils.queryInterface
const Sequelize = utils.Sequelize const Sequelize = utils.Sequelize
@ -14,6 +12,11 @@ exports.up = function (utils, finalCallback) {
q.addColumn('Videos', 'language', data, { transaction: utils.transaction }).asCallback(finalCallback) q.addColumn('Videos', 'language', data, { transaction: utils.transaction }).asCallback(finalCallback)
} }
exports.down = function (options, callback) { function down (options, callback) {
throw new Error('Not implemented.') throw new Error('Not implemented.')
} }
export {
up,
down
}

View File

@ -1,17 +1,10 @@
'use strict' import { waterfall, eachSeries } from 'async'
import fs = require('fs')
import path = require('path')
const waterfall = require('async/waterfall')
const eachSeries = require('async/eachSeries')
const fs = require('fs')
const path = require('path')
const constants = require('./constants')
const db = require('./database') const db = require('./database')
const logger = require('../helpers/logger') import { LAST_MIGRATION_VERSION } from './constants'
import { logger } from '../helpers'
const migrator = {
migrate: migrate
}
function migrate (finalCallback) { function migrate (finalCallback) {
waterfall([ waterfall([
@ -46,7 +39,7 @@ function migrate (finalCallback) {
function abortMigrationIfNotNeeded (actualVersion, callback) { function abortMigrationIfNotNeeded (actualVersion, callback) {
// No need migrations // No need migrations
if (actualVersion >= constants.LAST_MIGRATION_VERSION) return finalCallback(null) if (actualVersion >= LAST_MIGRATION_VERSION) return finalCallback(null)
return callback(null, actualVersion) return callback(null, actualVersion)
}, },
@ -66,7 +59,7 @@ function migrate (finalCallback) {
}, function (err) { }, function (err) {
if (err) return callback(err) if (err) return callback(err)
logger.info('Migrations finished. New migration version schema: %s', constants.LAST_MIGRATION_VERSION) logger.info('Migrations finished. New migration version schema: %s', LAST_MIGRATION_VERSION)
return callback(null) return callback(null)
}) })
} }
@ -75,7 +68,9 @@ function migrate (finalCallback) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = migrator export {
migrate
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1,48 +1,35 @@
'use strict' import { each, eachLimit, eachSeries, series, waterfall } from 'async'
import request = require('request')
const each = require('async/each')
const eachLimit = require('async/eachLimit')
const eachSeries = require('async/eachSeries')
const series = require('async/series')
const request = require('request')
const waterfall = require('async/waterfall')
const constants = require('../initializers/constants')
const db = require('../initializers/database') const db = require('../initializers/database')
const logger = require('../helpers/logger') import {
const peertubeCrypto = require('../helpers/peertube-crypto') API_VERSION,
const requests = require('../helpers/requests') CONFIG,
const utils = require('../helpers/utils') REQUESTS_IN_PARALLEL,
const RequestScheduler = require('./request/request-scheduler') REQUEST_ENDPOINTS,
const RequestVideoQaduScheduler = require('./request/request-video-qadu-scheduler') REQUEST_ENDPOINT_ACTIONS,
const RequestVideoEventScheduler = require('./request/request-video-event-scheduler') REMOTE_SCHEME
} from '../initializers'
import {
logger,
getMyPublicCert,
makeSecureRequest,
makeRetryRequest,
createEmptyCallback
} from '../helpers'
import {
RequestScheduler,
RequestVideoQaduScheduler,
RequestVideoEventScheduler
} from './request'
const ENDPOINT_ACTIONS = constants.REQUEST_ENDPOINT_ACTIONS[constants.REQUEST_ENDPOINTS.VIDEOS] const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS]
const requestScheduler = new RequestScheduler() const requestScheduler = new RequestScheduler()
const requestVideoQaduScheduler = new RequestVideoQaduScheduler() const requestVideoQaduScheduler = new RequestVideoQaduScheduler()
const requestVideoEventScheduler = new RequestVideoEventScheduler() const requestVideoEventScheduler = new RequestVideoEventScheduler()
const friends = { function activateSchedulers () {
activate,
addVideoToFriends,
updateVideoToFriends,
reportAbuseVideoToFriend,
quickAndDirtyUpdateVideoToFriends,
quickAndDirtyUpdatesVideoToFriends,
addEventToRemoteVideo,
addEventsToRemoteVideo,
hasFriends,
makeFriends,
quitFriends,
removeVideoToFriends,
sendOwnedVideosToPod,
getRequestScheduler,
getRequestVideoQaduScheduler,
getRequestVideoEventScheduler
}
function activate () {
requestScheduler.activate() requestScheduler.activate()
requestVideoQaduScheduler.activate() requestVideoQaduScheduler.activate()
requestVideoEventScheduler.activate() requestVideoEventScheduler.activate()
@ -51,7 +38,7 @@ function activate () {
function addVideoToFriends (videoData, transaction, callback) { function addVideoToFriends (videoData, transaction, callback) {
const options = { const options = {
type: ENDPOINT_ACTIONS.ADD, type: ENDPOINT_ACTIONS.ADD,
endpoint: constants.REQUEST_ENDPOINTS.VIDEOS, endpoint: REQUEST_ENDPOINTS.VIDEOS,
data: videoData, data: videoData,
transaction transaction
} }
@ -61,7 +48,7 @@ function addVideoToFriends (videoData, transaction, callback) {
function updateVideoToFriends (videoData, transaction, callback) { function updateVideoToFriends (videoData, transaction, callback) {
const options = { const options = {
type: ENDPOINT_ACTIONS.UPDATE, type: ENDPOINT_ACTIONS.UPDATE,
endpoint: constants.REQUEST_ENDPOINTS.VIDEOS, endpoint: REQUEST_ENDPOINTS.VIDEOS,
data: videoData, data: videoData,
transaction transaction
} }
@ -71,7 +58,7 @@ function updateVideoToFriends (videoData, transaction, callback) {
function removeVideoToFriends (videoParams) { function removeVideoToFriends (videoParams) {
const options = { const options = {
type: ENDPOINT_ACTIONS.REMOVE, type: ENDPOINT_ACTIONS.REMOVE,
endpoint: constants.REQUEST_ENDPOINTS.VIDEOS, endpoint: REQUEST_ENDPOINTS.VIDEOS,
data: videoParams data: videoParams
} }
createRequest(options) createRequest(options)
@ -80,14 +67,14 @@ function removeVideoToFriends (videoParams) {
function reportAbuseVideoToFriend (reportData, video) { function reportAbuseVideoToFriend (reportData, video) {
const options = { const options = {
type: ENDPOINT_ACTIONS.REPORT_ABUSE, type: ENDPOINT_ACTIONS.REPORT_ABUSE,
endpoint: constants.REQUEST_ENDPOINTS.VIDEOS, endpoint: REQUEST_ENDPOINTS.VIDEOS,
data: reportData, data: reportData,
toIds: [ video.Author.podId ] toIds: [ video.Author.podId ]
} }
createRequest(options) createRequest(options)
} }
function quickAndDirtyUpdateVideoToFriends (qaduParams, transaction, callback) { function quickAndDirtyUpdateVideoToFriends (qaduParams, transaction?, callback?) {
const options = { const options = {
videoId: qaduParams.videoId, videoId: qaduParams.videoId,
type: qaduParams.type, type: qaduParams.type,
@ -110,7 +97,7 @@ function quickAndDirtyUpdatesVideoToFriends (qadusParams, transaction, finalCall
series(tasks, finalCallback) series(tasks, finalCallback)
} }
function addEventToRemoteVideo (eventParams, transaction, callback) { function addEventToRemoteVideo (eventParams, transaction?, callback?) {
const options = { const options = {
videoId: eventParams.videoId, videoId: eventParams.videoId,
type: eventParams.type, type: eventParams.type,
@ -146,7 +133,7 @@ function makeFriends (hosts, callback) {
const podsScore = {} const podsScore = {}
logger.info('Make friends!') logger.info('Make friends!')
peertubeCrypto.getMyPublicCert(function (err, cert) { getMyPublicCert(function (err, cert) {
if (err) { if (err) {
logger.error('Cannot read public cert.') logger.error('Cannot read public cert.')
return callback(err) return callback(err)
@ -186,16 +173,17 @@ function quitFriends (callback) {
function announceIQuitMyFriends (pods, callbackAsync) { function announceIQuitMyFriends (pods, callbackAsync) {
const requestParams = { const requestParams = {
method: 'POST', method: 'POST',
path: '/api/' + constants.API_VERSION + '/remote/pods/remove', path: '/api/' + API_VERSION + '/remote/pods/remove',
sign: true sign: true,
toPod: null
} }
// Announce we quit them // Announce we quit them
// We don't care if the request fails // We don't care if the request fails
// The other pod will exclude us automatically after a while // The other pod will exclude us automatically after a while
eachLimit(pods, constants.REQUESTS_IN_PARALLEL, function (pod, callbackEach) { eachLimit(pods, REQUESTS_IN_PARALLEL, function (pod, callbackEach) {
requestParams.toPod = pod requestParams.toPod = pod
requests.makeSecureRequest(requestParams, callbackEach) makeSecureRequest(requestParams, callbackEach)
}, function (err) { }, function (err) {
if (err) { if (err) {
logger.error('Some errors while quitting friends.', { err: err }) logger.error('Some errors while quitting friends.', { err: err })
@ -207,7 +195,7 @@ function quitFriends (callback) {
}, },
function removePodsFromDB (pods, callbackAsync) { function removePodsFromDB (pods, callbackAsync) {
each(pods, function (pod, callbackEach) { each(pods, function (pod: any, callbackEach) {
pod.destroy().asCallback(callbackEach) pod.destroy().asCallback(callbackEach)
}, callbackAsync) }, callbackAsync)
} }
@ -239,7 +227,7 @@ function sendOwnedVideosToPod (podId) {
const options = { const options = {
type: 'add', type: 'add',
endpoint: constants.REQUEST_ENDPOINTS.VIDEOS, endpoint: REQUEST_ENDPOINTS.VIDEOS,
data: remoteVideo, data: remoteVideo,
toIds: [ podId ] toIds: [ podId ]
} }
@ -263,7 +251,24 @@ function getRequestVideoEventScheduler () {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = friends export {
activateSchedulers,
addVideoToFriends,
updateVideoToFriends,
reportAbuseVideoToFriend,
quickAndDirtyUpdateVideoToFriends,
quickAndDirtyUpdatesVideoToFriends,
addEventToRemoteVideo,
addEventsToRemoteVideo,
hasFriends,
makeFriends,
quitFriends,
removeVideoToFriends,
sendOwnedVideosToPod,
getRequestScheduler,
getRequestVideoQaduScheduler,
getRequestVideoEventScheduler
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -304,9 +309,9 @@ function computeWinningPods (hosts, podsScore) {
} }
function getForeignPodsList (host, callback) { function getForeignPodsList (host, callback) {
const path = '/api/' + constants.API_VERSION + '/pods' const path = '/api/' + API_VERSION + '/pods'
request.get(constants.REMOTE_SCHEME.HTTP + '://' + host + path, function (err, response, body) { request.get(REMOTE_SCHEME.HTTP + '://' + host + path, function (err, response, body) {
if (err) return callback(err) if (err) return callback(err)
try { try {
@ -324,18 +329,18 @@ function makeRequestsToWinningPods (cert, podsList, callback) {
// Flush pool requests // Flush pool requests
requestScheduler.forceSend() requestScheduler.forceSend()
eachLimit(podsList, constants.REQUESTS_IN_PARALLEL, function (pod, callbackEach) { eachLimit(podsList, REQUESTS_IN_PARALLEL, function (pod: any, callbackEach) {
const params = { const params = {
url: constants.REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + constants.API_VERSION + '/pods/', url: REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + API_VERSION + '/pods/',
method: 'POST', method: 'POST',
json: { json: {
host: constants.CONFIG.WEBSERVER.HOST, host: CONFIG.WEBSERVER.HOST,
email: constants.CONFIG.ADMIN.EMAIL, email: CONFIG.ADMIN.EMAIL,
publicKey: cert publicKey: cert
} }
} }
requests.makeRetryRequest(params, function (err, res, body) { makeRetryRequest(params, function (err, res, body) {
if (err) { if (err) {
logger.error('Error with adding %s pod.', pod.host, { error: err }) logger.error('Error with adding %s pod.', pod.host, { error: err })
// Don't break the process // Don't break the process
@ -372,8 +377,8 @@ function makeRequestsToWinningPods (cert, podsList, callback) {
// Wrapper that populate "toIds" argument with all our friends if it is not specified // Wrapper that populate "toIds" argument with all our friends if it is not specified
// { type, endpoint, data, toIds, transaction } // { type, endpoint, data, toIds, transaction }
function createRequest (options, callback) { function createRequest (options, callback?) {
if (!callback) callback = function () {} if (!callback) callback = function () { /* empty */ }
if (options.toIds) return requestScheduler.createRequest(options, callback) if (options.toIds) return requestScheduler.createRequest(options, callback)
// If the "toIds" pods is not specified, we send the request to all our friends // If the "toIds" pods is not specified, we send the request to all our friends
@ -389,17 +394,17 @@ function createRequest (options, callback) {
} }
function createVideoQaduRequest (options, callback) { function createVideoQaduRequest (options, callback) {
if (!callback) callback = utils.createEmptyCallback() if (!callback) callback = createEmptyCallback()
requestVideoQaduScheduler.createRequest(options, callback) requestVideoQaduScheduler.createRequest(options, callback)
} }
function createVideoEventRequest (options, callback) { function createVideoEventRequest (options, callback) {
if (!callback) callback = utils.createEmptyCallback() if (!callback) callback = createEmptyCallback()
requestVideoEventScheduler.createRequest(options, callback) requestVideoEventScheduler.createRequest(options, callback)
} }
function isMe (host) { function isMe (host) {
return host === constants.CONFIG.WEBSERVER.HOST return host === CONFIG.WEBSERVER.HOST
} }

4
server/lib/index.ts Normal file
View File

@ -0,0 +1,4 @@
export * from './jobs'
export * from './request'
export * from './friends'
export * from './oauth-model'

View File

@ -1,7 +0,0 @@
'use strict'
const videoTranscoder = require('./video-transcoder')
module.exports = {
videoTranscoder
}

View File

@ -0,0 +1,9 @@
import * as videoTranscoder from './video-transcoder'
const jobHandlers = {
videoTranscoder
}
export {
jobHandlers
}

View File

@ -1,16 +1,6 @@
'use strict'
const db = require('../../../initializers/database') const db = require('../../../initializers/database')
const logger = require('../../../helpers/logger') import { logger } from '../../../helpers'
const friends = require('../../../lib/friends') import { addVideoToFriends } from '../../../lib'
const VideoTranscoderHandler = {
process,
onError,
onSuccess
}
// ---------------------------------------------------------------------------
function process (data, callback) { function process (data, callback) {
db.Video.loadAndPopulateAuthorAndPodAndTags(data.id, function (err, video) { db.Video.loadAndPopulateAuthorAndPodAndTags(data.id, function (err, video) {
@ -34,10 +24,14 @@ function onSuccess (data, jobId, video, callback) {
if (err) return callback(err) if (err) return callback(err)
// Now we'll add the video's meta data to our friends // Now we'll add the video's meta data to our friends
friends.addVideoToFriends(remoteVideo, null, callback) addVideoToFriends(remoteVideo, null, callback)
}) })
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = VideoTranscoderHandler export {
process,
onError,
onSuccess
}

1
server/lib/jobs/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './job-scheduler'

View File

@ -1,129 +0,0 @@
'use strict'
const forever = require('async/forever')
const queue = require('async/queue')
const constants = require('../../initializers/constants')
const db = require('../../initializers/database')
const logger = require('../../helpers/logger')
const jobHandlers = require('./handlers')
const jobScheduler = {
activate,
createJob
}
function activate () {
const limit = constants.JOBS_FETCH_LIMIT_PER_CYCLE
logger.info('Jobs scheduler activated.')
const jobsQueue = queue(processJob)
// Finish processing jobs from a previous start
const state = constants.JOB_STATES.PROCESSING
db.Job.listWithLimit(limit, state, function (err, jobs) {
enqueueJobs(err, jobsQueue, jobs)
forever(
function (next) {
if (jobsQueue.length() !== 0) {
// Finish processing the queue first
return setTimeout(next, constants.JOBS_FETCHING_INTERVAL)
}
const state = constants.JOB_STATES.PENDING
db.Job.listWithLimit(limit, state, function (err, jobs) {
if (err) {
logger.error('Cannot list pending jobs.', { error: err })
} else {
jobs.forEach(function (job) {
jobsQueue.push(job)
})
}
// Optimization: we could use "drain" from queue object
return setTimeout(next, constants.JOBS_FETCHING_INTERVAL)
})
}
)
})
}
// ---------------------------------------------------------------------------
module.exports = jobScheduler
// ---------------------------------------------------------------------------
function enqueueJobs (err, jobsQueue, jobs) {
if (err) {
logger.error('Cannot list pending jobs.', { error: err })
} else {
jobs.forEach(function (job) {
jobsQueue.push(job)
})
}
}
function createJob (transaction, handlerName, handlerInputData, callback) {
const createQuery = {
state: constants.JOB_STATES.PENDING,
handlerName,
handlerInputData
}
const options = { transaction }
db.Job.create(createQuery, options).asCallback(callback)
}
function processJob (job, callback) {
const jobHandler = jobHandlers[job.handlerName]
logger.info('Processing job %d with handler %s.', job.id, job.handlerName)
job.state = constants.JOB_STATES.PROCESSING
job.save().asCallback(function (err) {
if (err) return cannotSaveJobError(err, callback)
if (jobHandler === undefined) {
logger.error('Unknown job handler for job %s.', jobHandler.handlerName)
return callback()
}
return jobHandler.process(job.handlerInputData, function (err, result) {
if (err) {
logger.error('Error in job handler %s.', job.handlerName, { error: err })
return onJobError(jobHandler, job, result, callback)
}
return onJobSuccess(jobHandler, job, result, callback)
})
})
}
function onJobError (jobHandler, job, jobResult, callback) {
job.state = constants.JOB_STATES.ERROR
job.save().asCallback(function (err) {
if (err) return cannotSaveJobError(err, callback)
return jobHandler.onError(err, job.id, jobResult, callback)
})
}
function onJobSuccess (jobHandler, job, jobResult, callback) {
job.state = constants.JOB_STATES.SUCCESS
job.save().asCallback(function (err) {
if (err) return cannotSaveJobError(err, callback)
return jobHandler.onSuccess(err, job.id, jobResult, callback)
})
}
function cannotSaveJobError (err, callback) {
logger.error('Cannot save new job state.', { error: err })
return callback(err)
}

View File

@ -0,0 +1,137 @@
import { forever, queue } from 'async'
const db = require('../../initializers/database')
import {
JOBS_FETCHING_INTERVAL,
JOBS_FETCH_LIMIT_PER_CYCLE,
JOB_STATES
} from '../../initializers'
import { logger } from '../../helpers'
import { jobHandlers } from './handlers'
class JobScheduler {
private static instance: JobScheduler
private constructor () { }
static get Instance () {
return this.instance || (this.instance = new this())
}
activate () {
const limit = JOBS_FETCH_LIMIT_PER_CYCLE
logger.info('Jobs scheduler activated.')
const jobsQueue = queue(this.processJob)
// Finish processing jobs from a previous start
const state = JOB_STATES.PROCESSING
db.Job.listWithLimit(limit, state, (err, jobs) => {
this.enqueueJobs(err, jobsQueue, jobs)
forever(
next => {
if (jobsQueue.length() !== 0) {
// Finish processing the queue first
return setTimeout(next, JOBS_FETCHING_INTERVAL)
}
const state = JOB_STATES.PENDING
db.Job.listWithLimit(limit, state, (err, jobs) => {
if (err) {
logger.error('Cannot list pending jobs.', { error: err })
} else {
jobs.forEach(job => {
jobsQueue.push(job)
})
}
// Optimization: we could use "drain" from queue object
return setTimeout(next, JOBS_FETCHING_INTERVAL)
})
},
err => { logger.error('Error in job scheduler queue.', { error: err }) }
)
})
}
createJob (transaction, handlerName, handlerInputData, callback) {
const createQuery = {
state: JOB_STATES.PENDING,
handlerName,
handlerInputData
}
const options = { transaction }
db.Job.create(createQuery, options).asCallback(callback)
}
private enqueueJobs (err, jobsQueue, jobs) {
if (err) {
logger.error('Cannot list pending jobs.', { error: err })
} else {
jobs.forEach(job => {
jobsQueue.push(job)
})
}
}
private processJob (job, callback) {
const jobHandler = jobHandlers[job.handlerName]
logger.info('Processing job %d with handler %s.', job.id, job.handlerName)
job.state = JOB_STATES.PROCESSING
job.save().asCallback(err => {
if (err) return this.cannotSaveJobError(err, callback)
if (jobHandler === undefined) {
logger.error('Unknown job handler for job %s.', jobHandler.handlerName)
return callback()
}
return jobHandler.process(job.handlerInputData, (err, result) => {
if (err) {
logger.error('Error in job handler %s.', job.handlerName, { error: err })
return this.onJobError(jobHandler, job, result, callback)
}
return this.onJobSuccess(jobHandler, job, result, callback)
})
})
}
private onJobError (jobHandler, job, jobResult, callback) {
job.state = JOB_STATES.ERROR
job.save().asCallback(err => {
if (err) return this.cannotSaveJobError(err, callback)
return jobHandler.onError(err, job.id, jobResult, callback)
})
}
private onJobSuccess (jobHandler, job, jobResult, callback) {
job.state = JOB_STATES.SUCCESS
job.save().asCallback(err => {
if (err) return this.cannotSaveJobError(err, callback)
return jobHandler.onSuccess(err, job.id, jobResult, callback)
})
}
private cannotSaveJobError (err, callback) {
logger.error('Cannot save new job state.', { error: err })
return callback(err)
}
}
// ---------------------------------------------------------------------------
export {
JobScheduler
}

View File

@ -1,15 +1,5 @@
const db = require('../initializers/database') const db = require('../initializers/database')
const logger = require('../helpers/logger') import { logger } from '../helpers'
// See https://github.com/oauthjs/node-oauth2-server/wiki/Model-specification for the model specifications
const OAuthModel = {
getAccessToken,
getClient,
getRefreshToken,
getUser,
revokeToken,
saveToken
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -94,4 +84,12 @@ function saveToken (token, client, user) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = OAuthModel // See https://github.com/oauthjs/node-oauth2-server/wiki/Model-specification for the model specifications
export {
getAccessToken,
getClient,
getRefreshToken,
getUser,
revokeToken,
saveToken
}

View File

@ -1,19 +1,31 @@
'use strict' import { eachLimit } from 'async/eachLimit'
const eachLimit = require('async/eachLimit')
const constants = require('../../initializers/constants')
const db = require('../../initializers/database') const db = require('../../initializers/database')
const logger = require('../../helpers/logger') import { logger, makeSecureRequest } from '../../helpers'
const requests = require('../../helpers/requests') import {
API_VERSION,
REQUESTS_IN_PARALLEL,
REQUESTS_INTERVAL
} from '../../initializers'
module.exports = class BaseRequestScheduler { abstract class BaseRequestScheduler {
constructor (options) { protected lastRequestTimestamp: number
protected timer: NodeJS.Timer
protected requestInterval: number
protected limitPods: number
protected limitPerPod: number
protected description: string
constructor () {
this.lastRequestTimestamp = 0 this.lastRequestTimestamp = 0
this.timer = null this.timer = null
this.requestInterval = constants.REQUESTS_INTERVAL this.requestInterval = REQUESTS_INTERVAL
} }
abstract getRequestModel ()
abstract getRequestToPodModel ()
abstract buildRequestObjects (requests: any)
activate () { activate () {
logger.info('Requests scheduler activated.') logger.info('Requests scheduler activated.')
this.lastRequestTimestamp = Date.now() this.lastRequestTimestamp = Date.now()
@ -38,30 +50,34 @@ module.exports = class BaseRequestScheduler {
remainingMilliSeconds () { remainingMilliSeconds () {
if (this.timer === null) return -1 if (this.timer === null) return -1
return constants.REQUESTS_INTERVAL - (Date.now() - this.lastRequestTimestamp) return REQUESTS_INTERVAL - (Date.now() - this.lastRequestTimestamp)
} }
remainingRequestsCount (callback) { remainingRequestsCount (callback) {
return this.getRequestModel().countTotalRequests(callback) return this.getRequestModel().countTotalRequests(callback)
} }
flush (callback) {
this.getRequestModel().removeAll(callback)
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Make a requests to friends of a certain type // Make a requests to friends of a certain type
makeRequest (toPod, requestEndpoint, requestsToMake, callback) { protected makeRequest (toPod, requestEndpoint, requestsToMake, callback) {
if (!callback) callback = function () {} if (!callback) callback = function () { /* empty */ }
const params = { const params = {
toPod: toPod, toPod: toPod,
sign: true, // Prove our identity sign: true, // Prove our identity
method: 'POST', method: 'POST',
path: '/api/' + constants.API_VERSION + '/remote/' + requestEndpoint, path: '/api/' + API_VERSION + '/remote/' + requestEndpoint,
data: requestsToMake // Requests we need to make data: requestsToMake // Requests we need to make
} }
// Make multiple retry requests to all of pods // Make multiple retry requests to all of pods
// The function fire some useful callbacks // The function fire some useful callbacks
requests.makeSecureRequest(params, (err, res) => { makeSecureRequest(params, (err, res) => {
if (err || (res.statusCode !== 200 && res.statusCode !== 201 && res.statusCode !== 204)) { if (err || (res.statusCode !== 200 && res.statusCode !== 201 && res.statusCode !== 204)) {
err = err ? err.message : 'Status code not 20x : ' + res.statusCode err = err ? err.message : 'Status code not 20x : ' + res.statusCode
logger.error('Error sending secure request to %s pod.', toPod.host, { error: err }) logger.error('Error sending secure request to %s pod.', toPod.host, { error: err })
@ -74,7 +90,7 @@ module.exports = class BaseRequestScheduler {
} }
// Make all the requests of the scheduler // Make all the requests of the scheduler
makeRequests () { protected makeRequests () {
this.getRequestModel().listWithLimitAndRandom(this.limitPods, this.limitPerPod, (err, requests) => { this.getRequestModel().listWithLimitAndRandom(this.limitPods, this.limitPerPod, (err, requests) => {
if (err) { if (err) {
logger.error('Cannot get the list of "%s".', this.description, { err: err }) logger.error('Cannot get the list of "%s".', this.description, { err: err })
@ -95,7 +111,7 @@ module.exports = class BaseRequestScheduler {
const goodPods = [] const goodPods = []
const badPods = [] const badPods = []
eachLimit(Object.keys(requestsToMakeGrouped), constants.REQUESTS_IN_PARALLEL, (hashKey, callbackEach) => { eachLimit(Object.keys(requestsToMakeGrouped), REQUESTS_IN_PARALLEL, (hashKey, callbackEach) => {
const requestToMake = requestsToMakeGrouped[hashKey] const requestToMake = requestsToMakeGrouped[hashKey]
const toPod = requestToMake.toPod const toPod = requestToMake.toPod
@ -122,15 +138,17 @@ module.exports = class BaseRequestScheduler {
}) })
} }
flush (callback) { protected afterRequestHook () {
this.getRequestModel().removeAll(callback)
}
afterRequestHook () {
// Nothing to do, let children reimplement it // Nothing to do, let children reimplement it
} }
afterRequestsHook () { protected afterRequestsHook () {
// Nothing to do, let children reimplement it // Nothing to do, let children reimplement it
} }
} }
// ---------------------------------------------------------------------------
export {
BaseRequestScheduler
}

View File

@ -0,0 +1,3 @@
export * from './request-scheduler'
export * from './request-video-event-scheduler'
export * from './request-video-qadu-scheduler'

View File

@ -1,17 +1,18 @@
'use strict'
const constants = require('../../initializers/constants')
const BaseRequestScheduler = require('./base-request-scheduler')
const db = require('../../initializers/database') const db = require('../../initializers/database')
const logger = require('../../helpers/logger') import { BaseRequestScheduler } from './base-request-scheduler'
import { logger } from '../../helpers'
import {
REQUESTS_LIMIT_PODS,
REQUESTS_LIMIT_PER_POD
} from '../../initializers'
module.exports = class RequestScheduler extends BaseRequestScheduler { class RequestScheduler extends BaseRequestScheduler {
constructor () { constructor () {
super() super()
// We limit the size of the requests // We limit the size of the requests
this.limitPods = constants.REQUESTS_LIMIT_PODS this.limitPods = REQUESTS_LIMIT_PODS
this.limitPerPod = constants.REQUESTS_LIMIT_PER_POD this.limitPerPod = REQUESTS_LIMIT_PER_POD
this.description = 'requests' this.description = 'requests'
} }
@ -95,3 +96,9 @@ module.exports = class RequestScheduler extends BaseRequestScheduler {
}) })
} }
} }
// ---------------------------------------------------------------------------
export {
RequestScheduler
}

View File

@ -1,16 +1,18 @@
'use strict'
const BaseRequestScheduler = require('./base-request-scheduler')
const constants = require('../../initializers/constants')
const db = require('../../initializers/database') const db = require('../../initializers/database')
import { BaseRequestScheduler } from './base-request-scheduler'
import {
REQUESTS_VIDEO_EVENT_LIMIT_PODS,
REQUESTS_VIDEO_EVENT_LIMIT_PER_POD,
REQUEST_VIDEO_EVENT_ENDPOINT
} from '../../initializers'
module.exports = class RequestVideoEventScheduler extends BaseRequestScheduler { class RequestVideoEventScheduler extends BaseRequestScheduler {
constructor () { constructor () {
super() super()
// We limit the size of the requests // We limit the size of the requests
this.limitPods = constants.REQUESTS_VIDEO_EVENT_LIMIT_PODS this.limitPods = REQUESTS_VIDEO_EVENT_LIMIT_PODS
this.limitPerPod = constants.REQUESTS_VIDEO_EVENT_LIMIT_PER_POD this.limitPerPod = REQUESTS_VIDEO_EVENT_LIMIT_PER_POD
this.description = 'video event requests' this.description = 'video event requests'
} }
@ -45,7 +47,7 @@ module.exports = class RequestVideoEventScheduler extends BaseRequestScheduler {
if (!requestsToMakeGrouped[toPodId]) { if (!requestsToMakeGrouped[toPodId]) {
requestsToMakeGrouped[toPodId] = { requestsToMakeGrouped[toPodId] = {
toPod: eventToProcess.pod, toPod: eventToProcess.pod,
endpoint: constants.REQUEST_VIDEO_EVENT_ENDPOINT, endpoint: REQUEST_VIDEO_EVENT_ENDPOINT,
ids: [], // request ids, to delete them from the DB in the future ids: [], // request ids, to delete them from the DB in the future
datas: [] // requests data datas: [] // requests data
} }
@ -94,7 +96,7 @@ module.exports = class RequestVideoEventScheduler extends BaseRequestScheduler {
if (count === undefined) count = 1 if (count === undefined) count = 1
const dbRequestOptions = {} const dbRequestOptions: { transaction?: any } = {}
if (transaction) dbRequestOptions.transaction = transaction if (transaction) dbRequestOptions.transaction = transaction
const createQuery = { const createQuery = {
@ -106,3 +108,9 @@ module.exports = class RequestVideoEventScheduler extends BaseRequestScheduler {
return db.RequestVideoEvent.create(createQuery, dbRequestOptions).asCallback(callback) return db.RequestVideoEvent.create(createQuery, dbRequestOptions).asCallback(callback)
} }
} }
// ---------------------------------------------------------------------------
export {
RequestVideoEventScheduler
}

View File

@ -1,17 +1,20 @@
'use strict'
const BaseRequestScheduler = require('./base-request-scheduler')
const constants = require('../../initializers/constants')
const db = require('../../initializers/database') const db = require('../../initializers/database')
const logger = require('../../helpers/logger') import { BaseRequestScheduler } from './base-request-scheduler'
import { logger } from '../../helpers'
import {
REQUESTS_VIDEO_QADU_LIMIT_PODS,
REQUESTS_VIDEO_QADU_LIMIT_PER_POD,
REQUEST_VIDEO_QADU_ENDPOINT,
REQUEST_VIDEO_QADU_TYPES
} from '../../initializers'
module.exports = class RequestVideoQaduScheduler extends BaseRequestScheduler { class RequestVideoQaduScheduler extends BaseRequestScheduler {
constructor () { constructor () {
super() super()
// We limit the size of the requests // We limit the size of the requests
this.limitPods = constants.REQUESTS_VIDEO_QADU_LIMIT_PODS this.limitPods = REQUESTS_VIDEO_QADU_LIMIT_PODS
this.limitPerPod = constants.REQUESTS_VIDEO_QADU_LIMIT_PER_POD this.limitPerPod = REQUESTS_VIDEO_QADU_LIMIT_PER_POD
this.description = 'video QADU requests' this.description = 'video QADU requests'
} }
@ -37,7 +40,7 @@ module.exports = class RequestVideoQaduScheduler extends BaseRequestScheduler {
if (!requestsToMakeGrouped[hashKey]) { if (!requestsToMakeGrouped[hashKey]) {
requestsToMakeGrouped[hashKey] = { requestsToMakeGrouped[hashKey] = {
toPod: pod, toPod: pod,
endpoint: constants.REQUEST_VIDEO_QADU_ENDPOINT, endpoint: REQUEST_VIDEO_QADU_ENDPOINT,
ids: [], // request ids, to delete them from the DB in the future ids: [], // request ids, to delete them from the DB in the future
datas: [], // requests data datas: [], // requests data
videos: {} videos: {}
@ -49,15 +52,15 @@ module.exports = class RequestVideoQaduScheduler extends BaseRequestScheduler {
if (!videoData) videoData = {} if (!videoData) videoData = {}
switch (request.type) { switch (request.type) {
case constants.REQUEST_VIDEO_QADU_TYPES.LIKES: case REQUEST_VIDEO_QADU_TYPES.LIKES:
videoData.likes = video.likes videoData.likes = video.likes
break break
case constants.REQUEST_VIDEO_QADU_TYPES.DISLIKES: case REQUEST_VIDEO_QADU_TYPES.DISLIKES:
videoData.dislikes = video.dislikes videoData.dislikes = video.dislikes
break break
case constants.REQUEST_VIDEO_QADU_TYPES.VIEWS: case REQUEST_VIDEO_QADU_TYPES.VIEWS:
videoData.views = video.views videoData.views = video.views
break break
@ -99,7 +102,7 @@ module.exports = class RequestVideoQaduScheduler extends BaseRequestScheduler {
const videoId = options.videoId const videoId = options.videoId
const transaction = options.transaction const transaction = options.transaction
const dbRequestOptions = {} const dbRequestOptions: { transaction?: any } = {}
if (transaction) dbRequestOptions.transaction = transaction if (transaction) dbRequestOptions.transaction = transaction
// Send the update to all our friends // Send the update to all our friends
@ -115,3 +118,9 @@ module.exports = class RequestVideoQaduScheduler extends BaseRequestScheduler {
}) })
} }
} }
// ---------------------------------------------------------------------------
export {
RequestVideoQaduScheduler
}

View File

@ -1,11 +1,5 @@
'use strict'
const logger = require('../helpers/logger') const logger = require('../helpers/logger')
const adminMiddleware = {
ensureIsAdmin
}
function ensureIsAdmin (req, res, next) { function ensureIsAdmin (req, res, next) {
const user = res.locals.oauth.token.user const user = res.locals.oauth.token.user
if (user.isAdmin() === false) { if (user.isAdmin() === false) {
@ -18,4 +12,6 @@ function ensureIsAdmin (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = adminMiddleware export {
ensureIsAdmin
}

View File

@ -1,25 +0,0 @@
'use strict'
const adminMiddleware = require('./admin')
const oauthMiddleware = require('./oauth')
const paginationMiddleware = require('./pagination')
const podsMiddleware = require('./pods')
const validatorsMiddleware = require('./validators')
const searchMiddleware = require('./search')
const sortMiddleware = require('./sort')
const secureMiddleware = require('./secure')
const middlewares = {
admin: adminMiddleware,
oauth: oauthMiddleware,
pagination: paginationMiddleware,
pods: podsMiddleware,
search: searchMiddleware,
secure: secureMiddleware,
sort: sortMiddleware,
validators: validatorsMiddleware
}
// ---------------------------------------------------------------------------
module.exports = middlewares

View File

@ -0,0 +1,8 @@
export * from './validators';
export * from './admin';
export * from './oauth';
export * from './pagination';
export * from './pods';
export * from './search';
export * from './secure';
export * from './sort';

View File

@ -1,6 +1,4 @@
'use strict' import OAuthServer = require('express-oauth-server')
const OAuthServer = require('express-oauth-server')
const constants = require('../initializers/constants') const constants = require('../initializers/constants')
const logger = require('../helpers/logger') const logger = require('../helpers/logger')
@ -11,11 +9,6 @@ const oAuthServer = new OAuthServer({
model: require('../lib/oauth-model') model: require('../lib/oauth-model')
}) })
const oAuth = {
authenticate,
token
}
function authenticate (req, res, next) { function authenticate (req, res, next) {
oAuthServer.authenticate()(req, res, function (err) { oAuthServer.authenticate()(req, res, function (err) {
if (err) { if (err) {
@ -35,4 +28,7 @@ function token (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = oAuth export {
authenticate,
token
}

View File

@ -1,14 +1,9 @@
'use strict'
const constants = require('../initializers/constants') const constants = require('../initializers/constants')
const paginationMiddleware = {
setPagination
}
function setPagination (req, res, next) { function setPagination (req, res, next) {
if (!req.query.start) req.query.start = 0 if (!req.query.start) req.query.start = 0
else req.query.start = parseInt(req.query.start, 10) else req.query.start = parseInt(req.query.start, 10)
if (!req.query.count) req.query.count = constants.PAGINATION_COUNT_DEFAULT if (!req.query.count) req.query.count = constants.PAGINATION_COUNT_DEFAULT
else req.query.count = parseInt(req.query.count, 10) else req.query.count = parseInt(req.query.count, 10)
@ -17,4 +12,6 @@ function setPagination (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = paginationMiddleware export {
setPagination
}

View File

@ -2,11 +2,6 @@
const constants = require('../initializers/constants') const constants = require('../initializers/constants')
const podsMiddleware = {
setBodyHostsPort,
setBodyHostPort
}
function setBodyHostsPort (req, res, next) { function setBodyHostsPort (req, res, next) {
if (!req.body.hosts) return next() if (!req.body.hosts) return next()
@ -41,7 +36,10 @@ function setBodyHostPort (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = podsMiddleware export {
setBodyHostsPort,
setBodyHostPort
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1,9 +1,3 @@
'use strict'
const searchMiddleware = {
setVideosSearch
}
function setVideosSearch (req, res, next) { function setVideosSearch (req, res, next) {
if (!req.query.field) req.query.field = 'name' if (!req.query.field) req.query.field = 'name'
@ -12,4 +6,6 @@ function setVideosSearch (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = searchMiddleware export {
setVideosSearch
}

View File

@ -1,13 +1,7 @@
'use strict'
const db = require('../initializers/database') const db = require('../initializers/database')
const logger = require('../helpers/logger') const logger = require('../helpers/logger')
const peertubeCrypto = require('../helpers/peertube-crypto') const peertubeCrypto = require('../helpers/peertube-crypto')
const secureMiddleware = {
checkSignature
}
function checkSignature (req, res, next) { function checkSignature (req, res, next) {
const host = req.body.signature.host const host = req.body.signature.host
db.Pod.loadByHost(host, function (err, pod) { db.Pod.loadByHost(host, function (err, pod) {
@ -49,4 +43,6 @@ function checkSignature (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = secureMiddleware export {
checkSignature
}

View File

@ -1,11 +1,3 @@
'use strict'
const sortMiddleware = {
setUsersSort,
setVideoAbusesSort,
setVideosSort
}
function setUsersSort (req, res, next) { function setUsersSort (req, res, next) {
if (!req.query.sort) req.query.sort = '-createdAt' if (!req.query.sort) req.query.sort = '-createdAt'
@ -26,4 +18,8 @@ function setVideosSort (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = sortMiddleware export {
setUsersSort,
setVideoAbusesSort,
setVideosSort
}

View File

@ -1,21 +0,0 @@
'use strict'
const paginationValidators = require('./pagination')
const podsValidators = require('./pods')
const remoteValidators = require('./remote')
const sortValidators = require('./sort')
const usersValidators = require('./users')
const videosValidators = require('./videos')
const validators = {
pagination: paginationValidators,
pods: podsValidators,
remote: remoteValidators,
sort: sortValidators,
users: usersValidators,
videos: videosValidators
}
// ---------------------------------------------------------------------------
module.exports = validators

View File

@ -0,0 +1,6 @@
export * from './remote'
export * from './pagination'
export * from './pods'
export * from './sort'
export * from './users'
export * from './videos'

View File

@ -1,13 +1,7 @@
'use strict' import { checkErrors } from './utils'
import { logger } from '../../helpers'
const checkErrors = require('./utils').checkErrors function paginationValidator (req, res, next) {
const logger = require('../../helpers/logger')
const validatorsPagination = {
pagination
}
function pagination (req, res, next) {
req.checkQuery('start', 'Should have a number start').optional().isInt() req.checkQuery('start', 'Should have a number start').optional().isInt()
req.checkQuery('count', 'Should have a number count').optional().isInt() req.checkQuery('count', 'Should have a number count').optional().isInt()
@ -18,4 +12,6 @@ function pagination (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = validatorsPagination export {
paginationValidator
}

View File

@ -1,20 +1,13 @@
'use strict'
const checkErrors = require('./utils').checkErrors
const constants = require('../../initializers/constants')
const db = require('../../initializers/database') const db = require('../../initializers/database')
const friends = require('../../lib/friends') import { checkErrors } from './utils'
const logger = require('../../helpers/logger') import { logger } from '../../helpers'
const utils = require('../../helpers/utils') import { CONFIG } from '../../initializers'
import { hasFriends } from '../../lib'
import { isTestInstance } from '../../helpers'
const validatorsPod = { function makeFriendsValidator (req, res, next) {
makeFriends,
podsAdd
}
function makeFriends (req, res, next) {
// Force https if the administrator wants to make friends // Force https if the administrator wants to make friends
if (utils.isTestInstance() === false && constants.CONFIG.WEBSERVER.SCHEME === 'http') { if (isTestInstance() === false && CONFIG.WEBSERVER.SCHEME === 'http') {
return res.status(400).send('Cannot make friends with a non HTTPS webserver.') return res.status(400).send('Cannot make friends with a non HTTPS webserver.')
} }
@ -23,13 +16,13 @@ function makeFriends (req, res, next) {
logger.debug('Checking makeFriends parameters', { parameters: req.body }) logger.debug('Checking makeFriends parameters', { parameters: req.body })
checkErrors(req, res, function () { checkErrors(req, res, function () {
friends.hasFriends(function (err, hasFriends) { hasFriends(function (err, heHasFriends) {
if (err) { if (err) {
logger.error('Cannot know if we have friends.', { error: err }) logger.error('Cannot know if we have friends.', { error: err })
res.sendStatus(500) res.sendStatus(500)
} }
if (hasFriends === true) { if (heHasFriends === true) {
// We need to quit our friends before make new ones // We need to quit our friends before make new ones
return res.sendStatus(409) return res.sendStatus(409)
} }
@ -39,7 +32,7 @@ function makeFriends (req, res, next) {
}) })
} }
function podsAdd (req, res, next) { function podsAddValidator (req, res, next) {
req.checkBody('host', 'Should have a host').isHostValid() req.checkBody('host', 'Should have a host').isHostValid()
req.checkBody('email', 'Should have an email').isEmail() req.checkBody('email', 'Should have an email').isEmail()
req.checkBody('publicKey', 'Should have a public key').notEmpty() req.checkBody('publicKey', 'Should have a public key').notEmpty()
@ -64,4 +57,7 @@ function podsAdd (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = validatorsPod export {
makeFriendsValidator,
podsAddValidator
}

View File

@ -1,13 +0,0 @@
'use strict'
const remoteSignatureValidators = require('./signature')
const remoteVideosValidators = require('./videos')
const validators = {
signature: remoteSignatureValidators,
videos: remoteVideosValidators
}
// ---------------------------------------------------------------------------
module.exports = validators

View File

@ -0,0 +1,2 @@
export * from './signature'
export * from './videos'

View File

@ -1,13 +1,7 @@
'use strict' import { logger } from '../../../helpers'
import { checkErrors } from '../utils'
const checkErrors = require('../utils').checkErrors function signatureValidator (req, res, next) {
const logger = require('../../../helpers/logger')
const validatorsRemoteSignature = {
signature
}
function signature (req, res, next) {
req.checkBody('signature.host', 'Should have a signature host').isURL() req.checkBody('signature.host', 'Should have a signature host').isURL()
req.checkBody('signature.signature', 'Should have a signature').notEmpty() req.checkBody('signature.signature', 'Should have a signature').notEmpty()
@ -18,4 +12,6 @@ function signature (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = validatorsRemoteSignature export {
signatureValidator
}

View File

@ -1,15 +1,7 @@
'use strict' import { logger } from '../../../helpers'
import { checkErrors } from '../utils'
const checkErrors = require('../utils').checkErrors function remoteVideosValidator (req, res, next) {
const logger = require('../../../helpers/logger')
const validatorsRemoteVideos = {
remoteVideos,
remoteQaduVideos,
remoteEventsVideos
}
function remoteVideos (req, res, next) {
req.checkBody('data').isEachRemoteRequestVideosValid() req.checkBody('data').isEachRemoteRequestVideosValid()
logger.debug('Checking remoteVideos parameters', { parameters: req.body }) logger.debug('Checking remoteVideos parameters', { parameters: req.body })
@ -17,7 +9,7 @@ function remoteVideos (req, res, next) {
checkErrors(req, res, next) checkErrors(req, res, next)
} }
function remoteQaduVideos (req, res, next) { function remoteQaduVideosValidator (req, res, next) {
req.checkBody('data').isEachRemoteRequestVideosQaduValid() req.checkBody('data').isEachRemoteRequestVideosQaduValid()
logger.debug('Checking remoteQaduVideos parameters', { parameters: req.body }) logger.debug('Checking remoteQaduVideos parameters', { parameters: req.body })
@ -25,13 +17,18 @@ function remoteQaduVideos (req, res, next) {
checkErrors(req, res, next) checkErrors(req, res, next)
} }
function remoteEventsVideos (req, res, next) { function remoteEventsVideosValidator (req, res, next) {
req.checkBody('data').isEachRemoteRequestVideosEventsValid() req.checkBody('data').isEachRemoteRequestVideosEventsValid()
logger.debug('Checking remoteEventsVideos parameters', { parameters: req.body }) logger.debug('Checking remoteEventsVideos parameters', { parameters: req.body })
checkErrors(req, res, next) checkErrors(req, res, next)
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = validatorsRemoteVideos export {
remoteVideosValidator,
remoteQaduVideosValidator,
remoteEventsVideosValidator
}

View File

@ -1,35 +1,31 @@
'use strict' import { checkErrors } from './utils'
import { logger } from '../../helpers'
const checkErrors = require('./utils').checkErrors import { SORTABLE_COLUMNS } from '../../initializers'
const constants = require('../../initializers/constants')
const logger = require('../../helpers/logger')
const validatorsSort = {
usersSort,
videoAbusesSort,
videosSort
}
// Initialize constants here for better performances // Initialize constants here for better performances
const SORTABLE_USERS_COLUMNS = createSortableColumns(constants.SORTABLE_COLUMNS.USERS) const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS)
const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(constants.SORTABLE_COLUMNS.VIDEO_ABUSES) const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES)
const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(constants.SORTABLE_COLUMNS.VIDEOS) const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS)
function usersSort (req, res, next) { function usersSortValidator (req, res, next) {
checkSort(req, res, next, SORTABLE_USERS_COLUMNS) checkSort(req, res, next, SORTABLE_USERS_COLUMNS)
} }
function videoAbusesSort (req, res, next) { function videoAbusesSortValidator (req, res, next) {
checkSort(req, res, next, SORTABLE_VIDEO_ABUSES_COLUMNS) checkSort(req, res, next, SORTABLE_VIDEO_ABUSES_COLUMNS)
} }
function videosSort (req, res, next) { function videosSortValidator (req, res, next) {
checkSort(req, res, next, SORTABLE_VIDEOS_COLUMNS) checkSort(req, res, next, SORTABLE_VIDEOS_COLUMNS)
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = validatorsSort export {
usersSortValidator,
videoAbusesSortValidator,
videosSortValidator
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1,17 +1,8 @@
'use strict'
const checkErrors = require('./utils').checkErrors
const db = require('../../initializers/database') const db = require('../../initializers/database')
const logger = require('../../helpers/logger') import { checkErrors } from './utils'
import { logger } from '../../helpers'
const validatorsUsers = { function usersAddValidator (req, res, next) {
usersAdd,
usersRemove,
usersUpdate,
usersVideoRating
}
function usersAdd (req, res, next) {
req.checkBody('username', 'Should have a valid username').isUserUsernameValid() req.checkBody('username', 'Should have a valid username').isUserUsernameValid()
req.checkBody('password', 'Should have a valid password').isUserPasswordValid() req.checkBody('password', 'Should have a valid password').isUserPasswordValid()
req.checkBody('email', 'Should have a valid email').isEmail() req.checkBody('email', 'Should have a valid email').isEmail()
@ -32,7 +23,7 @@ function usersAdd (req, res, next) {
}) })
} }
function usersRemove (req, res, next) { function usersRemoveValidator (req, res, next) {
req.checkParams('id', 'Should have a valid id').notEmpty().isInt() req.checkParams('id', 'Should have a valid id').notEmpty().isInt()
logger.debug('Checking usersRemove parameters', { parameters: req.params }) logger.debug('Checking usersRemove parameters', { parameters: req.params })
@ -53,7 +44,7 @@ function usersRemove (req, res, next) {
}) })
} }
function usersUpdate (req, res, next) { function usersUpdateValidator (req, res, next) {
req.checkParams('id', 'Should have a valid id').notEmpty().isInt() req.checkParams('id', 'Should have a valid id').notEmpty().isInt()
// Add old password verification // Add old password verification
req.checkBody('password', 'Should have a valid password').optional().isUserPasswordValid() req.checkBody('password', 'Should have a valid password').optional().isUserPasswordValid()
@ -64,7 +55,7 @@ function usersUpdate (req, res, next) {
checkErrors(req, res, next) checkErrors(req, res, next)
} }
function usersVideoRating (req, res, next) { function usersVideoRatingValidator (req, res, next) {
req.checkParams('videoId', 'Should have a valid video id').notEmpty().isUUID(4) req.checkParams('videoId', 'Should have a valid video id').notEmpty().isUUID(4)
logger.debug('Checking usersVideoRating parameters', { parameters: req.params }) logger.debug('Checking usersVideoRating parameters', { parameters: req.params })
@ -85,4 +76,9 @@ function usersVideoRating (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = validatorsUsers export {
usersAddValidator,
usersRemoveValidator,
usersUpdateValidator,
usersVideoRatingValidator
}

View File

@ -1,20 +1,14 @@
'use strict' import { inspect } from 'util'
const util = require('util') import { logger } from '../../helpers'
const logger = require('../../helpers/logger') function checkErrors (req, res, next, statusCode?) {
const validatorsUtils = {
checkErrors
}
function checkErrors (req, res, next, statusCode) {
if (statusCode === undefined) statusCode = 400 if (statusCode === undefined) statusCode = 400
const errors = req.validationErrors() const errors = req.validationErrors()
if (errors) { if (errors) {
logger.warn('Incorrect request parameters', { path: req.originalUrl, err: errors }) logger.warn('Incorrect request parameters', { path: req.originalUrl, err: errors })
return res.status(statusCode).send('There have been validation errors: ' + util.inspect(errors)) return res.status(statusCode).send('There have been validation errors: ' + inspect(errors))
} }
return next() return next()
@ -22,4 +16,6 @@ function checkErrors (req, res, next, statusCode) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = validatorsUtils export {
checkErrors
}

View File

@ -1,26 +1,9 @@
'use strict'
const checkErrors = require('./utils').checkErrors
const constants = require('../../initializers/constants')
const customVideosValidators = require('../../helpers/custom-validators').videos
const db = require('../../initializers/database') const db = require('../../initializers/database')
const logger = require('../../helpers/logger') import { checkErrors } from './utils'
import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers'
import { logger, isVideoDurationValid } from '../../helpers'
const validatorsVideos = { function videosAddValidator (req, res, next) {
videosAdd,
videosUpdate,
videosGet,
videosRemove,
videosSearch,
videoAbuseReport,
videoRate,
videosBlacklist
}
function videosAdd (req, res, next) {
req.checkBody('videofile', 'Should have a valid file').isVideoFile(req.files) req.checkBody('videofile', 'Should have a valid file').isVideoFile(req.files)
req.checkBody('name', 'Should have a valid name').isVideoNameValid() req.checkBody('name', 'Should have a valid name').isVideoNameValid()
req.checkBody('category', 'Should have a valid category').isVideoCategoryValid() req.checkBody('category', 'Should have a valid category').isVideoCategoryValid()
@ -40,8 +23,8 @@ function videosAdd (req, res, next) {
return res.status(400).send('Cannot retrieve metadata of the file.') return res.status(400).send('Cannot retrieve metadata of the file.')
} }
if (!customVideosValidators.isVideoDurationValid(duration)) { if (!isVideoDurationValid(duration)) {
return res.status(400).send('Duration of the video file is too big (max: ' + constants.CONSTRAINTS_FIELDS.VIDEOS.DURATION.max + 's).') return res.status(400).send('Duration of the video file is too big (max: ' + CONSTRAINTS_FIELDS.VIDEOS.DURATION.max + 's).')
} }
videoFile.duration = duration videoFile.duration = duration
@ -50,7 +33,7 @@ function videosAdd (req, res, next) {
}) })
} }
function videosUpdate (req, res, next) { function videosUpdateValidator (req, res, next) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4)
req.checkBody('name', 'Should have a valid name').optional().isVideoNameValid() req.checkBody('name', 'Should have a valid name').optional().isVideoNameValid()
req.checkBody('category', 'Should have a valid category').optional().isVideoCategoryValid() req.checkBody('category', 'Should have a valid category').optional().isVideoCategoryValid()
@ -78,7 +61,7 @@ function videosUpdate (req, res, next) {
}) })
} }
function videosGet (req, res, next) { function videosGetValidator (req, res, next) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4)
logger.debug('Checking videosGet parameters', { parameters: req.params }) logger.debug('Checking videosGet parameters', { parameters: req.params })
@ -88,7 +71,7 @@ function videosGet (req, res, next) {
}) })
} }
function videosRemove (req, res, next) { function videosRemoveValidator (req, res, next) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4)
logger.debug('Checking videosRemove parameters', { parameters: req.params }) logger.debug('Checking videosRemove parameters', { parameters: req.params })
@ -105,8 +88,8 @@ function videosRemove (req, res, next) {
}) })
} }
function videosSearch (req, res, next) { function videosSearchValidator (req, res, next) {
const searchableColumns = constants.SEARCHABLE_COLUMNS.VIDEOS const searchableColumns = SEARCHABLE_COLUMNS.VIDEOS
req.checkParams('value', 'Should have a valid search').notEmpty() req.checkParams('value', 'Should have a valid search').notEmpty()
req.checkQuery('field', 'Should have correct searchable column').optional().isIn(searchableColumns) req.checkQuery('field', 'Should have correct searchable column').optional().isIn(searchableColumns)
@ -115,7 +98,7 @@ function videosSearch (req, res, next) {
checkErrors(req, res, next) checkErrors(req, res, next)
} }
function videoAbuseReport (req, res, next) { function videoAbuseReportValidator (req, res, next) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4)
req.checkBody('reason', 'Should have a valid reason').isVideoAbuseReasonValid() req.checkBody('reason', 'Should have a valid reason').isVideoAbuseReasonValid()
@ -126,7 +109,7 @@ function videoAbuseReport (req, res, next) {
}) })
} }
function videoRate (req, res, next) { function videoRateValidator (req, res, next) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4)
req.checkBody('rating', 'Should have a valid rate type').isVideoRatingTypeValid() req.checkBody('rating', 'Should have a valid rate type').isVideoRatingTypeValid()
@ -137,7 +120,7 @@ function videoRate (req, res, next) {
}) })
} }
function videosBlacklist (req, res, next) { function videosBlacklistValidator (req, res, next) {
req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4)
logger.debug('Checking videosBlacklist parameters', { parameters: req.params }) logger.debug('Checking videosBlacklist parameters', { parameters: req.params })
@ -151,7 +134,19 @@ function videosBlacklist (req, res, next) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
module.exports = validatorsVideos export {
videosAddValidator,
videosUpdateValidator,
videosGetValidator,
videosRemoveValidator,
videosSearchValidator,
videoAbuseReportValidator,
videoRateValidator,
videosBlacklistValidator
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1,5 +1,3 @@
'use strict'
module.exports = function (sequelize, DataTypes) { module.exports = function (sequelize, DataTypes) {
const Application = sequelize.define('Application', const Application = sequelize.define('Application',
{ {
@ -38,7 +36,7 @@ function loadMigrationVersion (callback) {
} }
function updateMigrationVersion (newVersion, transaction, callback) { function updateMigrationVersion (newVersion, transaction, callback) {
const options = { const options: { where?: any, transaction?: any } = {
where: {} where: {}
} }

View File

@ -1,6 +1,4 @@
'use strict' import { isUserUsernameValid } from '../helpers'
const customUsersValidators = require('../helpers/custom-validators').users
module.exports = function (sequelize, DataTypes) { module.exports = function (sequelize, DataTypes) {
const Author = sequelize.define('Author', const Author = sequelize.define('Author',
@ -10,7 +8,7 @@ module.exports = function (sequelize, DataTypes) {
allowNull: false, allowNull: false,
validate: { validate: {
usernameValid: function (value) { usernameValid: function (value) {
const res = customUsersValidators.isUserUsernameValid(value) const res = isUserUsernameValid(value)
if (res === false) throw new Error('Username is not valid.') if (res === false) throw new Error('Username is not valid.')
} }
} }
@ -76,7 +74,7 @@ function findOrCreateAuthor (name, podId, userId, transaction, callback) {
userId userId
} }
const query = { const query: any = {
where: author, where: author,
defaults: author defaults: author
} }

View File

@ -1,8 +1,6 @@
'use strict' import { values } from 'lodash'
const values = require('lodash/values') import { JOB_STATES } from '../initializers'
const constants = require('../initializers/constants')
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -10,7 +8,7 @@ module.exports = function (sequelize, DataTypes) {
const Job = sequelize.define('Job', const Job = sequelize.define('Job',
{ {
state: { state: {
type: DataTypes.ENUM(values(constants.JOB_STATES)), type: DataTypes.ENUM(values(JOB_STATES)),
allowNull: false allowNull: false
}, },
handlerName: { handlerName: {

View File

@ -1,5 +1,3 @@
'use strict'
module.exports = function (sequelize, DataTypes) { module.exports = function (sequelize, DataTypes) {
const OAuthClient = sequelize.define('OAuthClient', const OAuthClient = sequelize.define('OAuthClient',
{ {

View File

@ -1,6 +1,4 @@
'use strict' import { logger } from '../helpers'
const logger = require('../helpers/logger')
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -1,12 +1,8 @@
'use strict' import { each, waterfall } from 'async'
import { map } from 'lodash'
const each = require('async/each') import { FRIEND_SCORE, PODS_SCORE } from '../initializers'
const map = require('lodash/map') import { logger, isHostValid } from '../helpers'
const waterfall = require('async/waterfall')
const constants = require('../initializers/constants')
const logger = require('../helpers/logger')
const customPodsValidators = require('../helpers/custom-validators').pods
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -18,7 +14,7 @@ module.exports = function (sequelize, DataTypes) {
allowNull: false, allowNull: false,
validate: { validate: {
isHost: function (value) { isHost: function (value) {
const res = customPodsValidators.isHostValid(value) const res = isHostValid(value)
if (res === false) throw new Error('Host not valid.') if (res === false) throw new Error('Host not valid.')
} }
} }
@ -29,11 +25,11 @@ module.exports = function (sequelize, DataTypes) {
}, },
score: { score: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
defaultValue: constants.FRIEND_SCORE.BASE, defaultValue: FRIEND_SCORE.BASE,
allowNull: false, allowNull: false,
validate: { validate: {
isInt: true, isInt: true,
max: constants.FRIEND_SCORE.MAX max: FRIEND_SCORE.MAX
} }
}, },
email: { email: {
@ -106,7 +102,7 @@ function countAll (callback) {
} }
function incrementScores (ids, value, callback) { function incrementScores (ids, value, callback) {
if (!callback) callback = function () {} if (!callback) callback = function () { /* empty */ }
const update = { const update = {
score: this.sequelize.literal('score +' + value) score: this.sequelize.literal('score +' + value)
@ -135,7 +131,7 @@ function listAllIds (transaction, callback) {
transaction = null transaction = null
} }
const query = { const query: any = {
attributes: [ 'id' ] attributes: [ 'id' ]
} }
@ -223,13 +219,13 @@ function updatePodsScore (goodPods, badPods) {
logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length) logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length)
if (goodPods.length !== 0) { if (goodPods.length !== 0) {
this.incrementScores(goodPods, constants.PODS_SCORE.BONUS, function (err) { this.incrementScores(goodPods, PODS_SCORE.BONUS, function (err) {
if (err) logger.error('Cannot increment scores of good pods.', { error: err }) if (err) logger.error('Cannot increment scores of good pods.', { error: err })
}) })
} }
if (badPods.length !== 0) { if (badPods.length !== 0) {
this.incrementScores(badPods, constants.PODS_SCORE.MALUS, function (err) { this.incrementScores(badPods, PODS_SCORE.MALUS, function (err) {
if (err) logger.error('Cannot decrement scores of bad pods.', { error: err }) if (err) logger.error('Cannot decrement scores of bad pods.', { error: err })
removeBadPods.call(self) removeBadPods.call(self)
}) })
@ -255,7 +251,7 @@ function removeBadPods () {
}, },
function removeTheseBadPods (pods, callback) { function removeTheseBadPods (pods, callback) {
each(pods, function (pod, callbackEach) { each(pods, function (pod: any, callbackEach) {
pod.destroy().asCallback(callbackEach) pod.destroy().asCallback(callbackEach)
}, function (err) { }, function (err) {
return callback(err, pods.length) return callback(err, pods.length)

View File

@ -1,7 +1,3 @@
'use strict'
// ---------------------------------------------------------------------------
module.exports = function (sequelize, DataTypes) { module.exports = function (sequelize, DataTypes) {
const RequestToPod = sequelize.define('RequestToPod', {}, { const RequestToPod = sequelize.define('RequestToPod', {}, {
indexes: [ indexes: [
@ -27,7 +23,7 @@ module.exports = function (sequelize, DataTypes) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
function removeByRequestIdsAndPod (requestsIds, podId, callback) { function removeByRequestIdsAndPod (requestsIds, podId, callback) {
if (!callback) callback = function () {} if (!callback) callback = function () { /* empty */ }
const query = { const query = {
where: { where: {

View File

@ -1,13 +1,11 @@
'use strict'
/* /*
Request Video events (likes, dislikes, views...) Request Video events (likes, dislikes, views...)
*/ */
const values = require('lodash/values') import { values } from 'lodash'
const constants = require('../initializers/constants') import { REQUEST_VIDEO_EVENT_TYPES } from '../initializers'
const customVideosValidators = require('../helpers/custom-validators').videos import { isVideoEventCountValid } from '../helpers'
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -15,7 +13,7 @@ module.exports = function (sequelize, DataTypes) {
const RequestVideoEvent = sequelize.define('RequestVideoEvent', const RequestVideoEvent = sequelize.define('RequestVideoEvent',
{ {
type: { type: {
type: DataTypes.ENUM(values(constants.REQUEST_VIDEO_EVENT_TYPES)), type: DataTypes.ENUM(values(REQUEST_VIDEO_EVENT_TYPES)),
allowNull: false allowNull: false
}, },
count: { count: {
@ -23,7 +21,7 @@ module.exports = function (sequelize, DataTypes) {
allowNull: false, allowNull: false,
validate: { validate: {
countValid: function (value) { countValid: function (value) {
const res = customVideosValidators.isVideoEventCountValid(value) const res = isVideoEventCountValid(value)
if (res === false) throw new Error('Video event count is not valid.') if (res === false) throw new Error('Video event count is not valid.')
} }
} }

Some files were not shown because too many files have changed in this diff Show More