diff --git a/package.json b/package.json index e7d0c39a45577099737a7ca252664352d6bdff3a..71cd789ba305871bdfdaa139a954c4117845c1c9 100644 --- a/package.json +++ b/package.json @@ -82,8 +82,10 @@ "@types/config": "^0.0.32", "@types/express": "^4.0.35", "@types/lodash": "^4.14.64", + "@types/magnet-uri": "^5.1.1", "@types/mkdirp": "^0.3.29", "@types/morgan": "^1.7.32", + "@types/multer": "^0.0.34", "@types/node": "^7.0.18", "@types/request": "^0.0.43", "@types/sequelize": "^4.0.55", diff --git a/server/controllers/api/clients.ts b/server/controllers/api/clients.ts index f6499556a0d4e249b93fd310722187d4ef2cc231..8c460096bef12ec15c7c9a1d0e8ed5dd49be3825 100644 --- a/server/controllers/api/clients.ts +++ b/server/controllers/api/clients.ts @@ -1,6 +1,6 @@ import * as express from 'express' -import { CONFIG } from '../../initializers'; +import { CONFIG } from '../../initializers' import { logger } from '../../helpers' import { database as db } from '../../initializers/database' @@ -9,7 +9,7 @@ const clientsRouter = express.Router() clientsRouter.get('/local', getLocalClient) // Get the client credentials for the PeerTube front end -function getLocalClient (req, res, next) { +function getLocalClient (req: express.Request, res: express.Response, next: express.NextFunction) { const serverHostname = CONFIG.WEBSERVER.HOSTNAME const serverPort = CONFIG.WEBSERVER.PORT let headerHostShouldBe = serverHostname diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 57c9398ecaafbd57a326b9ee02887fa5ca160dc2..c639817976a7ca6cb1cb1db88a1da9e3e4420a0b 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts @@ -7,7 +7,7 @@ const configRouter = express.Router() configRouter.get('/', getConfig) // Get the client credentials for the PeerTube front end -function getConfig (req, res, next) { +function getConfig (req: express.Request, res: express.Response, next: express.NextFunction) { res.json({ signup: { enabled: CONFIG.SIGNUP.ENABLED diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts index 98004544d05c1d8aa85ec244918461fd10a73bd5..ac3972ac63d8c00fb2aa5dea60d3ba604337836f 100644 --- a/server/controllers/api/index.ts +++ b/server/controllers/api/index.ts @@ -28,6 +28,6 @@ export { apiRouter } // --------------------------------------------------------------------------- -function pong (req, res, next) { +function pong (req: express.Request, res: express.Response, next: express.NextFunction) { return res.send('pong').status(200).end() } diff --git a/server/controllers/api/pods.ts b/server/controllers/api/pods.ts index a028c4ab9a1073b0debadf05a557902613199f1d..283105f6c39c8d4fac140167c2917016ae7b37c9 100644 --- a/server/controllers/api/pods.ts +++ b/server/controllers/api/pods.ts @@ -21,6 +21,9 @@ import { setBodyHostPort, setBodyHostsPort } from '../../middlewares' +import { + PodInstance +} from '../../models' const podsRouter = express.Router() @@ -51,10 +54,10 @@ export { // --------------------------------------------------------------------------- -function addPods (req, res, next) { +function addPods (req: express.Request, res: express.Response, next: express.NextFunction) { const informations = req.body - waterfall([ + waterfall<string, Error>([ function addPod (callback) { const pod = db.Pod.build(informations) pod.save().asCallback(function (err, podCreated) { @@ -63,7 +66,7 @@ function addPods (req, res, next) { }) }, - function sendMyVideos (podCreated, callback) { + function sendMyVideos (podCreated: PodInstance, callback) { sendOwnedVideosToPod(podCreated.id) callback(null) @@ -86,7 +89,7 @@ function addPods (req, res, next) { }) } -function listPods (req, res, next) { +function listPods (req: express.Request, res: express.Response, next: express.NextFunction) { db.Pod.list(function (err, podsList) { if (err) return next(err) @@ -94,8 +97,8 @@ function listPods (req, res, next) { }) } -function makeFriendsController (req, res, next) { - const hosts = req.body.hosts +function makeFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) { + const hosts = req.body.hosts as string[] makeFriends(hosts, function (err) { if (err) { @@ -109,7 +112,7 @@ function makeFriendsController (req, res, next) { res.type('json').status(204).end() } -function quitFriendsController (req, res, next) { +function quitFriendsController (req: express.Request, res: express.Response, next: express.NextFunction) { quitFriends(function (err) { if (err) return next(err) diff --git a/server/controllers/api/remote/pods.ts b/server/controllers/api/remote/pods.ts index 9c9d2164d9b8b342aacb5e7aff7d703267cbf54c..b0d6642c13bfe71edbad706b5b8fd15ee8c7ed4c 100644 --- a/server/controllers/api/remote/pods.ts +++ b/server/controllers/api/remote/pods.ts @@ -21,7 +21,7 @@ export { // --------------------------------------------------------------------------- -function removePods (req, res, next) { +function removePods (req: express.Request, res: express.Response, next: express.NextFunction) { const host = req.body.signature.host waterfall([ diff --git a/server/controllers/api/remote/videos.ts b/server/controllers/api/remote/videos.ts index d97a3db31ef0683a34d5c4cd973c74d6be8d0449..d9cc08fb41710c13b92d18aaf07b808eb064679f 100644 --- a/server/controllers/api/remote/videos.ts +++ b/server/controllers/api/remote/videos.ts @@ -1,4 +1,5 @@ import * as express from 'express' +import * as Sequelize from 'sequelize' import { eachSeries, waterfall } from 'async' import { database as db } from '../../../initializers/database' @@ -23,6 +24,7 @@ import { startSerializableTransaction } from '../../../helpers' import { quickAndDirtyUpdatesVideoToFriends } from '../../../lib' +import { PodInstance, VideoInstance } from '../../../models' const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS] @@ -64,7 +66,7 @@ export { // --------------------------------------------------------------------------- -function remoteVideos (req, res, next) { +function remoteVideos (req: express.Request, res: express.Response, next: express.NextFunction) { const requests = req.body.data const fromPod = res.locals.secure.pod @@ -89,7 +91,7 @@ function remoteVideos (req, res, next) { return res.type('json').status(204).end() } -function remoteVideosQadu (req, res, next) { +function remoteVideosQadu (req: express.Request, res: express.Response, next: express.NextFunction) { const requests = req.body.data const fromPod = res.locals.secure.pod @@ -104,7 +106,7 @@ function remoteVideosQadu (req, res, next) { return res.type('json').status(204).end() } -function remoteVideosEvents (req, res, next) { +function remoteVideosEvents (req: express.Request, res: express.Response, next: express.NextFunction) { const requests = req.body.data const fromPod = res.locals.secure.pod @@ -119,7 +121,7 @@ function remoteVideosEvents (req, res, next) { return res.type('json').status(204).end() } -function processVideosEventsRetryWrapper (eventData, fromPod, finalCallback) { +function processVideosEventsRetryWrapper (eventData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) { const options = { arguments: [ eventData, fromPod ], errorMessage: 'Cannot process videos events with many retries.' @@ -128,7 +130,7 @@ function processVideosEventsRetryWrapper (eventData, fromPod, finalCallback) { retryTransactionWrapper(processVideosEvents, options, finalCallback) } -function processVideosEvents (eventData, fromPod, finalCallback) { +function processVideosEvents (eventData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) { waterfall([ startSerializableTransaction, @@ -187,7 +189,7 @@ function processVideosEvents (eventData, fromPod, finalCallback) { commitTransaction - ], function (err, t) { + ], function (err: Error, t: Sequelize.Transaction) { if (err) { logger.debug('Cannot process a video event.', { error: err }) return rollbackTransaction(err, t, finalCallback) @@ -198,7 +200,7 @@ function processVideosEvents (eventData, fromPod, finalCallback) { }) } -function quickAndDirtyUpdateVideoRetryWrapper (videoData, fromPod, finalCallback) { +function quickAndDirtyUpdateVideoRetryWrapper (videoData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) { const options = { arguments: [ videoData, fromPod ], errorMessage: 'Cannot update quick and dirty the remote video with many retries.' @@ -207,7 +209,7 @@ function quickAndDirtyUpdateVideoRetryWrapper (videoData, fromPod, finalCallback retryTransactionWrapper(quickAndDirtyUpdateVideo, options, finalCallback) } -function quickAndDirtyUpdateVideo (videoData, fromPod, finalCallback) { +function quickAndDirtyUpdateVideo (videoData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) { let videoName waterfall([ @@ -243,7 +245,7 @@ function quickAndDirtyUpdateVideo (videoData, fromPod, finalCallback) { commitTransaction - ], function (err, t) { + ], function (err: Error, t: Sequelize.Transaction) { if (err) { logger.debug('Cannot quick and dirty update the remote video.', { error: err }) return rollbackTransaction(err, t, finalCallback) @@ -255,7 +257,7 @@ function quickAndDirtyUpdateVideo (videoData, fromPod, finalCallback) { } // Handle retries on fail -function addRemoteVideoRetryWrapper (videoToCreateData, fromPod, finalCallback) { +function addRemoteVideoRetryWrapper (videoToCreateData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) { const options = { arguments: [ videoToCreateData, fromPod ], errorMessage: 'Cannot insert the remote video with many retries.' @@ -264,7 +266,7 @@ function addRemoteVideoRetryWrapper (videoToCreateData, fromPod, finalCallback) retryTransactionWrapper(addRemoteVideo, options, finalCallback) } -function addRemoteVideo (videoToCreateData, fromPod, finalCallback) { +function addRemoteVideo (videoToCreateData: any, fromPod: PodInstance, finalCallback: (err: Error) => void) { logger.debug('Adding remote video "%s".', videoToCreateData.remoteId) waterfall([ @@ -359,7 +361,7 @@ function addRemoteVideo (videoToCreateData, fromPod, finalCallback) { commitTransaction - ], function (err, t) { + ], function (err: Error, t: Sequelize.Transaction) { if (err) { // This is just a debug because we will retry the insert logger.debug('Cannot insert the remote video.', { error: err }) @@ -372,7 +374,7 @@ function addRemoteVideo (videoToCreateData, fromPod, finalCallback) { } // Handle retries on fail -function updateRemoteVideoRetryWrapper (videoAttributesToUpdate, fromPod, finalCallback) { +function updateRemoteVideoRetryWrapper (videoAttributesToUpdate: any, fromPod: PodInstance, finalCallback: (err: Error) => void) { const options = { arguments: [ videoAttributesToUpdate, fromPod ], errorMessage: 'Cannot update the remote video with many retries' @@ -381,7 +383,7 @@ function updateRemoteVideoRetryWrapper (videoAttributesToUpdate, fromPod, finalC retryTransactionWrapper(updateRemoteVideo, options, finalCallback) } -function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) { +function updateRemoteVideo (videoAttributesToUpdate: any, fromPod: PodInstance, finalCallback: (err: Error) => void) { logger.debug('Updating remote video "%s".', videoAttributesToUpdate.remoteId) waterfall([ @@ -435,7 +437,7 @@ function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) { commitTransaction - ], function (err, t) { + ], function (err: Error, t: Sequelize.Transaction) { if (err) { // This is just a debug because we will retry the insert logger.debug('Cannot update the remote video.', { error: err }) @@ -447,7 +449,7 @@ function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) { }) } -function removeRemoteVideo (videoToRemoveData, fromPod, callback) { +function removeRemoteVideo (videoToRemoveData: any, fromPod: PodInstance, callback: (err: Error) => void) { // We need the instance because we have to remove some other stuffs (thumbnail etc) fetchRemoteVideo(fromPod.host, videoToRemoveData.remoteId, function (err, video) { // Do not return the error, continue the process @@ -465,7 +467,7 @@ function removeRemoteVideo (videoToRemoveData, fromPod, callback) { }) } -function reportAbuseRemoteVideo (reportData, fromPod, callback) { +function reportAbuseRemoteVideo (reportData: any, fromPod: PodInstance, callback: (err: Error) => void) { fetchOwnedVideo(reportData.videoRemoteId, function (err, video) { if (err || !video) { if (!err) err = new Error('video not found') @@ -494,7 +496,7 @@ function reportAbuseRemoteVideo (reportData, fromPod, callback) { }) } -function fetchOwnedVideo (id, callback) { +function fetchOwnedVideo (id: string, callback: (err: Error, video?: VideoInstance) => void) { db.Video.load(id, function (err, video) { if (err || !video) { if (!err) err = new Error('video not found') @@ -507,7 +509,7 @@ function fetchOwnedVideo (id, callback) { }) } -function fetchRemoteVideo (podHost, remoteId, callback) { +function fetchRemoteVideo (podHost: string, remoteId: string, callback: (err: Error, video?: VideoInstance) => void) { db.Video.loadByHostAndRemoteId(podHost, remoteId, function (err, video) { if (err || !video) { if (!err) err = new Error('video not found') diff --git a/server/controllers/api/requests.ts b/server/controllers/api/requests.ts index ff4b4ac1ab85e0ad0525645b466bc222a64c5f94..2c18fe04608f6ec79161db35d0e739d44e83b9f7 100644 --- a/server/controllers/api/requests.ts +++ b/server/controllers/api/requests.ts @@ -2,6 +2,7 @@ import * as express from 'express' import { parallel } from 'async' import { + BaseRequestScheduler, getRequestScheduler, getRequestVideoQaduScheduler, getRequestVideoEventScheduler @@ -24,7 +25,7 @@ export { // --------------------------------------------------------------------------- -function getStatsRequests (req, res, next) { +function getStatsRequests (req: express.Request, res: express.Response, next: express.NextFunction) { parallel({ requestScheduler: buildRequestSchedulerFunction(getRequestScheduler()), requestVideoQaduScheduler: buildRequestSchedulerFunction(getRequestVideoQaduScheduler()), @@ -38,7 +39,7 @@ function getStatsRequests (req, res, next) { // --------------------------------------------------------------------------- -function buildRequestSchedulerFunction (requestScheduler) { +function buildRequestSchedulerFunction (requestScheduler: BaseRequestScheduler) { return function (callback) { requestScheduler.remainingRequestsCount(function (err, count) { if (err) return callback(err) diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts index 44c5ec13c8f21e2f238ded0e05b00fc5e41c063b..ffe5881e5594040e6a5cb9f99fcaf84cee6e59bd 100644 --- a/server/controllers/api/users.ts +++ b/server/controllers/api/users.ts @@ -76,7 +76,7 @@ export { // --------------------------------------------------------------------------- -function ensureRegistrationEnabled (req, res, next) { +function ensureRegistrationEnabled (req: express.Request, res: express.Response, next: express.NextFunction) { const registrationEnabled = CONFIG.SIGNUP.ENABLED if (registrationEnabled === true) { @@ -86,7 +86,7 @@ function ensureRegistrationEnabled (req, res, next) { return res.status(400).send('User registration is not enabled.') } -function createUser (req, res, next) { +function createUser (req: express.Request, res: express.Response, next: express.NextFunction) { const user = db.User.build({ username: req.body.username, password: req.body.password, @@ -95,14 +95,14 @@ function createUser (req, res, next) { role: USER_ROLES.USER }) - user.save().asCallback(function (err, createdUser) { + user.save().asCallback(function (err) { if (err) return next(err) return res.type('json').status(204).end() }) } -function getUserInformation (req, res, next) { +function getUserInformation (req: express.Request, res: express.Response, next: express.NextFunction) { db.User.loadByUsername(res.locals.oauth.token.user.username, function (err, user) { if (err) return next(err) @@ -110,9 +110,9 @@ function getUserInformation (req, res, next) { }) } -function getUserVideoRating (req, res, next) { - const videoId = req.params.videoId - const userId = res.locals.oauth.token.User.id +function getUserVideoRating (req: express.Request, res: express.Response, next: express.NextFunction) { + const videoId = '' + req.params.videoId + const userId = +res.locals.oauth.token.User.id db.UserVideoRate.load(userId, videoId, null, function (err, ratingObj) { if (err) return next(err) @@ -126,7 +126,7 @@ function getUserVideoRating (req, res, next) { }) } -function listUsers (req, res, next) { +function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) { db.User.listForApi(req.query.start, req.query.count, req.query.sort, function (err, usersList, usersTotal) { if (err) return next(err) @@ -134,7 +134,7 @@ function listUsers (req, res, next) { }) } -function removeUser (req, res, next) { +function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) { waterfall([ function loadUser (callback) { db.User.loadById(req.params.id, callback) @@ -153,7 +153,7 @@ function removeUser (req, res, next) { }) } -function updateUser (req, res, next) { +function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) { db.User.loadByUsername(res.locals.oauth.token.user.username, function (err, user) { if (err) return next(err) @@ -168,6 +168,6 @@ function updateUser (req, res, next) { }) } -function success (req, res, next) { +function success (req: express.Request, res: express.Response, next: express.NextFunction) { res.end() } diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts index 68db025b7f3bf67a0ec079b61039bdd5fdd01171..78e8e8b3d7ed9bf188731640c016e7e44d1d5238 100644 --- a/server/controllers/api/videos/abuse.ts +++ b/server/controllers/api/videos/abuse.ts @@ -1,4 +1,5 @@ import * as express from 'express' +import * as Sequelize from 'sequelize' import { waterfall } from 'async' import { database as db } from '../../../initializers/database' @@ -46,7 +47,7 @@ export { // --------------------------------------------------------------------------- -function listVideoAbuses (req, res, next) { +function listVideoAbuses (req: express.Request, res: express.Response, next: express.NextFunction) { db.VideoAbuse.listForApi(req.query.start, req.query.count, req.query.sort, function (err, abusesList, abusesTotal) { if (err) return next(err) @@ -54,7 +55,7 @@ function listVideoAbuses (req, res, next) { }) } -function reportVideoAbuseRetryWrapper (req, res, next) { +function reportVideoAbuseRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { const options = { arguments: [ req, res ], errorMessage: 'Cannot report abuse to the video with many retries.' @@ -67,7 +68,7 @@ function reportVideoAbuseRetryWrapper (req, res, next) { }) } -function reportVideoAbuse (req, res, finalCallback) { +function reportVideoAbuse (req: express.Request, res: express.Response, finalCallback: (err: Error) => void) { const videoInstance = res.locals.video const reporterUsername = res.locals.oauth.token.User.username @@ -105,7 +106,7 @@ function reportVideoAbuse (req, res, finalCallback) { commitTransaction - ], function andFinally (err, t) { + ], function andFinally (err: Error, t: Sequelize.Transaction) { if (err) { logger.debug('Cannot update the video.', { error: err }) return rollbackTransaction(err, t, finalCallback) diff --git a/server/controllers/api/videos/blacklist.ts b/server/controllers/api/videos/blacklist.ts index 58960798bd503cfd2978f411a9352f3d9a795686..4b42fc2d703c17a3eb867f2db8b5f4fd4166a15d 100644 --- a/server/controllers/api/videos/blacklist.ts +++ b/server/controllers/api/videos/blacklist.ts @@ -25,7 +25,7 @@ export { // --------------------------------------------------------------------------- -function addVideoToBlacklist (req, res, next) { +function addVideoToBlacklist (req: express.Request, res: express.Response, next: express.NextFunction) { const videoInstance = res.locals.video const toCreate = { diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index b82b0936f13674fcae423411ebb73ec6a18053b2..bfa018031d4a767a69e2253d78fafea8c12e646c 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -1,4 +1,5 @@ import * as express from 'express' +import * as Sequelize from 'sequelize' import * as fs from 'fs' import * as multer from 'multer' import * as path from 'path' @@ -124,21 +125,21 @@ export { // --------------------------------------------------------------------------- -function listVideoCategories (req, res, next) { +function listVideoCategories (req: express.Request, res: express.Response, next: express.NextFunction) { res.json(VIDEO_CATEGORIES) } -function listVideoLicences (req, res, next) { +function listVideoLicences (req: express.Request, res: express.Response, next: express.NextFunction) { res.json(VIDEO_LICENCES) } -function listVideoLanguages (req, res, next) { +function listVideoLanguages (req: express.Request, res: express.Response, next: express.NextFunction) { res.json(VIDEO_LANGUAGES) } // Wrapper to video add that retry the function if there is a database error // We need this because we run the transaction in SERIALIZABLE isolation that can fail -function addVideoRetryWrapper (req, res, next) { +function addVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { const options = { arguments: [ req, res, req.files.videofile[0] ], errorMessage: 'Cannot insert the video with many retries.' @@ -152,7 +153,7 @@ function addVideoRetryWrapper (req, res, next) { }) } -function addVideo (req, res, videoFile, finalCallback) { +function addVideo (req: express.Request, res: express.Response, videoFile: Express.Multer.File, finalCallback: (err: Error) => void) { const videoInfos = req.body waterfall([ @@ -190,7 +191,7 @@ function addVideo (req, res, videoFile, finalCallback) { language: videoInfos.language, nsfw: videoInfos.nsfw, description: videoInfos.description, - duration: videoFile.duration, + duration: videoFile['duration'], // duration was added by a previous middleware authorId: author.id } @@ -254,7 +255,7 @@ function addVideo (req, res, videoFile, finalCallback) { commitTransaction - ], function andFinally (err, t) { + ], function andFinally (err: Error, t: Sequelize.Transaction) { if (err) { // This is just a debug because we will retry the insert logger.debug('Cannot insert the video.', { error: err }) @@ -266,7 +267,7 @@ function addVideo (req, res, videoFile, finalCallback) { }) } -function updateVideoRetryWrapper (req, res, next) { +function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { const options = { arguments: [ req, res ], errorMessage: 'Cannot update the video with many retries.' @@ -280,7 +281,7 @@ function updateVideoRetryWrapper (req, res, next) { }) } -function updateVideo (req, res, finalCallback) { +function updateVideo (req: express.Request, res: express.Response, finalCallback: (err: Error) => void) { const videoInstance = res.locals.video const videoFieldsSave = videoInstance.toJSON() const videoInfosToUpdate = req.body @@ -341,7 +342,7 @@ function updateVideo (req, res, finalCallback) { commitTransaction - ], function andFinally (err, t) { + ], function andFinally (err: Error, t: Sequelize.Transaction) { if (err) { logger.debug('Cannot update the video.', { error: err }) @@ -361,7 +362,7 @@ function updateVideo (req, res, finalCallback) { }) } -function getVideo (req, res, next) { +function getVideo (req: express.Request, res: express.Response, next: express.NextFunction) { const videoInstance = res.locals.video if (videoInstance.isOwned()) { @@ -393,7 +394,7 @@ function getVideo (req, res, next) { res.json(videoInstance.toFormatedJSON()) } -function listVideos (req, res, next) { +function listVideos (req: express.Request, res: express.Response, next: express.NextFunction) { db.Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) { if (err) return next(err) @@ -401,7 +402,7 @@ function listVideos (req, res, next) { }) } -function removeVideo (req, res, next) { +function removeVideo (req: express.Request, res: express.Response, next: express.NextFunction) { const videoInstance = res.locals.video videoInstance.destroy().asCallback(function (err) { @@ -414,7 +415,7 @@ function removeVideo (req, res, next) { }) } -function searchVideos (req, res, next) { +function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { db.Video.searchAndPopulateAuthorAndPodAndTags( req.params.value, req.query.field, req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) { diff --git a/server/controllers/api/videos/rate.ts b/server/controllers/api/videos/rate.ts index 1bc575675ae93bb2ff6e1056b97f5b069a062e58..afdd099f8defdb8d875fadbf26cbe760302e45db 100644 --- a/server/controllers/api/videos/rate.ts +++ b/server/controllers/api/videos/rate.ts @@ -1,4 +1,5 @@ import * as express from 'express' +import * as Sequelize from 'sequelize' import { waterfall } from 'async' import { database as db } from '../../../initializers/database' @@ -39,7 +40,7 @@ export { // --------------------------------------------------------------------------- -function rateVideoRetryWrapper (req, res, next) { +function rateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { const options = { arguments: [ req, res ], errorMessage: 'Cannot update the user video rate.' @@ -52,7 +53,7 @@ function rateVideoRetryWrapper (req, res, next) { }) } -function rateVideo (req, res, finalCallback) { +function rateVideo (req: express.Request, res: express.Response, finalCallback: (err: Error) => void) { const rateType = req.body.rating const videoInstance = res.locals.video const userInstance = res.locals.oauth.token.User @@ -168,7 +169,7 @@ function rateVideo (req, res, finalCallback) { commitTransaction - ], function (err, t) { + ], function (err: Error, t: Sequelize.Transaction) { if (err) { // This is just a debug because we will retry the insert logger.debug('Cannot add the user video rate.', { error: err }) diff --git a/server/controllers/client.ts b/server/controllers/client.ts index c3d28245c329bfc5d180d0073a21389abc893b1a..503eff75013ab5c58bf80869e3b0b0c24ecde67e 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts @@ -12,6 +12,7 @@ import { STATIC_MAX_AGE } from '../initializers' import { root } from '../helpers' +import { VideoInstance } from '../models' const clientsRouter = express.Router() @@ -25,7 +26,7 @@ const indexPath = join(distPath, 'index.html') // Do not use a template engine for a so little thing clientsRouter.use('/videos/watch/:id', generateWatchHtmlPage) -clientsRouter.use('/videos/embed', function (req, res, next) { +clientsRouter.use('/videos/embed', function (req: express.Request, res: express.Response, next: express.NextFunction) { res.sendFile(embedPath) }) @@ -33,7 +34,7 @@ clientsRouter.use('/videos/embed', function (req, res, next) { clientsRouter.use('/client', express.static(distPath, { maxAge: STATIC_MAX_AGE })) // 404 for static files not found -clientsRouter.use('/client/*', function (req, res, next) { +clientsRouter.use('/client/*', function (req: express.Request, res: express.Response, next: express.NextFunction) { res.sendStatus(404) }) @@ -45,7 +46,7 @@ export { // --------------------------------------------------------------------------- -function addOpenGraphTags (htmlStringPage, video) { +function addOpenGraphTags (htmlStringPage: string, video: VideoInstance) { let basePreviewUrlHttp if (video.isOwned()) { @@ -88,8 +89,8 @@ function addOpenGraphTags (htmlStringPage, video) { return htmlStringPage.replace(opengraphComment, tagsString) } -function generateWatchHtmlPage (req, res, next) { - const videoId = req.params.id +function generateWatchHtmlPage (req: express.Request, res: express.Response, next: express.NextFunction) { + const videoId = '' + req.params.id // Let Angular application handle errors if (!validator.isUUID(videoId, 4)) return res.sendFile(indexPath) @@ -102,7 +103,7 @@ function generateWatchHtmlPage (req, res, next) { video: function (callback) { db.Video.loadAndPopulateAuthorAndPodAndTags(videoId, callback) } - }, function (err, result: any) { + }, function (err: Error, result: { file: Buffer, video: VideoInstance }) { if (err) return next(err) const html = result.file.toString() diff --git a/server/helpers/custom-validators/misc.ts b/server/helpers/custom-validators/misc.ts index 83f50a7fef69e92325d07d5c6fb0e8a29ccaa50f..b1291ba7a5b38a8f91a9e5a6f1d14c068d1731ee 100644 --- a/server/helpers/custom-validators/misc.ts +++ b/server/helpers/custom-validators/misc.ts @@ -1,8 +1,8 @@ -function exists (value) { +function exists (value: any) { return value !== undefined && value !== null } -function isArray (value) { +function isArray (value: any) { return Array.isArray(value) } @@ -12,3 +12,12 @@ export { exists, isArray } + +declare global { + namespace ExpressValidator { + export interface Validator { + exists, + isArray + } + } +} diff --git a/server/helpers/custom-validators/pods.ts b/server/helpers/custom-validators/pods.ts index ee939ad04b0053722fd281d7ab12a98326ec5066..ec9f26cc8444caab3671f06870f4fc31ea8ed488 100644 --- a/server/helpers/custom-validators/pods.ts +++ b/server/helpers/custom-validators/pods.ts @@ -1,12 +1,12 @@ import * as validator from 'validator' -import { isArray } from './misc' +import { isArray, exists } from './misc' -function isHostValid (host) { - return validator.isURL(host) && host.split('://').length === 1 +function isHostValid (host: string) { + return exists(host) && validator.isURL(host) && host.split('://').length === 1 } -function isEachUniqueHostValid (hosts) { +function isEachUniqueHostValid (hosts: string[]) { return isArray(hosts) && hosts.length !== 0 && hosts.every(function (host) { @@ -20,3 +20,12 @@ export { isEachUniqueHostValid, isHostValid } + +declare global { + namespace ExpressValidator { + export interface Validator { + isEachUniqueHostValid + isHostValid + } + } +} diff --git a/server/helpers/custom-validators/remote/index.ts b/server/helpers/custom-validators/remote/index.ts index d6f9a7e77c86aefdd910299f834923f65582a2c7..e29a9b7670f6e0e0a7393b6f22c6df54784810f9 100644 --- a/server/helpers/custom-validators/remote/index.ts +++ b/server/helpers/custom-validators/remote/index.ts @@ -1 +1 @@ -export * from './videos'; +export * from './videos' diff --git a/server/helpers/custom-validators/remote/videos.ts b/server/helpers/custom-validators/remote/videos.ts index 4b904d011a85328d084d08fdbd3f33326a6b78ef..1df7316aa8cbc2cc7cb766bfa8ea19ed31143adb 100644 --- a/server/helpers/custom-validators/remote/videos.ts +++ b/server/helpers/custom-validators/remote/videos.ts @@ -31,7 +31,7 @@ import { const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS] -function isEachRemoteRequestVideosValid (requests) { +function isEachRemoteRequestVideosValid (requests: any[]) { return isArray(requests) && requests.every(function (request) { const video = request.data @@ -61,7 +61,7 @@ function isEachRemoteRequestVideosValid (requests) { }) } -function isEachRemoteRequestVideosQaduValid (requests) { +function isEachRemoteRequestVideosQaduValid (requests: any[]) { return isArray(requests) && requests.every(function (request) { const video = request.data @@ -70,14 +70,14 @@ function isEachRemoteRequestVideosQaduValid (requests) { return ( isVideoRemoteIdValid(video.remoteId) && - (has(video, 'views') === false || isVideoViewsValid) && - (has(video, 'likes') === false || isVideoLikesValid) && - (has(video, 'dislikes') === false || isVideoDislikesValid) + (has(video, 'views') === false || isVideoViewsValid(video.views)) && + (has(video, 'likes') === false || isVideoLikesValid(video.likes)) && + (has(video, 'dislikes') === false || isVideoDislikesValid(video.dislikes)) ) }) } -function isEachRemoteRequestVideosEventsValid (requests) { +function isEachRemoteRequestVideosEventsValid (requests: any[]) { return isArray(requests) && requests.every(function (request) { const eventData = request.data @@ -100,9 +100,19 @@ export { isEachRemoteRequestVideosEventsValid } +declare global { + namespace ExpressValidator { + export interface Validator { + isEachRemoteRequestVideosValid, + isEachRemoteRequestVideosQaduValid, + isEachRemoteRequestVideosEventsValid + } + } +} + // --------------------------------------------------------------------------- -function isCommonVideoAttributesValid (video) { +function isCommonVideoAttributesValid (video: any) { return isVideoDateValid(video.createdAt) && isVideoDateValid(video.updatedAt) && isVideoCategoryValid(video.category) && @@ -121,18 +131,18 @@ function isCommonVideoAttributesValid (video) { isVideoDislikesValid(video.dislikes) } -function isRequestTypeAddValid (value) { +function isRequestTypeAddValid (value: string) { return value === ENDPOINT_ACTIONS.ADD } -function isRequestTypeUpdateValid (value) { +function isRequestTypeUpdateValid (value: string) { return value === ENDPOINT_ACTIONS.UPDATE } -function isRequestTypeRemoveValid (value) { +function isRequestTypeRemoveValid (value: string) { return value === ENDPOINT_ACTIONS.REMOVE } -function isRequestTypeReportAbuseValid (value) { +function isRequestTypeReportAbuseValid (value: string) { return value === ENDPOINT_ACTIONS.REPORT_ABUSE } diff --git a/server/helpers/custom-validators/users.ts b/server/helpers/custom-validators/users.ts index f303ab8db2f5be4ea43bc69ee0663ce06d687371..7792ffd74eb82865f65dede8f37a36a6373b5dc7 100644 --- a/server/helpers/custom-validators/users.ts +++ b/server/helpers/custom-validators/users.ts @@ -1,25 +1,26 @@ import { values } from 'lodash' import * as validator from 'validator' +import { exists } from './misc' import { CONSTRAINTS_FIELDS, USER_ROLES } from '../../initializers' const USERS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.USERS -function isUserPasswordValid (value) { +function isUserPasswordValid (value: string) { return validator.isLength(value, USERS_CONSTRAINTS_FIELDS.PASSWORD) } -function isUserRoleValid (value) { +function isUserRoleValid (value: string) { return values(USER_ROLES).indexOf(value) !== -1 } -function isUserUsernameValid (value) { +function isUserUsernameValid (value: string) { const max = USERS_CONSTRAINTS_FIELDS.USERNAME.max const min = USERS_CONSTRAINTS_FIELDS.USERNAME.min - return validator.matches(value, new RegExp(`^[a-zA-Z0-9._]{${min},${max}}$`)) + return exists(value) && validator.matches(value, new RegExp(`^[a-zA-Z0-9._]{${min},${max}}$`)) } -function isUserDisplayNSFWValid (value) { - return validator.isBoolean(value) +function isUserDisplayNSFWValid (value: any) { + return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value)) } // --------------------------------------------------------------------------- @@ -30,3 +31,14 @@ export { isUserUsernameValid, isUserDisplayNSFWValid } + +declare global { + namespace ExpressValidator { + export interface Validator { + isUserPasswordValid, + isUserRoleValid, + isUserUsernameValid, + isUserDisplayNSFWValid + } + } +} diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index 6389998e1320c831d0891d5cf78f76756c04a1f2..c5ef4cb5f3308fd8d8b8c899ba2f27982dd13ae3 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts @@ -9,105 +9,105 @@ import { VIDEO_RATE_TYPES } from '../../initializers' import { isUserUsernameValid } from './users' -import { isArray } from './misc' +import { isArray, exists } from './misc' const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES const VIDEO_EVENTS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_EVENTS -function isVideoAuthorValid (value) { +function isVideoAuthorValid (value: string) { return isUserUsernameValid(value) } -function isVideoDateValid (value) { - return validator.isDate(value) +function isVideoDateValid (value: string) { + return exists(value) && validator.isISO8601(value) } -function isVideoCategoryValid (value) { +function isVideoCategoryValid (value: number) { return VIDEO_CATEGORIES[value] !== undefined } -function isVideoLicenceValid (value) { +function isVideoLicenceValid (value: number) { return VIDEO_LICENCES[value] !== undefined } -function isVideoLanguageValid (value) { +function isVideoLanguageValid (value: number) { return value === null || VIDEO_LANGUAGES[value] !== undefined } -function isVideoNSFWValid (value) { - return validator.isBoolean(value) +function isVideoNSFWValid (value: any) { + return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value)) } -function isVideoDescriptionValid (value) { - return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION) +function isVideoDescriptionValid (value: string) { + return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION) } -function isVideoDurationValid (value) { - return validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION) +function isVideoDurationValid (value: string) { + return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION) } -function isVideoExtnameValid (value) { +function isVideoExtnameValid (value: string) { return VIDEOS_CONSTRAINTS_FIELDS.EXTNAME.indexOf(value) !== -1 } -function isVideoInfoHashValid (value) { - return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH) +function isVideoInfoHashValid (value: string) { + return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH) } -function isVideoNameValid (value) { - return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME) +function isVideoNameValid (value: string) { + return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME) } -function isVideoTagsValid (tags) { +function isVideoTagsValid (tags: string[]) { return isArray(tags) && - validator.isInt(tags.length, VIDEOS_CONSTRAINTS_FIELDS.TAGS) && + validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) && tags.every(function (tag) { - return validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG) + return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG) }) } -function isVideoThumbnailValid (value) { - return validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL) +function isVideoThumbnailValid (value: string) { + return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL) } -function isVideoThumbnailDataValid (value) { - return validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA) +function isVideoThumbnailDataValid (value: string) { + return exists(value) && validator.isByteLength(value, VIDEOS_CONSTRAINTS_FIELDS.THUMBNAIL_DATA) } -function isVideoRemoteIdValid (value) { - return validator.isUUID(value, 4) +function isVideoRemoteIdValid (value: string) { + return exists(value) && validator.isUUID(value, 4) } -function isVideoAbuseReasonValid (value) { - return validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON) +function isVideoAbuseReasonValid (value: string) { + return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON) } -function isVideoAbuseReporterUsernameValid (value) { +function isVideoAbuseReporterUsernameValid (value: string) { return isUserUsernameValid(value) } -function isVideoViewsValid (value) { - return validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS) +function isVideoViewsValid (value: string) { + return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS) } -function isVideoLikesValid (value) { - return validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.LIKES) +function isVideoLikesValid (value: string) { + return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.LIKES) } -function isVideoDislikesValid (value) { - return validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DISLIKES) +function isVideoDislikesValid (value: string) { + return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DISLIKES) } -function isVideoEventCountValid (value) { - return validator.isInt(value + '', VIDEO_EVENTS_CONSTRAINTS_FIELDS.COUNT) +function isVideoEventCountValid (value: string) { + return exists(value) && validator.isInt(value + '', VIDEO_EVENTS_CONSTRAINTS_FIELDS.COUNT) } -function isVideoRatingTypeValid (value) { +function isVideoRatingTypeValid (value: string) { return values(VIDEO_RATE_TYPES).indexOf(value) !== -1 } -function isVideoFile (value, files) { +function isVideoFile (value: string, files: { [ fieldname: string ]: Express.Multer.File[] }) { // Should have files if (!files) return false @@ -149,3 +149,33 @@ export { isVideoDislikesValid, isVideoEventCountValid } + +declare global { + namespace ExpressValidator { + export interface Validator { + isVideoAuthorValid, + isVideoDateValid, + isVideoCategoryValid, + isVideoLicenceValid, + isVideoLanguageValid, + isVideoNSFWValid, + isVideoDescriptionValid, + isVideoDurationValid, + isVideoInfoHashValid, + isVideoNameValid, + isVideoTagsValid, + isVideoThumbnailValid, + isVideoThumbnailDataValid, + isVideoExtnameValid, + isVideoRemoteIdValid, + isVideoAbuseReasonValid, + isVideoAbuseReporterUsernameValid, + isVideoFile, + isVideoViewsValid, + isVideoLikesValid, + isVideoRatingTypeValid, + isVideoDislikesValid, + isVideoEventCountValid + } + } +} diff --git a/server/helpers/database-utils.ts b/server/helpers/database-utils.ts index 4f49c58250abae92c230f737429008e7a287425e..f8ee9a45424e6c9e69fa70635e350cadeec1df17 100644 --- a/server/helpers/database-utils.ts +++ b/server/helpers/database-utils.ts @@ -1,14 +1,15 @@ +import * as Sequelize from 'sequelize' // TODO: import from ES6 when retry typing file will include errorFilter function import * as retry from 'async/retry' import { database as db } from '../initializers/database' import { logger } from './logger' -function commitTransaction (t, callback) { +function commitTransaction (t: Sequelize.Transaction, callback: (err: Error) => void) { return t.commit().asCallback(callback) } -function rollbackTransaction (err, t, callback) { +function rollbackTransaction (err: Error, t: Sequelize.Transaction, callback: (err: Error) => void) { // Try to rollback transaction if (t) { // Do not catch err, report the original one @@ -20,8 +21,8 @@ function rollbackTransaction (err, t, callback) { } } -// { arguments, errorMessage } -function retryTransactionWrapper (functionToRetry, options, finalCallback) { +type RetryTransactionWrapperOptions = { errorMessage: string, arguments?: any[] } +function retryTransactionWrapper (functionToRetry: Function, options: RetryTransactionWrapperOptions, finalCallback: Function) { const args = options.arguments ? options.arguments : [] transactionRetryer( @@ -39,7 +40,7 @@ function retryTransactionWrapper (functionToRetry, options, finalCallback) { ) } -function transactionRetryer (func, callback) { +function transactionRetryer (func: Function, callback: (err: Error) => void) { retry({ times: 5, @@ -51,7 +52,7 @@ function transactionRetryer (func, callback) { }, func, callback) } -function startSerializableTransaction (callback) { +function startSerializableTransaction (callback: (err: Error, t: Sequelize.Transaction) => void) { db.sequelize.transaction(/* { isolationLevel: 'SERIALIZABLE' } */).asCallback(function (err, t) { // We force to return only two parameters return callback(err, t) diff --git a/server/helpers/peertube-crypto.ts b/server/helpers/peertube-crypto.ts index feb32a4cd7a2374425c4342a8bdce0a03b904cb1..0ac87512704177f28fff94c7c90f38f6f883c4c4 100644 --- a/server/helpers/peertube-crypto.ts +++ b/server/helpers/peertube-crypto.ts @@ -14,7 +14,7 @@ import { } from '../initializers' import { logger } from './logger' -function checkSignature (publicKey, data, hexSignature) { +function checkSignature (publicKey: string, data: string, hexSignature: string) { const verify = crypto.createVerify(SIGNATURE_ALGORITHM) let dataString @@ -35,10 +35,10 @@ function checkSignature (publicKey, data, hexSignature) { return isValid } -function sign (data) { +function sign (data: string|Object) { const sign = crypto.createSign(SIGNATURE_ALGORITHM) - let dataString + let dataString: string if (typeof data === 'string') { dataString = data } else { @@ -60,7 +60,7 @@ function sign (data) { return signature } -function comparePassword (plainPassword, hashPassword, callback) { +function comparePassword (plainPassword: string, hashPassword: string, callback: (err: Error, match?: boolean) => void) { bcrypt.compare(plainPassword, hashPassword, function (err, isPasswordMatch) { if (err) return callback(err) @@ -68,7 +68,7 @@ function comparePassword (plainPassword, hashPassword, callback) { }) } -function createCertsIfNotExist (callback) { +function createCertsIfNotExist (callback: (err: Error) => void) { certsExist(function (err, exist) { if (err) return callback(err) @@ -82,7 +82,7 @@ function createCertsIfNotExist (callback) { }) } -function cryptPassword (password, callback) { +function cryptPassword (password: string, callback: (err: Error, hash?: string) => void) { bcrypt.genSalt(BCRYPT_SALT_SIZE, function (err, salt) { if (err) return callback(err) @@ -92,12 +92,12 @@ function cryptPassword (password, callback) { }) } -function getMyPrivateCert (callback) { +function getMyPrivateCert (callback: (err: Error, privateCert: string) => void) { const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) fs.readFile(certPath, 'utf8', callback) } -function getMyPublicCert (callback) { +function getMyPublicCert (callback: (err: Error, publicCert: string) => void) { const certPath = join(CONFIG.STORAGE.CERT_DIR, PUBLIC_CERT_NAME) fs.readFile(certPath, 'utf8', callback) } @@ -116,7 +116,7 @@ export { // --------------------------------------------------------------------------- -function certsExist (callback) { +function certsExist (callback: (err: Error, certsExist: boolean) => void) { const certPath = join(CONFIG.STORAGE.CERT_DIR, PRIVATE_CERT_NAME) fs.access(certPath, function (err) { // If there is an error the certificates do not exist @@ -125,14 +125,14 @@ function certsExist (callback) { }) } -function createCerts (callback) { +function createCerts (callback: (err: Error) => void) { certsExist(function (err, exist) { if (err) return callback(err) if (exist === true) { - const string = 'Certs already exist.' - logger.warning(string) - return callback(new Error(string)) + const errorMessage = 'Certs already exist.' + logger.warning(errorMessage) + return callback(new Error(errorMessage)) } logger.info('Generating a RSA key...') diff --git a/server/helpers/requests.ts b/server/helpers/requests.ts index 48b1fd703122e1c4cb9013ccfa7f3409bca8c33a..b40fc8e39083101de377f64c70a9c60f35348e0f 100644 --- a/server/helpers/requests.ts +++ b/server/helpers/requests.ts @@ -6,9 +6,15 @@ import { REMOTE_SCHEME, CONFIG } from '../initializers' +import { PodInstance } from '../models' import { sign } from './peertube-crypto' -function makeRetryRequest (params, callback) { +type MakeRetryRequestParams = { + url: string, + method: 'GET'|'POST', + json: Object +} +function makeRetryRequest (params: MakeRetryRequestParams, callback: request.RequestCallback) { replay( request(params, callback), { @@ -20,14 +26,21 @@ function makeRetryRequest (params, callback) { ) } -function makeSecureRequest (params, callback) { +type MakeSecureRequestParams = { + method: 'GET'|'POST' + toPod: PodInstance + path: string + sign: boolean + data?: Object +} +function makeSecureRequest (params: MakeSecureRequestParams, callback: request.RequestCallback) { const requestParams = { url: REMOTE_SCHEME.HTTP + '://' + params.toPod.host + params.path, json: {} } 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.'), null, null) } // Add signature if it is specified in the params diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index bc76cfb267fabe92fd22b08c2e4cf007b04f0ed1..1dcbd31c4c8ad1a7f463502a30ed1ca883277aeb 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts @@ -1,13 +1,15 @@ +import * as express from 'express' + import { pseudoRandomBytes } from 'crypto' import { join } from 'path' import { logger } from './logger' -function badRequest (req, res, next) { +function badRequest (req: express.Request, res: express.Response, next: express.NextFunction) { res.type('json').status(400).end() } -function generateRandomString (size, callback) { +function generateRandomString (size: number, callback: (err: Error, randomString?: string) => void) { pseudoRandomBytes(size, function (err, raw) { if (err) return callback(err) @@ -15,11 +17,6 @@ function generateRandomString (size, callback) { }) } -function cleanForExit (webtorrentProcess) { - logger.info('Gracefully exiting.') - process.kill(-webtorrentProcess.pid) -} - function createEmptyCallback () { return function (err) { if (err) logger.error('Error in empty callback.', { error: err }) @@ -27,10 +24,10 @@ function createEmptyCallback () { } function isTestInstance () { - return (process.env.NODE_ENV === 'test') + return process.env.NODE_ENV === 'test' } -function getFormatedObjects (objects, objectsTotal) { +function getFormatedObjects (objects: any[], objectsTotal: number) { const formatedObjects = [] objects.forEach(function (object) { @@ -53,7 +50,6 @@ function root () { export { badRequest, createEmptyCallback, - cleanForExit, generateRandomString, isTestInstance, getFormatedObjects, diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts index 8c3d64b6004b2c187a59b4eb4db73946b39ef060..7007f2c0b2fa92abbfc9ff6025fa2612e574541d 100644 --- a/server/initializers/checker.ts +++ b/server/initializers/checker.ts @@ -23,7 +23,7 @@ function checkMissedConfig () { 'storage.certs', 'storage.videos', 'storage.logs', 'storage.thumbnails', 'storage.previews', 'admin.email', 'signup.enabled', 'transcoding.enabled', 'transcoding.threads' ] - const miss = [] + const miss: string[] = [] for (const key of required) { if (!config.has(key)) { @@ -35,7 +35,7 @@ function checkMissedConfig () { } // Check the available codecs -function checkFFmpeg (callback) { +function checkFFmpeg (callback: (err: Error) => void) { const Ffmpeg = require('fluent-ffmpeg') Ffmpeg.getAvailableCodecs(function (err, codecs) { @@ -57,7 +57,7 @@ function checkFFmpeg (callback) { }) } -function clientsExist (callback) { +function clientsExist (callback: (err: Error, clientsExist?: boolean) => void) { db.OAuthClient.countTotal(function (err, totalClients) { if (err) return callback(err) @@ -65,7 +65,7 @@ function clientsExist (callback) { }) } -function usersExist (callback) { +function usersExist (callback: (err: Error, usersExist?: boolean) => void) { db.User.countTotal(function (err, totalUsers) { if (err) return callback(err) diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 7ab019f4446e682865b215a1b736b6be50f1cce2..6dcb4bb91ef2a6b01a18395cf086e52eb2a2df14 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -202,7 +202,7 @@ const REQUEST_ENDPOINTS = { VIDEOS: 'videos' } -const REQUEST_ENDPOINT_ACTIONS = {} +const REQUEST_ENDPOINT_ACTIONS: { [ id: string ]: any } = {} REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS] = { ADD: 'add', UPDATE: 'update', diff --git a/server/initializers/database.ts b/server/initializers/database.ts index b0f47876e93d48d114c4d807b20d5b43d04cc86e..78ca5ab84879fb0361552fb1b5a5de6b372f9868 100644 --- a/server/initializers/database.ts +++ b/server/initializers/database.ts @@ -59,7 +59,7 @@ const sequelize = new Sequelize(dbname, username, password, { port: CONFIG.DATABASE.PORT, benchmark: isTestInstance(), - logging: function (message, benchmark) { + logging: function (message: string, benchmark: number) { let newMessage = message if (benchmark !== undefined) { newMessage += ' | ' + benchmark + 'ms' @@ -71,7 +71,7 @@ const sequelize = new Sequelize(dbname, username, password, { database.sequelize = sequelize -database.init = function (silent, callback) { +database.init = function (silent: boolean, callback: (err: Error) => void) { const modelDirectory = join(__dirname, '..', 'models') fs.readdir(modelDirectory, function (err, files) { diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index 2f9b589916b9bc6e28c0f50b945639f70cd31656..f105c82924d52e248c514802285034597cc18ded 100644 --- a/server/initializers/installer.ts +++ b/server/initializers/installer.ts @@ -9,7 +9,7 @@ import { USER_ROLES, CONFIG, LAST_MIGRATION_VERSION } from './constants' import { clientsExist, usersExist } from './checker' import { logger, createCertsIfNotExist, root } from '../helpers' -function installApplication (callback) { +function installApplication (callback: (err: Error) => void) { series([ function createDatabase (callbackAsync) { db.sequelize.sync().asCallback(callbackAsync) @@ -42,7 +42,7 @@ export { // --------------------------------------------------------------------------- -function createDirectoriesIfNotExist (callback) { +function createDirectoriesIfNotExist (callback: (err: Error) => void) { const storages = config.get('storage') each(Object.keys(storages), function (key, callbackEach) { @@ -51,7 +51,7 @@ function createDirectoriesIfNotExist (callback) { }, callback) } -function createOAuthClientIfNotExist (callback) { +function createOAuthClientIfNotExist (callback: (err: Error) => void) { clientsExist(function (err, exist) { if (err) return callback(err) @@ -80,7 +80,7 @@ function createOAuthClientIfNotExist (callback) { }) } -function createOAuthAdminIfNotExist (callback) { +function createOAuthAdminIfNotExist (callback: (err: Error) => void) { usersExist(function (err, exist) { if (err) return callback(err) diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts index 379d43af528f0e16456dd9e8c7a635870620dadf..d72c60638a2c58a23290a1308446d3abb7bc5e6c 100644 --- a/server/initializers/migrator.ts +++ b/server/initializers/migrator.ts @@ -8,7 +8,7 @@ import { LAST_MIGRATION_VERSION } from './constants' import { logger } from '../helpers' import { ApplicationInstance } from '../models' -function migrate (finalCallback) { +function migrate (finalCallback: (err: Error) => void) { waterfall([ function checkApplicationTableExists (callback) { @@ -56,7 +56,7 @@ function migrate (finalCallback) { }, function doMigrations (actualVersion, migrationScripts, callback) { - eachSeries(migrationScripts, function (entity, callbackEach) { + eachSeries(migrationScripts, function (entity: any, callbackEach) { executeMigration(actualVersion, entity, callbackEach) }, function (err) { if (err) return callback(err) @@ -76,7 +76,8 @@ export { // --------------------------------------------------------------------------- -function getMigrationScripts (callback) { +type GetMigrationScriptsCallback = (err: Error, filesToMigrate?: { version: string, script: string }[]) => void +function getMigrationScripts (callback: GetMigrationScriptsCallback) { fs.readdir(path.join(__dirname, 'migrations'), function (err, files) { if (err) return callback(err) @@ -95,7 +96,7 @@ function getMigrationScripts (callback) { }) } -function executeMigration (actualVersion, entity, callback) { +function executeMigration (actualVersion: number, entity: { version: string, script: string }, callback: (err: Error) => void) { const versionScript = parseInt(entity.version, 10) // Do not execute old migration scripts diff --git a/server/lib/friends.ts b/server/lib/friends.ts index 6b0fbd2bfc29fb20a46a2e9ca6a403afd5d994cc..e097f925488c8c108f19b24c69a7a8da1fdb7014 100644 --- a/server/lib/friends.ts +++ b/server/lib/friends.ts @@ -1,5 +1,6 @@ import { each, eachLimit, eachSeries, series, waterfall } from 'async' import * as request from 'request' +import * as Sequelize from 'sequelize' import { database as db } from '../initializers/database' import { @@ -19,9 +20,18 @@ import { } from '../helpers' import { RequestScheduler, + RequestSchedulerOptions, + RequestVideoQaduScheduler, - RequestVideoEventScheduler + RequestVideoQaduSchedulerOptions, + + RequestVideoEventScheduler, + RequestVideoEventSchedulerOptions } from './request' +import { PodInstance, VideoInstance } from '../models' + +type QaduParam = { videoId: string, type: string } +type EventParam = { videoId: string, type: string } const ENDPOINT_ACTIONS = REQUEST_ENDPOINT_ACTIONS[REQUEST_ENDPOINTS.VIDEOS] @@ -35,7 +45,7 @@ function activateSchedulers () { requestVideoEventScheduler.activate() } -function addVideoToFriends (videoData, transaction, callback) { +function addVideoToFriends (videoData: Object, transaction: Sequelize.Transaction, callback: (err: Error) => void) { const options = { type: ENDPOINT_ACTIONS.ADD, endpoint: REQUEST_ENDPOINTS.VIDEOS, @@ -45,7 +55,7 @@ function addVideoToFriends (videoData, transaction, callback) { createRequest(options, callback) } -function updateVideoToFriends (videoData, transaction, callback) { +function updateVideoToFriends (videoData: Object, transaction: Sequelize.Transaction, callback: (err: Error) => void) { const options = { type: ENDPOINT_ACTIONS.UPDATE, endpoint: REQUEST_ENDPOINTS.VIDEOS, @@ -55,35 +65,37 @@ function updateVideoToFriends (videoData, transaction, callback) { createRequest(options, callback) } -function removeVideoToFriends (videoParams) { +function removeVideoToFriends (videoParams: Object) { const options = { type: ENDPOINT_ACTIONS.REMOVE, endpoint: REQUEST_ENDPOINTS.VIDEOS, - data: videoParams + data: videoParams, + transaction: null } createRequest(options) } -function reportAbuseVideoToFriend (reportData, video) { +function reportAbuseVideoToFriend (reportData: Object, video: VideoInstance) { const options = { type: ENDPOINT_ACTIONS.REPORT_ABUSE, endpoint: REQUEST_ENDPOINTS.VIDEOS, data: reportData, - toIds: [ video.Author.podId ] + toIds: [ video.Author.podId ], + transaction: null } createRequest(options) } -function quickAndDirtyUpdateVideoToFriends (qaduParams, transaction?, callback?) { +function quickAndDirtyUpdateVideoToFriends (qaduParam: QaduParam, transaction?: Sequelize.Transaction, callback?: (err: Error) => void) { const options = { - videoId: qaduParams.videoId, - type: qaduParams.type, + videoId: qaduParam.videoId, + type: qaduParam.type, transaction } return createVideoQaduRequest(options, callback) } -function quickAndDirtyUpdatesVideoToFriends (qadusParams, transaction, finalCallback) { +function quickAndDirtyUpdatesVideoToFriends (qadusParams: QaduParam[], transaction: Sequelize.Transaction, finalCallback: (err: Error) => void) { const tasks = [] qadusParams.forEach(function (qaduParams) { @@ -97,16 +109,16 @@ function quickAndDirtyUpdatesVideoToFriends (qadusParams, transaction, finalCall series(tasks, finalCallback) } -function addEventToRemoteVideo (eventParams, transaction?, callback?) { +function addEventToRemoteVideo (eventParam: EventParam, transaction?: Sequelize.Transaction, callback?: (err: Error) => void) { const options = { - videoId: eventParams.videoId, - type: eventParams.type, + videoId: eventParam.videoId, + type: eventParam.type, transaction } createVideoEventRequest(options, callback) } -function addEventsToRemoteVideo (eventsParams, transaction, finalCallback) { +function addEventsToRemoteVideo (eventsParams: EventParam[], transaction: Sequelize.Transaction, finalCallback: (err: Error) => void) { const tasks = [] eventsParams.forEach(function (eventParams) { @@ -120,7 +132,7 @@ function addEventsToRemoteVideo (eventsParams, transaction, finalCallback) { series(tasks, finalCallback) } -function hasFriends (callback) { +function hasFriends (callback: (err: Error, hasFriends?: boolean) => void) { db.Pod.countAll(function (err, count) { if (err) return callback(err) @@ -129,7 +141,7 @@ function hasFriends (callback) { }) } -function makeFriends (hosts, callback) { +function makeFriends (hosts: string[], callback: (err: Error) => void) { const podsScore = {} logger.info('Make friends!') @@ -141,7 +153,7 @@ function makeFriends (hosts, callback) { eachSeries(hosts, function (host, callbackEach) { computeForeignPodsList(host, podsScore, callbackEach) - }, function (err) { + }, function (err: Error) { if (err) return callback(err) logger.debug('Pods scores computed.', { podsScore: podsScore }) @@ -153,7 +165,7 @@ function makeFriends (hosts, callback) { }) } -function quitFriends (callback) { +function quitFriends (callback: (err: Error) => void) { // Stop pool requests requestScheduler.deactivate() @@ -172,7 +184,7 @@ function quitFriends (callback) { function announceIQuitMyFriends (pods, callbackAsync) { const requestParams = { - method: 'POST', + method: 'POST' as 'POST', path: '/api/' + API_VERSION + '/remote/pods/remove', sign: true, toPod: null @@ -199,7 +211,7 @@ function quitFriends (callback) { pod.destroy().asCallback(callbackEach) }, callbackAsync) } - ], function (err) { + ], function (err: Error) { // Don't forget to re activate the scheduler, even if there was an error requestScheduler.activate() @@ -210,7 +222,7 @@ function quitFriends (callback) { }) } -function sendOwnedVideosToPod (podId) { +function sendOwnedVideosToPod (podId: number) { db.Video.listOwnedAndPopulateAuthorAndTags(function (err, videosList) { if (err) { logger.error('Cannot get the list of videos we own.') @@ -229,7 +241,8 @@ function sendOwnedVideosToPod (podId) { type: 'add', endpoint: REQUEST_ENDPOINTS.VIDEOS, data: remoteVideo, - toIds: [ podId ] + toIds: [ podId ], + transaction: null } createRequest(options) }) @@ -272,7 +285,7 @@ export { // --------------------------------------------------------------------------- -function computeForeignPodsList (host, podsScore, callback) { +function computeForeignPodsList (host: string, podsScore: { [ host: string ]: number }, callback: (err: Error) => void) { getForeignPodsList(host, function (err, res) { if (err) return callback(err) @@ -288,11 +301,11 @@ function computeForeignPodsList (host, podsScore, callback) { else podsScore[foreignPodHost] = 1 }) - return callback() + return callback(null) }) } -function computeWinningPods (hosts, podsScore) { +function computeWinningPods (hosts: string[], podsScore: { [ host: string ]: number }) { // Build the list of pods to add // Only add a pod if it exists in more than a half base pods const podsList = [] @@ -308,7 +321,7 @@ function computeWinningPods (hosts, podsScore) { return podsList } -function getForeignPodsList (host, callback) { +function getForeignPodsList (host: string, callback: (err: Error, foreignPodsList?: any) => void) { const path = '/api/' + API_VERSION + '/pods' request.get(REMOTE_SCHEME.HTTP + '://' + host + path, function (err, response, body) { @@ -323,16 +336,16 @@ function getForeignPodsList (host, callback) { }) } -function makeRequestsToWinningPods (cert, podsList, callback) { +function makeRequestsToWinningPods (cert: string, podsList: PodInstance[], callback: (err: Error) => void) { // Stop pool requests requestScheduler.deactivate() // Flush pool requests requestScheduler.forceSend() - eachLimit(podsList, REQUESTS_IN_PARALLEL, function (pod: { host: string }, callbackEach) { + eachLimit(podsList, REQUESTS_IN_PARALLEL, function (pod: PodInstance, callbackEach) { const params = { url: REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + API_VERSION + '/pods/', - method: 'POST', + method: 'POST' as 'POST', json: { host: CONFIG.WEBSERVER.HOST, email: CONFIG.ADMIN.EMAIL, @@ -371,15 +384,22 @@ function makeRequestsToWinningPods (cert, podsList, callback) { requestScheduler.activate() logger.debug('makeRequestsToWinningPods finished.') - return callback() + return callback(null) }) } // Wrapper that populate "toIds" argument with all our friends if it is not specified -// { type, endpoint, data, toIds, transaction } -function createRequest (options, callback?) { +type CreateRequestOptions = { + type: string + endpoint: string + data: Object + toIds?: number[] + transaction: Sequelize.Transaction +} +function createRequest (options: CreateRequestOptions, callback?: (err: Error) => void) { if (!callback) callback = function () { /* empty */ } - if (options.toIds) return requestScheduler.createRequest(options, callback) + + if (options.toIds !== undefined) return requestScheduler.createRequest(options as RequestSchedulerOptions, callback) // If the "toIds" pods is not specified, we send the request to all our friends db.Pod.listAllIds(options.transaction, function (err, podIds) { @@ -393,18 +413,18 @@ function createRequest (options, callback?) { }) } -function createVideoQaduRequest (options, callback) { +function createVideoQaduRequest (options: RequestVideoQaduSchedulerOptions, callback: (err: Error) => void) { if (!callback) callback = createEmptyCallback() requestVideoQaduScheduler.createRequest(options, callback) } -function createVideoEventRequest (options, callback) { +function createVideoEventRequest (options: RequestVideoEventSchedulerOptions, callback: (err: Error) => void) { if (!callback) callback = createEmptyCallback() requestVideoEventScheduler.createRequest(options, callback) } -function isMe (host) { +function isMe (host: string) { return host === CONFIG.WEBSERVER.HOST } diff --git a/server/lib/jobs/handlers/index.ts b/server/lib/jobs/handlers/index.ts index ae5440031ce81b5d8c1a7415d78801ddd7ce76f5..7d0263b1554e9053ab6b64fcb74322f6c0ae023b 100644 --- a/server/lib/jobs/handlers/index.ts +++ b/server/lib/jobs/handlers/index.ts @@ -1,6 +1,14 @@ import * as videoTranscoder from './video-transcoder' -const jobHandlers = { +import { VideoInstance } from '../../../models' + +export interface JobHandler<T> { + process (data: object, callback: (err: Error, videoInstance?: T) => void) + onError (err: Error, jobId: number, video: T, callback: (err: Error) => void) + onSuccess (data: any, jobId: number, video: T, callback: (err: Error) => void) +} + +const jobHandlers: { [ handlerName: string ]: JobHandler<any> } = { videoTranscoder } diff --git a/server/lib/jobs/handlers/video-transcoder.ts b/server/lib/jobs/handlers/video-transcoder.ts index 43599356a729df8723e172395b7a916c2a4c4c1a..efa18ef2d66e3b4017ca619cbfbf873f94a2f024 100644 --- a/server/lib/jobs/handlers/video-transcoder.ts +++ b/server/lib/jobs/handlers/video-transcoder.ts @@ -1,8 +1,9 @@ import { database as db } from '../../../initializers/database' import { logger } from '../../../helpers' import { addVideoToFriends } from '../../../lib' +import { VideoInstance } from '../../../models' -function process (data, callback) { +function process (data: { id: string }, callback: (err: Error, videoInstance?: VideoInstance) => void) { db.Video.loadAndPopulateAuthorAndPodAndTags(data.id, function (err, video) { if (err) return callback(err) @@ -12,12 +13,12 @@ function process (data, callback) { }) } -function onError (err, jobId, video, callback) { +function onError (err: Error, jobId: number, video: VideoInstance, callback: () => void) { logger.error('Error when transcoding video file in job %d.', jobId, { error: err }) return callback() } -function onSuccess (data, jobId, video, callback) { +function onSuccess (data: any, jobId: number, video: VideoInstance, callback: (err: Error) => void) { logger.info('Job %d is a success.', jobId) video.toAddRemoteJSON(function (err, remoteVideo) { diff --git a/server/lib/jobs/job-scheduler.ts b/server/lib/jobs/job-scheduler.ts index ad5f7f6d98bb0afcd137c472e1b1775427f6b8c0..2f01387e7258cfc2722efc47ed84f439e289a106 100644 --- a/server/lib/jobs/job-scheduler.ts +++ b/server/lib/jobs/job-scheduler.ts @@ -1,4 +1,5 @@ import { forever, queue } from 'async' +import * as Sequelize from 'sequelize' import { database as db } from '../../initializers/database' import { @@ -7,7 +8,10 @@ import { JOB_STATES } from '../../initializers' import { logger } from '../../helpers' -import { jobHandlers } from './handlers' +import { JobInstance } from '../../models' +import { JobHandler, jobHandlers } from './handlers' + +type JobQueueCallback = (err: Error) => void class JobScheduler { @@ -24,7 +28,7 @@ class JobScheduler { logger.info('Jobs scheduler activated.') - const jobsQueue = queue(this.processJob.bind(this)) + const jobsQueue = queue<JobInstance, JobQueueCallback>(this.processJob.bind(this)) // Finish processing jobs from a previous start const state = JOB_STATES.PROCESSING @@ -58,7 +62,7 @@ class JobScheduler { }) } - createJob (transaction, handlerName: string, handlerInputData: object, callback) { + createJob (transaction: Sequelize.Transaction, handlerName: string, handlerInputData: object, callback: (err: Error) => void) { const createQuery = { state: JOB_STATES.PENDING, handlerName, @@ -69,7 +73,7 @@ class JobScheduler { db.Job.create(createQuery, options).asCallback(callback) } - private enqueueJobs (err, jobsQueue, jobs) { + private enqueueJobs (err: Error, jobsQueue: AsyncQueue<JobInstance>, jobs: JobInstance[]) { if (err) { logger.error('Cannot list pending jobs.', { error: err }) } else { @@ -79,7 +83,7 @@ class JobScheduler { } } - private processJob (job, callback) { + private processJob (job: JobInstance, callback: (err: Error) => void) { const jobHandler = jobHandlers[job.handlerName] logger.info('Processing job %d with handler %s.', job.id, job.handlerName) @@ -89,8 +93,8 @@ class JobScheduler { if (err) return this.cannotSaveJobError(err, callback) if (jobHandler === undefined) { - logger.error('Unknown job handler for job %s.', jobHandler.handlerName) - return callback() + logger.error('Unknown job handler for job %s.', job.handlerName) + return callback(null) } return jobHandler.process(job.handlerInputData, (err, result) => { @@ -104,7 +108,7 @@ class JobScheduler { }) } - private onJobError (jobHandler, job, jobResult, callback) { + private onJobError (jobHandler: JobHandler<any>, job: JobInstance, jobResult: any, callback: (err: Error) => void) { job.state = JOB_STATES.ERROR job.save().asCallback(err => { @@ -114,7 +118,7 @@ class JobScheduler { }) } - private onJobSuccess (jobHandler, job, jobResult, callback) { + private onJobSuccess (jobHandler: JobHandler<any>, job: JobInstance, jobResult: any, callback: (err: Error) => void) { job.state = JOB_STATES.SUCCESS job.save().asCallback(err => { @@ -124,7 +128,7 @@ class JobScheduler { }) } - private cannotSaveJobError (err, callback) { + private cannotSaveJobError (err: Error, callback: (err: Error) => void) { logger.error('Cannot save new job state.', { error: err }) return callback(err) } diff --git a/server/lib/oauth-model.ts b/server/lib/oauth-model.ts index 3bdf0f47867973682aa7aa823c5172ef2d424e58..7cf42e94c284ed9b7a169403bdf5efcea91e291a 100644 --- a/server/lib/oauth-model.ts +++ b/server/lib/oauth-model.ts @@ -1,27 +1,30 @@ +import { OAuthClientInstance, UserInstance } from '../models' import { database as db } from '../initializers/database' import { logger } from '../helpers' +type TokenInfo = { accessToken: string, refreshToken: string, accessTokenExpiresAt: Date, refreshTokenExpiresAt: Date } + // --------------------------------------------------------------------------- -function getAccessToken (bearerToken) { +function getAccessToken (bearerToken: string) { logger.debug('Getting access token (bearerToken: ' + bearerToken + ').') return db.OAuthToken.getByTokenAndPopulateUser(bearerToken) } -function getClient (clientId, clientSecret) { +function getClient (clientId: string, clientSecret: string) { logger.debug('Getting Client (clientId: ' + clientId + ', clientSecret: ' + clientSecret + ').') return db.OAuthClient.getByIdAndSecret(clientId, clientSecret) } -function getRefreshToken (refreshToken) { +function getRefreshToken (refreshToken: string) { logger.debug('Getting RefreshToken (refreshToken: ' + refreshToken + ').') return db.OAuthToken.getByRefreshTokenAndPopulateClient(refreshToken) } -function getUser (username, password) { +function getUser (username: string, password: string) { logger.debug('Getting User (username: ' + username + ', password: ' + password + ').') return db.User.getByUsername(username).then(function (user) { @@ -42,7 +45,7 @@ function getUser (username, password) { }) } -function revokeToken (token) { +function revokeToken (token: TokenInfo) { return db.OAuthToken.getByRefreshTokenAndPopulateUser(token.refreshToken).then(function (tokenDB) { if (tokenDB) tokenDB.destroy() @@ -60,7 +63,7 @@ function revokeToken (token) { }) } -function saveToken (token, client, user) { +function saveToken (token: TokenInfo, client: OAuthClientInstance, user: UserInstance) { logger.debug('Saving token ' + token.accessToken + ' for client ' + client.id + ' and user ' + user.id + '.') const tokenToCreate = { diff --git a/server/lib/request/base-request-scheduler.ts b/server/lib/request/base-request-scheduler.ts index b7ef6abf902e7b5011a4e83310a421b475cb5875..26bdc2bff7e13544db6407ad9b81594b2b48f318 100644 --- a/server/lib/request/base-request-scheduler.ts +++ b/server/lib/request/base-request-scheduler.ts @@ -2,6 +2,7 @@ import * as eachLimit from 'async/eachLimit' import { database as db } from '../../initializers/database' import { logger, makeSecureRequest } from '../../helpers' +import { PodInstance } from '../../models' import { API_VERSION, REQUESTS_IN_PARALLEL, @@ -9,11 +10,12 @@ import { } from '../../initializers' abstract class BaseRequestScheduler { + requestInterval: number + limitPods: number + limitPerPod: number + protected lastRequestTimestamp: number protected timer: NodeJS.Timer - protected requestInterval: number - protected limitPods: number - protected limitPerPod: number protected description: string constructor () { @@ -53,24 +55,24 @@ abstract class BaseRequestScheduler { return REQUESTS_INTERVAL - (Date.now() - this.lastRequestTimestamp) } - remainingRequestsCount (callback) { + remainingRequestsCount (callback: (err: Error, total: number) => void) { return this.getRequestModel().countTotalRequests(callback) } - flush (callback) { + flush (callback: (err: Error) => void) { this.getRequestModel().removeAll(callback) } // --------------------------------------------------------------------------- // Make a requests to friends of a certain type - protected makeRequest (toPod, requestEndpoint, requestsToMake, callback) { + protected makeRequest (toPod: PodInstance, requestEndpoint: string, requestsToMake: Object, callback) { if (!callback) callback = function () { /* empty */ } const params = { toPod: toPod, sign: true, // Prove our identity - method: 'POST', + method: 'POST' as 'POST', path: '/api/' + API_VERSION + '/remote/' + requestEndpoint, data: requestsToMake // Requests we need to make } diff --git a/server/lib/request/index.ts b/server/lib/request/index.ts index c98f956db79935d0ad55934a75a7ee273b184e0f..110d0ed78befc55b1afb839b853873ad18bee8b0 100644 --- a/server/lib/request/index.ts +++ b/server/lib/request/index.ts @@ -1,3 +1,4 @@ +export * from './base-request-scheduler' export * from './request-scheduler' export * from './request-video-event-scheduler' export * from './request-video-qadu-scheduler' diff --git a/server/lib/request/request-scheduler.ts b/server/lib/request/request-scheduler.ts index 26ffbfb868f892e5f384a3caf059dd728600d15d..69d840eeb140705547c14ab15b19e63fb56f011d 100644 --- a/server/lib/request/request-scheduler.ts +++ b/server/lib/request/request-scheduler.ts @@ -1,3 +1,5 @@ +import * as Sequelize from 'sequelize' + import { database as db } from '../../initializers/database' import { BaseRequestScheduler } from './base-request-scheduler' import { logger } from '../../helpers' @@ -6,6 +8,14 @@ import { REQUESTS_LIMIT_PER_POD } from '../../initializers' +export type RequestSchedulerOptions = { + type: string + endpoint: string + data: Object + toIds: number[] + transaction: Sequelize.Transaction +} + class RequestScheduler extends BaseRequestScheduler { constructor () { super() @@ -25,7 +35,7 @@ class RequestScheduler extends BaseRequestScheduler { return db.RequestToPod } - buildRequestObjects (requests) { + buildRequestObjects (requests: { [ toPodId: number ]: any }) { const requestsToMakeGrouped = {} Object.keys(requests).forEach(toPodId => { @@ -51,14 +61,7 @@ class RequestScheduler extends BaseRequestScheduler { return requestsToMakeGrouped } - // { type, endpoint, data, toIds, transaction } - createRequest (options, callback) { - const type = options.type - const endpoint = options.endpoint - const data = options.data - const toIds = options.toIds - const transaction = options.transaction - + createRequest ({ type, endpoint, data, toIds, transaction }: RequestSchedulerOptions, callback: (err: Error) => void) { // TODO: check the setPods works const podIds = [] @@ -77,7 +80,7 @@ class RequestScheduler extends BaseRequestScheduler { } } - const dbRequestOptions = { + const dbRequestOptions: Sequelize.CreateOptions = { transaction } diff --git a/server/lib/request/request-video-event-scheduler.ts b/server/lib/request/request-video-event-scheduler.ts index bde50b1d33dfc3ae9c619758f249c89d54257f5c..9da82585ef321b8103fa789af4306a057e5d8f5d 100644 --- a/server/lib/request/request-video-event-scheduler.ts +++ b/server/lib/request/request-video-event-scheduler.ts @@ -1,3 +1,5 @@ +import * as Sequelize from 'sequelize' + import { database as db } from '../../initializers/database' import { BaseRequestScheduler } from './base-request-scheduler' import { @@ -6,6 +8,13 @@ import { REQUEST_VIDEO_EVENT_ENDPOINT } from '../../initializers' +export type RequestVideoEventSchedulerOptions = { + type: string + videoId: string + count?: number + transaction?: Sequelize.Transaction +} + class RequestVideoEventScheduler extends BaseRequestScheduler { constructor () { super() @@ -25,7 +34,7 @@ class RequestVideoEventScheduler extends BaseRequestScheduler { return db.RequestVideoEvent } - buildRequestObjects (eventsToProcess) { + buildRequestObjects (eventsToProcess: { [ toPodId: number ]: any }[]) { const requestsToMakeGrouped = {} /* Example: @@ -87,16 +96,10 @@ class RequestVideoEventScheduler extends BaseRequestScheduler { return requestsToMakeGrouped } - // { type, videoId, count?, transaction? } - createRequest (options, callback) { - const type = options.type - const videoId = options.videoId - const transaction = options.transaction - let count = options.count - + createRequest ({ type, videoId, count, transaction }: RequestVideoEventSchedulerOptions, callback: (err: Error) => void) { if (count === undefined) count = 1 - const dbRequestOptions: { transaction?: any } = {} + const dbRequestOptions: Sequelize.CreateOptions = {} if (transaction) dbRequestOptions.transaction = transaction const createQuery = { diff --git a/server/lib/request/request-video-qadu-scheduler.ts b/server/lib/request/request-video-qadu-scheduler.ts index dab526088f6703e8f6da429516e27db6d8b0ca95..436fd8e5035755370bbdf50acafdfc8ffbd002dc 100644 --- a/server/lib/request/request-video-qadu-scheduler.ts +++ b/server/lib/request/request-video-qadu-scheduler.ts @@ -1,3 +1,5 @@ +import * as Sequelize from 'sequelize' + import { database as db } from '../../initializers/database' import { BaseRequestScheduler } from './base-request-scheduler' import { logger } from '../../helpers' @@ -8,6 +10,12 @@ import { REQUEST_VIDEO_QADU_TYPES } from '../../initializers' +export type RequestVideoQaduSchedulerOptions = { + type: string + videoId: string + transaction?: Sequelize.Transaction +} + class RequestVideoQaduScheduler extends BaseRequestScheduler { constructor () { super() @@ -27,7 +35,7 @@ class RequestVideoQaduScheduler extends BaseRequestScheduler { return db.RequestVideoQadu } - buildRequestObjects (requests) { + buildRequestObjects (requests: { [ toPodId: number ]: any }[]) { const requestsToMakeGrouped = {} Object.keys(requests).forEach(toPodId => { @@ -96,17 +104,12 @@ class RequestVideoQaduScheduler extends BaseRequestScheduler { return requestsToMakeGrouped } - // { type, videoId, transaction? } - createRequest (options, callback) { - const type = options.type - const videoId = options.videoId - const transaction = options.transaction - - const dbRequestOptions: { transaction?: any } = {} + createRequest ({ type, videoId, transaction }: RequestVideoQaduSchedulerOptions, callback: (err: Error) => void) { + const dbRequestOptions: Sequelize.BulkCreateOptions = {} if (transaction) dbRequestOptions.transaction = transaction // Send the update to all our friends - db.Pod.listAllIds(options.transaction, function (err, podIds) { + db.Pod.listAllIds(transaction, function (err, podIds) { if (err) return callback(err) const queries = [] diff --git a/server/middlewares/admin.ts b/server/middlewares/admin.ts index 28b6a9a120a24b8a23fb953fe463504cae897125..812397352c6d62588297f64ef6227f7c44fb38fb 100644 --- a/server/middlewares/admin.ts +++ b/server/middlewares/admin.ts @@ -1,6 +1,9 @@ +import 'express-validator' +import * as express from 'express' + import { logger } from '../helpers' -function ensureIsAdmin (req, res, next) { +function ensureIsAdmin (req: express.Request, res: express.Response, next: express.NextFunction) { const user = res.locals.oauth.token.user if (user.isAdmin() === false) { logger.info('A non admin user is trying to access to an admin content.') diff --git a/server/middlewares/index.ts b/server/middlewares/index.ts index 2c1c5fa536c1cd922b198261024f8d23bbe7678d..d71dd245265a6fbbebef6bf1acf2ef3188304a98 100644 --- a/server/middlewares/index.ts +++ b/server/middlewares/index.ts @@ -1,8 +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'; +export * from './validators' +export * from './admin' +export * from './oauth' +export * from './pagination' +export * from './pods' +export * from './search' +export * from './secure' +export * from './sort' diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts index 468e418106c69c84ceb596b705665ebadfd7de40..d545b3e58f55f4ff150a2078e400646b520346f3 100644 --- a/server/middlewares/oauth.ts +++ b/server/middlewares/oauth.ts @@ -1,3 +1,5 @@ +import 'express-validator' +import * as express from 'express' import * as OAuthServer from 'express-oauth-server' import { OAUTH_LIFETIME } from '../initializers' @@ -9,7 +11,7 @@ const oAuthServer = new OAuthServer({ model: require('../lib/oauth-model') }) -function authenticate (req, res, next) { +function authenticate (req: express.Request, res: express.Response, next: express.NextFunction) { oAuthServer.authenticate()(req, res, function (err) { if (err) { logger.error('Cannot authenticate.', { error: err }) @@ -22,7 +24,7 @@ function authenticate (req, res, next) { }) } -function token (req, res, next) { +function token (req: express.Request, res: express.Response, next: express.NextFunction) { return oAuthServer.token()(req, res, next) } diff --git a/server/middlewares/pagination.ts b/server/middlewares/pagination.ts index cadd769805ae7f393e14187a867db86c6d60f56d..26a8cacf0bf532d34121760eb6092a3537e95670 100644 --- a/server/middlewares/pagination.ts +++ b/server/middlewares/pagination.ts @@ -1,6 +1,9 @@ +import 'express-validator' +import * as express from 'express' + import { PAGINATION_COUNT_DEFAULT } from '../initializers' -function setPagination (req, res, next) { +function setPagination (req: express.Request, res: express.Response, next: express.NextFunction) { if (!req.query.start) req.query.start = 0 else req.query.start = parseInt(req.query.start, 10) diff --git a/server/middlewares/pods.ts b/server/middlewares/pods.ts index c255be8998023a7bb8672b1cb8149fe78727c4fb..eaf9aa144a7806b9532b8356d1375543e9c1ec50 100644 --- a/server/middlewares/pods.ts +++ b/server/middlewares/pods.ts @@ -1,6 +1,9 @@ +import 'express-validator' +import * as express from 'express' + import { REMOTE_SCHEME } from '../initializers' -function setBodyHostsPort (req, res, next) { +function setBodyHostsPort (req: express.Request, res: express.Response, next: express.NextFunction) { if (!req.body.hosts) return next() for (let i = 0; i < req.body.hosts.length; i++) { @@ -17,7 +20,7 @@ function setBodyHostsPort (req, res, next) { return next() } -function setBodyHostPort (req, res, next) { +function setBodyHostPort (req: express.Request, res: express.Response, next: express.NextFunction) { if (!req.body.host) return next() const hostWithPort = getHostWithPort(req.body.host) @@ -41,7 +44,7 @@ export { // --------------------------------------------------------------------------- -function getHostWithPort (host) { +function getHostWithPort (host: string) { const splitted = host.split(':') // The port was not specified diff --git a/server/middlewares/search.ts b/server/middlewares/search.ts index 05a2e744273077df1984909b6e192ff4fc7212da..6fe83d25b43e01e5969536548e357d467a05b0e0 100644 --- a/server/middlewares/search.ts +++ b/server/middlewares/search.ts @@ -1,4 +1,7 @@ -function setVideosSearch (req, res, next) { +import 'express-validator' +import * as express from 'express' + +function setVideosSearch (req: express.Request, res: express.Response, next: express.NextFunction) { if (!req.query.field) req.query.field = 'name' return next() diff --git a/server/middlewares/secure.ts b/server/middlewares/secure.ts index bd7cfa918159247bb5ef0c70f3b1eb5ae6b6a826..fbfd08c7b4cb7c44a410dd923b4164a3a948477d 100644 --- a/server/middlewares/secure.ts +++ b/server/middlewares/secure.ts @@ -1,10 +1,13 @@ +import 'express-validator' +import * as express from 'express' + import { database as db } from '../initializers' import { logger, checkSignature as peertubeCryptoCheckSignature } from '../helpers' -function checkSignature (req, res, next) { +function checkSignature (req: express.Request, res: express.Response, next: express.NextFunction) { const host = req.body.signature.host db.Pod.loadByHost(host, function (err, pod) { if (err) { diff --git a/server/middlewares/sort.ts b/server/middlewares/sort.ts index ab9ccf5242bee9af0f6f56eab779534037dd19f1..632b2fae4158fd2bbfa0ff18e4dbb23844f9d0ca 100644 --- a/server/middlewares/sort.ts +++ b/server/middlewares/sort.ts @@ -1,16 +1,19 @@ -function setUsersSort (req, res, next) { +import 'express-validator' +import * as express from 'express' + +function setUsersSort (req: express.Request, res: express.Response, next: express.NextFunction) { if (!req.query.sort) req.query.sort = '-createdAt' return next() } -function setVideoAbusesSort (req, res, next) { +function setVideoAbusesSort (req: express.Request, res: express.Response, next: express.NextFunction) { if (!req.query.sort) req.query.sort = '-createdAt' return next() } -function setVideosSort (req, res, next) { +function setVideosSort (req: express.Request, res: express.Response, next: express.NextFunction) { if (!req.query.sort) req.query.sort = '-createdAt' return next() diff --git a/server/middlewares/validators/pagination.ts b/server/middlewares/validators/pagination.ts index de719c05bc42fd7f80c2a414332205c535655e5d..cca8295ffddc731bc309c3e189fb58210b9fffb0 100644 --- a/server/middlewares/validators/pagination.ts +++ b/server/middlewares/validators/pagination.ts @@ -1,7 +1,10 @@ +import 'express-validator' +import * as express from 'express' + import { checkErrors } from './utils' import { logger } from '../../helpers' -function paginationValidator (req, res, next) { +function paginationValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkQuery('start', 'Should have a number start').optional().isInt() req.checkQuery('count', 'Should have a number count').optional().isInt() diff --git a/server/middlewares/validators/pods.ts b/server/middlewares/validators/pods.ts index c55a88b85c6d29d0e582f2a7b304c394df7c83a5..d8eb90168a1c1014453461fc1d0d25fe80683432 100644 --- a/server/middlewares/validators/pods.ts +++ b/server/middlewares/validators/pods.ts @@ -1,3 +1,6 @@ +import 'express-validator' +import * as express from 'express' + import { database as db } from '../../initializers/database' import { checkErrors } from './utils' import { logger } from '../../helpers' @@ -5,7 +8,7 @@ import { CONFIG } from '../../initializers' import { hasFriends } from '../../lib' import { isTestInstance } from '../../helpers' -function makeFriendsValidator (req, res, next) { +function makeFriendsValidator (req: express.Request, res: express.Response, next: express.NextFunction) { // Force https if the administrator wants to make friends if (isTestInstance() === false && CONFIG.WEBSERVER.SCHEME === 'http') { return res.status(400).send('Cannot make friends with a non HTTPS webserver.') @@ -32,7 +35,7 @@ function makeFriendsValidator (req, res, next) { }) } -function podsAddValidator (req, res, next) { +function podsAddValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkBody('host', 'Should have a host').isHostValid() req.checkBody('email', 'Should have an email').isEmail() req.checkBody('publicKey', 'Should have a public key').notEmpty() diff --git a/server/middlewares/validators/remote/signature.ts b/server/middlewares/validators/remote/signature.ts index 6e3ebe7db3b747c927887bfef2790e40b2cc518c..eb5c196ebd6c67236e1771eef885a375a26552a1 100644 --- a/server/middlewares/validators/remote/signature.ts +++ b/server/middlewares/validators/remote/signature.ts @@ -1,7 +1,10 @@ +import 'express-validator' +import * as express from 'express' + import { logger } from '../../../helpers' import { checkErrors } from '../utils' -function signatureValidator (req, res, next) { +function signatureValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkBody('signature.host', 'Should have a signature host').isURL() req.checkBody('signature.signature', 'Should have a signature').notEmpty() diff --git a/server/middlewares/validators/remote/videos.ts b/server/middlewares/validators/remote/videos.ts index 3380c29e27850a5785bc87075fd72e06a50512b6..2037c0085e98b9cf71f2e44b673c6e9bdc3b84f5 100644 --- a/server/middlewares/validators/remote/videos.ts +++ b/server/middlewares/validators/remote/videos.ts @@ -1,7 +1,10 @@ +import 'express-validator' +import * as express from 'express' + import { logger } from '../../../helpers' import { checkErrors } from '../utils' -function remoteVideosValidator (req, res, next) { +function remoteVideosValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkBody('data').isEachRemoteRequestVideosValid() logger.debug('Checking remoteVideos parameters', { parameters: req.body }) @@ -9,7 +12,7 @@ function remoteVideosValidator (req, res, next) { checkErrors(req, res, next) } -function remoteQaduVideosValidator (req, res, next) { +function remoteQaduVideosValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkBody('data').isEachRemoteRequestVideosQaduValid() logger.debug('Checking remoteQaduVideos parameters', { parameters: req.body }) @@ -17,7 +20,7 @@ function remoteQaduVideosValidator (req, res, next) { checkErrors(req, res, next) } -function remoteEventsVideosValidator (req, res, next) { +function remoteEventsVideosValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkBody('data').isEachRemoteRequestVideosEventsValid() logger.debug('Checking remoteEventsVideos parameters', { parameters: req.body }) diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index ebc7333c7c07a88104474b55dac130c42981fd20..3baee9fb3df437236e675b0d4223f2fe61c26721 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts @@ -1,3 +1,6 @@ +import 'express-validator' +import * as express from 'express' + import { checkErrors } from './utils' import { logger } from '../../helpers' import { SORTABLE_COLUMNS } from '../../initializers' @@ -7,15 +10,15 @@ const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS) const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES) const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS) -function usersSortValidator (req, res, next) { +function usersSortValidator (req: express.Request, res: express.Response, next: express.NextFunction) { checkSort(req, res, next, SORTABLE_USERS_COLUMNS) } -function videoAbusesSortValidator (req, res, next) { +function videoAbusesSortValidator (req: express.Request, res: express.Response, next: express.NextFunction) { checkSort(req, res, next, SORTABLE_VIDEO_ABUSES_COLUMNS) } -function videosSortValidator (req, res, next) { +function videosSortValidator (req: express.Request, res: express.Response, next: express.NextFunction) { checkSort(req, res, next, SORTABLE_VIDEOS_COLUMNS) } @@ -29,7 +32,7 @@ export { // --------------------------------------------------------------------------- -function checkSort (req, res, next, sortableColumns) { +function checkSort (req: express.Request, res: express.Response, next: express.NextFunction, sortableColumns: string[]) { req.checkQuery('sort', 'Should have correct sortable column').optional().isIn(sortableColumns) logger.debug('Checking sort parameters', { parameters: req.query }) @@ -37,7 +40,7 @@ function checkSort (req, res, next, sortableColumns) { checkErrors(req, res, next) } -function createSortableColumns (sortableColumns) { +function createSortableColumns (sortableColumns: string[]) { const sortableColumnDesc = sortableColumns.map(sortableColumn => '-' + sortableColumn) return sortableColumns.concat(sortableColumnDesc) diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index e0d1d917a31d81e03b25167460d279ae7832d296..b7b9ef370079197fc390a78e1cf78bf4db013b7f 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts @@ -1,8 +1,11 @@ +import 'express-validator' +import * as express from 'express' + import { database as db } from '../../initializers/database' import { checkErrors } from './utils' import { logger } from '../../helpers' -function usersAddValidator (req, res, next) { +function usersAddValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkBody('username', 'Should have a valid username').isUserUsernameValid() req.checkBody('password', 'Should have a valid password').isUserPasswordValid() req.checkBody('email', 'Should have a valid email').isEmail() @@ -23,7 +26,7 @@ function usersAddValidator (req, res, next) { }) } -function usersRemoveValidator (req, res, next) { +function usersRemoveValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkParams('id', 'Should have a valid id').notEmpty().isInt() logger.debug('Checking usersRemove parameters', { parameters: req.params }) @@ -44,7 +47,7 @@ function usersRemoveValidator (req, res, next) { }) } -function usersUpdateValidator (req, res, next) { +function usersUpdateValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkParams('id', 'Should have a valid id').notEmpty().isInt() // Add old password verification req.checkBody('password', 'Should have a valid password').optional().isUserPasswordValid() @@ -55,7 +58,7 @@ function usersUpdateValidator (req, res, next) { checkErrors(req, res, next) } -function usersVideoRatingValidator (req, res, next) { +function usersVideoRatingValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkParams('videoId', 'Should have a valid video id').notEmpty().isUUID(4) logger.debug('Checking usersVideoRating parameters', { parameters: req.params }) diff --git a/server/middlewares/validators/utils.ts b/server/middlewares/validators/utils.ts index 710e65529684d5633a03fb630da7d7ab00328818..0424d59429f6e914fa7f855db71afcb1af4519cb 100644 --- a/server/middlewares/validators/utils.ts +++ b/server/middlewares/validators/utils.ts @@ -1,9 +1,10 @@ +import 'express-validator' +import * as express from 'express' import { inspect } from 'util' import { logger } from '../../helpers' -function checkErrors (req, res, next, statusCode?) { - if (statusCode === undefined) statusCode = 400 +function checkErrors (req: express.Request, res: express.Response, next: express.NextFunction, statusCode = 400) { const errors = req.validationErrors() if (errors) { diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts index 47825975c002798c65722ef65035ca9f3a2fff86..e99cdefb18e37f1d1bdfe82b6c7f9436ff379c7f 100644 --- a/server/middlewares/validators/videos.ts +++ b/server/middlewares/validators/videos.ts @@ -1,9 +1,13 @@ +import 'express-validator' +import * as multer from 'multer' +import * as express from 'express' + import { database as db } from '../../initializers/database' import { checkErrors } from './utils' import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers' import { logger, isVideoDurationValid } from '../../helpers' -function videosAddValidator (req, res, next) { +function videosAddValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkBody('videofile', 'Should have a valid file').isVideoFile(req.files) req.checkBody('name', 'Should have a valid name').isVideoNameValid() req.checkBody('category', 'Should have a valid category').isVideoCategoryValid() @@ -27,13 +31,13 @@ function videosAddValidator (req, res, next) { 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 next() }) }) } -function videosUpdateValidator (req, res, next) { +function videosUpdateValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkBody('name', 'Should have a valid name').optional().isVideoNameValid() req.checkBody('category', 'Should have a valid category').optional().isVideoCategoryValid() @@ -61,7 +65,7 @@ function videosUpdateValidator (req, res, next) { }) } -function videosGetValidator (req, res, next) { +function videosGetValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) logger.debug('Checking videosGet parameters', { parameters: req.params }) @@ -71,7 +75,7 @@ function videosGetValidator (req, res, next) { }) } -function videosRemoveValidator (req, res, next) { +function videosRemoveValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) logger.debug('Checking videosRemove parameters', { parameters: req.params }) @@ -88,7 +92,7 @@ function videosRemoveValidator (req, res, next) { }) } -function videosSearchValidator (req, res, next) { +function videosSearchValidator (req: express.Request, res: express.Response, next: express.NextFunction) { const searchableColumns = SEARCHABLE_COLUMNS.VIDEOS req.checkParams('value', 'Should have a valid search').notEmpty() req.checkQuery('field', 'Should have correct searchable column').optional().isIn(searchableColumns) @@ -98,7 +102,7 @@ function videosSearchValidator (req, res, next) { checkErrors(req, res, next) } -function videoAbuseReportValidator (req, res, next) { +function videoAbuseReportValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkBody('reason', 'Should have a valid reason').isVideoAbuseReasonValid() @@ -109,7 +113,7 @@ function videoAbuseReportValidator (req, res, next) { }) } -function videoRateValidator (req, res, next) { +function videoRateValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) req.checkBody('rating', 'Should have a valid rate type').isVideoRatingTypeValid() @@ -120,7 +124,7 @@ function videoRateValidator (req, res, next) { }) } -function videosBlacklistValidator (req, res, next) { +function videosBlacklistValidator (req: express.Request, res: express.Response, next: express.NextFunction) { req.checkParams('id', 'Should have a valid id').notEmpty().isUUID(4) logger.debug('Checking videosBlacklist parameters', { parameters: req.params }) @@ -150,7 +154,7 @@ export { // --------------------------------------------------------------------------- -function checkVideoExists (id, res, callback) { +function checkVideoExists (id: string, res: express.Response, callback: () => void) { db.Video.loadAndPopulateAuthorAndPodAndTags(id, function (err, video) { if (err) { logger.error('Error in video request validator.', { error: err }) @@ -164,7 +168,7 @@ function checkVideoExists (id, res, callback) { }) } -function checkUserCanDeleteVideo (userId, res, callback) { +function checkUserCanDeleteVideo (userId: number, res: express.Response, callback: () => void) { // Retrieve the user who did the request db.User.loadById(userId, function (err, user) { if (err) { @@ -190,7 +194,7 @@ function checkUserCanDeleteVideo (userId, res, callback) { }) } -function checkVideoIsBlacklistable (req, res, callback) { +function checkVideoIsBlacklistable (req: express.Request, res: express.Response, callback: () => void) { if (res.locals.video.isOwned() === true) { return res.status(403).send('Cannot blacklist a local video') } diff --git a/server/models/application-interface.ts b/server/models/application-interface.ts index 826d25df02026f70fdee2df09bd0b1450eb459af..c03513db17bd2bbf65b7894fe9f44070deebb84a 100644 --- a/server/models/application-interface.ts +++ b/server/models/application-interface.ts @@ -1,8 +1,11 @@ import * as Sequelize from 'sequelize' export namespace ApplicationMethods { - export type LoadMigrationVersion = (callback: (err: Error, version: number) => void) => void - export type UpdateMigrationVersion = (newVersion: number, transaction: any, callback: any) => void + export type LoadMigrationVersionCallback = (err: Error, version: number) => void + export type LoadMigrationVersion = (callback: LoadMigrationVersionCallback) => void + + export type UpdateMigrationVersionCallback = (err: Error, applicationInstance: ApplicationAttributes) => void + export type UpdateMigrationVersion = (newVersion: number, transaction: Sequelize.Transaction, callback: UpdateMigrationVersionCallback) => void } export interface ApplicationClass { diff --git a/server/models/application.ts b/server/models/application.ts index acd0dfbf2e38fb9d8c5f651dd29a9b64046027ca..14b87777ac61c44d08236b070770d873d84824a9 100644 --- a/server/models/application.ts +++ b/server/models/application.ts @@ -35,7 +35,7 @@ export default function defineApplication (sequelize: Sequelize.Sequelize, DataT // --------------------------------------------------------------------------- -loadMigrationVersion = function (callback: (err: Error, version: number) => void) { +loadMigrationVersion = function (callback: ApplicationMethods.LoadMigrationVersionCallback) { const query = { attributes: [ 'migrationVersion' ] } @@ -47,15 +47,10 @@ loadMigrationVersion = function (callback: (err: Error, version: number) => void }) } -updateMigrationVersion = function (newVersion: number, transaction: any, callback: any) { +updateMigrationVersion = function (newVersion: number, transaction: Sequelize.Transaction, callback: ApplicationMethods.UpdateMigrationVersionCallback) { const options: Sequelize.UpdateOptions = { - where: {} - } - - if (!callback) { - transaction = callback - } else { - options.transaction = transaction + where: {}, + transaction: transaction } return Application.update({ migrationVersion: newVersion }, options).asCallback(callback) diff --git a/server/models/author-interface.ts b/server/models/author-interface.ts index d2475c3bde981ebf7f8a4faaf5faeaeee8ae0761..b57ce2a6b46a7299ae244f7977f6edbac56d4515 100644 --- a/server/models/author-interface.ts +++ b/server/models/author-interface.ts @@ -1,7 +1,10 @@ import * as Sequelize from 'sequelize' +import { PodInstance } from './pod-interface' + export namespace AuthorMethods { - export type FindOrCreateAuthor = (name, podId, userId, transaction, callback) => void + export type FindOrCreateAuthorCallback = (err: Error, authorInstance?: AuthorInstance) => void + export type FindOrCreateAuthor = (name: string, podId: number, userId: number, transaction: Sequelize.Transaction, callback: FindOrCreateAuthorCallback) => void } export interface AuthorClass { @@ -16,6 +19,9 @@ export interface AuthorInstance extends AuthorClass, AuthorAttributes, Sequelize id: number createdAt: Date updatedAt: Date + + podId: number + Pod: PodInstance } export interface AuthorModel extends AuthorClass, Sequelize.Model<AuthorInstance, AuthorAttributes> {} diff --git a/server/models/author.ts b/server/models/author.ts index b543d17a0f57448039b6df492fd8d62ee6d6432d..3264d3a880fde51c9913754b75bd381822aa0d58 100644 --- a/server/models/author.ts +++ b/server/models/author.ts @@ -74,12 +74,13 @@ function associate (models) { }) } -findOrCreateAuthor = function (name, podId, userId, transaction, callback) { - if (!callback) { - callback = transaction - transaction = null - } - +findOrCreateAuthor = function ( + name: string, + podId: number, + userId: number, + transaction: Sequelize.Transaction, + callback: AuthorMethods.FindOrCreateAuthorCallback +) { const author = { name, podId, @@ -91,7 +92,7 @@ findOrCreateAuthor = function (name, podId, userId, transaction, callback) { defaults: author } - if (transaction) query.transaction = transaction + if (transaction !== null) query.transaction = transaction Author.findOrCreate(query).asCallback(function (err, result) { if (err) return callback(err) diff --git a/server/models/job-interface.ts b/server/models/job-interface.ts index ad4e2d2b0e4a8e3abf18fc5e2e71ecead99c867a..ab66782571e2c34cdc33467f2a2c1fd4fa79b46a 100644 --- a/server/models/job-interface.ts +++ b/server/models/job-interface.ts @@ -1,7 +1,8 @@ import * as Sequelize from 'sequelize' export namespace JobMethods { - export type ListWithLimit = (limit, state, callback) => void + export type ListWithLimitCallback = (err: Error, jobInstances: JobInstance[]) => void + export type ListWithLimit = (limit: number, state: string, callback: ListWithLimitCallback) => void } export interface JobClass { diff --git a/server/models/job.ts b/server/models/job.ts index 982b51499e2cc152ad2fc03707dceaac79a66d11..1afae8f0866f9e6bebec9a2f1f46297d3f2d4b6e 100644 --- a/server/models/job.ts +++ b/server/models/job.ts @@ -48,7 +48,7 @@ export default function defineJob (sequelize: Sequelize.Sequelize, DataTypes) { // --------------------------------------------------------------------------- -listWithLimit = function (limit, state, callback) { +listWithLimit = function (limit: number, state: string, callback: JobMethods.ListWithLimitCallback) { const query = { order: [ [ 'id', 'ASC' ] diff --git a/server/models/oauth-client-interface.ts b/server/models/oauth-client-interface.ts index 4efd6212ad547561cc0df47aa72e6a7e0ba17eb6..3b4325740bca26675dd8d3b478dd9e35770fc866 100644 --- a/server/models/oauth-client-interface.ts +++ b/server/models/oauth-client-interface.ts @@ -1,8 +1,12 @@ import * as Sequelize from 'sequelize' export namespace OAuthClientMethods { - export type CountTotal = (callback) => void - export type LoadFirstClient = (callback) => void + export type CountTotalCallback = (err: Error, total: number) => void + export type CountTotal = (callback: CountTotalCallback) => void + + export type LoadFirstClientCallback = (err: Error, client: OAuthClientInstance) => void + export type LoadFirstClient = (callback: LoadFirstClientCallback) => void + export type GetByIdAndSecret = (clientId, clientSecret) => void } diff --git a/server/models/oauth-client.ts b/server/models/oauth-client.ts index 2cefb5cb9ab6a058e14c3a64005538347f0844ab..22fae284271924b627f728109ae4085d1f8161a8 100644 --- a/server/models/oauth-client.ts +++ b/server/models/oauth-client.ts @@ -67,15 +67,15 @@ function associate (models) { }) } -countTotal = function (callback) { +countTotal = function (callback: OAuthClientMethods.CountTotalCallback) { return OAuthClient.count().asCallback(callback) } -loadFirstClient = function (callback) { +loadFirstClient = function (callback: OAuthClientMethods.LoadFirstClientCallback) { return OAuthClient.findOne().asCallback(callback) } -getByIdAndSecret = function (clientId, clientSecret) { +getByIdAndSecret = function (clientId: string, clientSecret: string) { const query = { where: { clientId: clientId, diff --git a/server/models/oauth-token-interface.ts b/server/models/oauth-token-interface.ts index a0cd1ffe7dcce86dda56f822bb6b281970cd94e6..88526697e0422481de176324c9ee32ab75dc0f30 100644 --- a/server/models/oauth-token-interface.ts +++ b/server/models/oauth-token-interface.ts @@ -1,11 +1,25 @@ import * as Sequelize from 'sequelize' +import * as Bluebird from 'bluebird' import { UserModel } from './user-interface' +export type OAuthTokenInfo = { + refreshToken: string + refreshTokenExpiresAt: Date, + client: { + id: number + }, + user: { + id: number + } +} + export namespace OAuthTokenMethods { - export type GetByRefreshTokenAndPopulateClient = (refreshToken) => void - export type GetByTokenAndPopulateUser = (bearerToken) => void - export type GetByRefreshTokenAndPopulateUser = (refreshToken) => any + export type GetByRefreshTokenAndPopulateClient = (refreshToken: string) => Bluebird<OAuthTokenInfo> + export type GetByTokenAndPopulateUser = (bearerToken: string) => Bluebird<OAuthTokenInstance> + export type GetByRefreshTokenAndPopulateUser = (refreshToken: string) => Bluebird<OAuthTokenInstance> + + export type RemoveByUserIdCallback = (err: Error) => void export type RemoveByUserId = (userId, callback) => void } diff --git a/server/models/oauth-token.ts b/server/models/oauth-token.ts index 567df1c12c3df91b676cd00a9d21ec981c4198b7..d70bd2bce87dee407e1c45806910ce6359a56edb 100644 --- a/server/models/oauth-token.ts +++ b/server/models/oauth-token.ts @@ -8,7 +8,8 @@ import { OAuthTokenInstance, OAuthTokenAttributes, - OAuthTokenMethods + OAuthTokenMethods, + OAuthTokenInfo } from './oauth-token-interface' let OAuthToken: Sequelize.Model<OAuthTokenInstance, OAuthTokenAttributes> @@ -90,7 +91,7 @@ function associate (models) { }) } -getByRefreshTokenAndPopulateClient = function (refreshToken) { +getByRefreshTokenAndPopulateClient = function (refreshToken: string) { const query = { where: { refreshToken: refreshToken @@ -99,9 +100,9 @@ getByRefreshTokenAndPopulateClient = function (refreshToken) { } return OAuthToken.findOne(query).then(function (token) { - if (!token) return token + if (!token) return null - const tokenInfos = { + const tokenInfos: OAuthTokenInfo = { refreshToken: token.refreshToken, refreshTokenExpiresAt: token.refreshTokenExpiresAt, client: { @@ -118,7 +119,7 @@ getByRefreshTokenAndPopulateClient = function (refreshToken) { }) } -getByTokenAndPopulateUser = function (bearerToken) { +getByTokenAndPopulateUser = function (bearerToken: string) { const query = { where: { accessToken: bearerToken @@ -133,7 +134,7 @@ getByTokenAndPopulateUser = function (bearerToken) { }) } -getByRefreshTokenAndPopulateUser = function (refreshToken) { +getByRefreshTokenAndPopulateUser = function (refreshToken: string) { const query = { where: { refreshToken: refreshToken diff --git a/server/models/pod-interface.ts b/server/models/pod-interface.ts index 14c88bec6257526942fddfc5f00189aacda3efed..8f362bd5cbca8d12100bab4daf8396e8439c5adc 100644 --- a/server/models/pod-interface.ts +++ b/server/models/pod-interface.ts @@ -1,18 +1,39 @@ import * as Sequelize from 'sequelize' +// Don't use barrel, import just what we need +import { Pod as FormatedPod } from '../../shared/models/pod.model' + export namespace PodMethods { - export type ToFormatedJSON = () => void + export type ToFormatedJSON = () => FormatedPod + export type CountAllCallback = (err: Error, total: number) => void export type CountAll = (callback) => void - export type IncrementScores = (ids, value, callback) => void - export type List = (callback) => void - export type ListAllIds = (transaction, callback) => void - export type ListRandomPodIdsWithRequest = (limit, tableWithPods, tableWithPodsJoins, callback) => void - export type ListBadPods = (callback) => void - export type Load = (id, callback) => void - export type LoadByHost = (host, callback) => void - export type RemoveAll = (callback) => void - export type UpdatePodsScore = (goodPods, badPods) => void + + export type IncrementScoresCallback = (err: Error) => void + export type IncrementScores = (ids: number[], value: number, callback?: IncrementScoresCallback) => void + + export type ListCallback = (err: Error, podInstances?: PodInstance[]) => void + export type List = (callback: ListCallback) => void + + export type ListAllIdsCallback = (err: Error, ids?: number[]) => void + export type ListAllIds = (transaction: Sequelize.Transaction, callback: ListAllIdsCallback) => void + + export type ListRandomPodIdsWithRequestCallback = (err: Error, podInstanceIds?: number[]) => void + export type ListRandomPodIdsWithRequest = (limit: number, tableWithPods: string, tableWithPodsJoins: string, callback: ListRandomPodIdsWithRequestCallback) => void + + export type ListBadPodsCallback = (err: Error, podInstances?: PodInstance[]) => void + export type ListBadPods = (callback: ListBadPodsCallback) => void + + export type LoadCallback = (err: Error, podInstance: PodInstance) => void + export type Load = (id: number, callback: LoadCallback) => void + + export type LoadByHostCallback = (err: Error, podInstance: PodInstance) => void + export type LoadByHost = (host: string, callback: LoadByHostCallback) => void + + export type RemoveAllCallback = (err: Error) => void + export type RemoveAll = (callback: RemoveAllCallback) => void + + export type UpdatePodsScore = (goodPods: number[], badPods: number[]) => void } export interface PodClass { diff --git a/server/models/pod.ts b/server/models/pod.ts index 2df32e4a4470028eb8987a1a1cf0c8069dd9ad02..107744c43063eb5c25307acc29b66540368aa247 100644 --- a/server/models/pod.ts +++ b/server/models/pod.ts @@ -118,11 +118,11 @@ function associate (models) { }) } -countAll = function (callback) { +countAll = function (callback: PodMethods.CountAllCallback) { return Pod.count().asCallback(callback) } -incrementScores = function (ids, value, callback) { +incrementScores = function (ids: number[], value: number, callback?: PodMethods.IncrementScoresCallback) { if (!callback) callback = function () { /* empty */ } const update = { @@ -142,35 +142,25 @@ incrementScores = function (ids, value, callback) { return Pod.update(update, options).asCallback(callback) } -list = function (callback) { +list = function (callback: PodMethods.ListCallback) { return Pod.findAll().asCallback(callback) } -listAllIds = function (transaction, callback) { - if (!callback) { - callback = transaction - transaction = null - } - +listAllIds = function (transaction: Sequelize.Transaction, callback: PodMethods.ListAllIdsCallback) { const query: any = { attributes: [ 'id' ] } - if (transaction) query.transaction = transaction + if (transaction !== null) query.transaction = transaction - return Pod.findAll(query).asCallback(function (err, pods) { + return Pod.findAll(query).asCallback(function (err: Error, pods) { if (err) return callback(err) return callback(null, map(pods, 'id')) }) } -listRandomPodIdsWithRequest = function (limit, tableWithPods, tableWithPodsJoins, callback) { - if (!callback) { - callback = tableWithPodsJoins - tableWithPodsJoins = '' - } - +listRandomPodIdsWithRequest = function (limit: number, tableWithPods: string, tableWithPodsJoins: string, callback: PodMethods.ListRandomPodIdsWithRequestCallback) { Pod.count().asCallback(function (err, count) { if (err) return callback(err) @@ -204,7 +194,7 @@ listRandomPodIdsWithRequest = function (limit, tableWithPods, tableWithPodsJoins }) } -listBadPods = function (callback) { +listBadPods = function (callback: PodMethods.ListBadPodsCallback) { const query = { where: { score: { $lte: 0 } @@ -214,11 +204,11 @@ listBadPods = function (callback) { return Pod.findAll(query).asCallback(callback) } -load = function (id, callback) { +load = function (id: number, callback: PodMethods.LoadCallback) { return Pod.findById(id).asCallback(callback) } -loadByHost = function (host, callback) { +loadByHost = function (host: string, callback: PodMethods.LoadByHostCallback) { const query = { where: { host: host @@ -228,11 +218,11 @@ loadByHost = function (host, callback) { return Pod.findOne(query).asCallback(callback) } -removeAll = function (callback) { +removeAll = function (callback: PodMethods.RemoveAllCallback) { return Pod.destroy().asCallback(callback) } -updatePodsScore = function (goodPods, badPods) { +updatePodsScore = function (goodPods: number[], badPods: number[]) { logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length) if (goodPods.length !== 0) { diff --git a/server/models/request-interface.ts b/server/models/request-interface.ts index 2bba8ce7fff42f08ce03007bba58cce727f086fe..4bbd79966b6d24a862bff855bb8b643bac25aaf7 100644 --- a/server/models/request-interface.ts +++ b/server/models/request-interface.ts @@ -1,12 +1,26 @@ import * as Sequelize from 'sequelize' -import { PodAttributes } from './pod-interface' +import { PodInstance, PodAttributes } from './pod-interface' + +export type RequestsGrouped = { + [ podId: number ]: { + request: RequestInstance, + pod: PodInstance + }[] +} export namespace RequestMethods { - export type CountTotalRequests = (callback) => void - export type ListWithLimitAndRandom = (limitPods, limitRequestsPerPod, callback) => void - export type RemoveWithEmptyTo = (callback) => void - export type RemoveAll = (callback) => void + export type CountTotalRequestsCallback = (err: Error, total: number) => void + export type CountTotalRequests = (callback: CountTotalRequestsCallback) => void + + export type ListWithLimitAndRandomCallback = (err: Error, requestsGrouped?: RequestsGrouped) => void + export type ListWithLimitAndRandom = (limitPods, limitRequestsPerPod, callback: ListWithLimitAndRandomCallback) => void + + export type RemoveWithEmptyToCallback = (err: Error) => void + export type RemoveWithEmptyTo = (callback: RemoveWithEmptyToCallback) => void + + export type RemoveAllCallback = (err: Error) => void + export type RemoveAll = (callback: RemoveAllCallback) => void } export interface RequestClass { @@ -21,12 +35,13 @@ export interface RequestAttributes { endpoint: string } -export interface RequestInstance extends Sequelize.Instance<RequestAttributes> { +export interface RequestInstance extends RequestClass, RequestAttributes, Sequelize.Instance<RequestAttributes> { id: number createdAt: Date updatedAt: Date setPods: Sequelize.HasManySetAssociationsMixin<PodAttributes, number> + Pods: PodInstance[] } export interface RequestModel extends RequestClass, Sequelize.Model<RequestInstance, RequestAttributes> {} diff --git a/server/models/request-to-pod-interface.ts b/server/models/request-to-pod-interface.ts index 52116d6c4d2853d9e7756b7a8198b2c3810be52d..6d75ca6e51f6986e7ce4fc540cbb684e7939c836 100644 --- a/server/models/request-to-pod-interface.ts +++ b/server/models/request-to-pod-interface.ts @@ -1,7 +1,8 @@ import * as Sequelize from 'sequelize' export namespace RequestToPodMethods { - export type RemoveByRequestIdsAndPod = (requestsIds, podId, callback) => void + export type RemoveByRequestIdsAndPodCallback = (err: Error) => void + export type RemoveByRequestIdsAndPod = (requestsIds: number[], podId: number, callback?: RemoveByRequestIdsAndPodCallback) => void } export interface RequestToPodClass { @@ -11,7 +12,7 @@ export interface RequestToPodClass { export interface RequestToPodAttributes { } -export interface RequestToPodInstance extends Sequelize.Instance<RequestToPodAttributes> { +export interface RequestToPodInstance extends RequestToPodClass, RequestToPodAttributes, Sequelize.Instance<RequestToPodAttributes> { id: number createdAt: Date updatedAt: Date diff --git a/server/models/request-to-pod.ts b/server/models/request-to-pod.ts index 681f808b7ebce082b86fcff73aa17a2e9a33d241..3562069cc761b17fe8c80b523301a29b9dda48d6 100644 --- a/server/models/request-to-pod.ts +++ b/server/models/request-to-pod.ts @@ -38,7 +38,7 @@ export default function (sequelize, DataTypes) { // --------------------------------------------------------------------------- -removeByRequestIdsAndPod = function (requestsIds, podId, callback) { +removeByRequestIdsAndPod = function (requestsIds: number[], podId: number, callback?: RequestToPodMethods.RemoveByRequestIdsAndPodCallback) { if (!callback) callback = function () { /* empty */ } const query = { diff --git a/server/models/request-video-event-interface.ts b/server/models/request-video-event-interface.ts index a31c7108f1e6246da7a7be2b5149a69130031a23..ad576a2b1cef869526bccc92f214c02966abe72f 100644 --- a/server/models/request-video-event-interface.ts +++ b/server/models/request-video-event-interface.ts @@ -1,10 +1,30 @@ import * as Sequelize from 'sequelize' +import { VideoInstance } from './video-interface' +import { PodInstance } from './pod-interface' + +export type RequestsVideoEventGrouped = { + [ podId: number ]: { + id: number + type: string + count: number + video: VideoInstance + pod: PodInstance + }[] +} + export namespace RequestVideoEventMethods { - export type CountTotalRequests = (callback) => void - export type ListWithLimitAndRandom = (limitPods, limitRequestsPerPod, callback) => void - export type RemoveByRequestIdsAndPod = (ids, podId, callback) => void - export type RemoveAll = (callback) => void + export type CountTotalRequestsCallback = (err: Error, total: number) => void + export type CountTotalRequests = (callback: CountTotalRequestsCallback) => void + + export type ListWithLimitAndRandomCallback = (err: Error, requestsGrouped?: RequestsVideoEventGrouped) => void + export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number, callback: ListWithLimitAndRandomCallback) => void + + export type RemoveByRequestIdsAndPodCallback = () => void + export type RemoveByRequestIdsAndPod = (ids: number[], podId: number, callback: RemoveByRequestIdsAndPodCallback) => void + + export type RemoveAllCallback = () => void + export type RemoveAll = (callback: RemoveAllCallback) => void } export interface RequestVideoEventClass { @@ -19,8 +39,10 @@ export interface RequestVideoEventAttributes { count: number } -export interface RequestVideoEventInstance extends Sequelize.Instance<RequestVideoEventAttributes> { +export interface RequestVideoEventInstance extends RequestVideoEventClass, RequestVideoEventAttributes, Sequelize.Instance<RequestVideoEventAttributes> { id: number + + Video: VideoInstance } export interface RequestVideoEventModel extends RequestVideoEventClass, Sequelize.Model<RequestVideoEventInstance, RequestVideoEventAttributes> {} diff --git a/server/models/request-video-event.ts b/server/models/request-video-event.ts index 234e2a8a9ea117ca4b21f7be6d90fde307f0aefa..e422649afc0b4072588b20efd98b4beffc91a80b 100644 --- a/server/models/request-video-event.ts +++ b/server/models/request-video-event.ts @@ -5,16 +5,17 @@ import { values } from 'lodash' import * as Sequelize from 'sequelize' +import { database as db } from '../initializers/database' import { REQUEST_VIDEO_EVENT_TYPES } from '../initializers' import { isVideoEventCountValid } from '../helpers' - import { addMethodsToModel } from './utils' import { RequestVideoEventClass, RequestVideoEventInstance, RequestVideoEventAttributes, - RequestVideoEventMethods + RequestVideoEventMethods, + RequestsVideoEventGrouped } from './request-video-event-interface' let RequestVideoEvent: Sequelize.Model<RequestVideoEventInstance, RequestVideoEventAttributes> @@ -76,13 +77,13 @@ function associate (models) { }) } -countTotalRequests = function (callback) { +countTotalRequests = function (callback: RequestVideoEventMethods.CountTotalRequestsCallback) { const query = {} return RequestVideoEvent.count(query).asCallback(callback) } -listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { - const Pod = RequestVideoEvent['sequelize'].models.Pod +listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number, callback: RequestVideoEventMethods.ListWithLimitAndRandomCallback) { + const Pod = db.Pod // We make a join between videos and authors to find the podId of our video event requests const podJoins = 'INNER JOIN "Videos" ON "Videos"."authorId" = "Authors"."id" ' + @@ -129,7 +130,7 @@ listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { }) } -removeByRequestIdsAndPod = function (ids, podId, callback) { +removeByRequestIdsAndPod = function (ids: number[], podId: number, callback: RequestVideoEventMethods.RemoveByRequestIdsAndPodCallback) { const query = { where: { id: { @@ -154,15 +155,15 @@ removeByRequestIdsAndPod = function (ids, podId, callback) { RequestVideoEvent.destroy(query).asCallback(callback) } -removeAll = function (callback) { +removeAll = function (callback: RequestVideoEventMethods.RemoveAllCallback) { // Delete all requests RequestVideoEvent.truncate({ cascade: true }).asCallback(callback) } // --------------------------------------------------------------------------- -function groupAndTruncateRequests (events, limitRequestsPerPod) { - const eventsGrouped = {} +function groupAndTruncateRequests (events: RequestVideoEventInstance[], limitRequestsPerPod: number) { + const eventsGrouped: RequestsVideoEventGrouped = {} events.forEach(function (event) { const pod = event.Video.Author.Pod diff --git a/server/models/request-video-qadu-interface.ts b/server/models/request-video-qadu-interface.ts index 6fe34ee9127ebd149a175f4da77b6ea4b310f6ee..04de7f159f85b1fe3fc8655a415b1b2de480934c 100644 --- a/server/models/request-video-qadu-interface.ts +++ b/server/models/request-video-qadu-interface.ts @@ -1,10 +1,28 @@ import * as Sequelize from 'sequelize' +import { VideoInstance } from './video-interface' +import { PodInstance } from './pod-interface' + +export type RequestsVideoQaduGrouped = { + [ podId: number ]: { + request: RequestVideoQaduInstance + video: VideoInstance + pod: PodInstance + } +} + export namespace RequestVideoQaduMethods { - export type CountTotalRequests = (callback) => void - export type ListWithLimitAndRandom = (limitPods, limitRequestsPerPod, callback) => void - export type RemoveByRequestIdsAndPod = (ids, podId, callback) => void - export type RemoveAll = (callback) => void + export type CountTotalRequestsCallback = (err: Error, total: number) => void + export type CountTotalRequests = (callback: CountTotalRequestsCallback) => void + + export type ListWithLimitAndRandomCallback = (err: Error, requestsGrouped?: RequestsVideoQaduGrouped) => void + export type ListWithLimitAndRandom = (limitPods: number, limitRequestsPerPod: number, callback: ListWithLimitAndRandomCallback) => void + + export type RemoveByRequestIdsAndPodCallback = () => void + export type RemoveByRequestIdsAndPod = (ids: number[], podId: number, callback: RemoveByRequestIdsAndPodCallback) => void + + export type RemoveAllCallback = () => void + export type RemoveAll = (callback: RemoveAllCallback) => void } export interface RequestVideoQaduClass { @@ -18,8 +36,11 @@ export interface RequestVideoQaduAttributes { type: string } -export interface RequestVideoQaduInstance extends Sequelize.Instance<RequestVideoQaduAttributes> { +export interface RequestVideoQaduInstance extends RequestVideoQaduClass, RequestVideoQaduAttributes, Sequelize.Instance<RequestVideoQaduAttributes> { id: number + + Pod: PodInstance + Video: VideoInstance } export interface RequestVideoQaduModel extends RequestVideoQaduClass, Sequelize.Model<RequestVideoQaduInstance, RequestVideoQaduAttributes> {} diff --git a/server/models/request-video-qadu.ts b/server/models/request-video-qadu.ts index e914e06cd19f66ccf603767f5747c8e80cb99e83..38627ad55f3fde4c2f9996390f856090f653b40d 100644 --- a/server/models/request-video-qadu.ts +++ b/server/models/request-video-qadu.ts @@ -12,8 +12,8 @@ import { values } from 'lodash' import * as Sequelize from 'sequelize' +import { database as db } from '../initializers/database' import { REQUEST_VIDEO_QADU_TYPES } from '../initializers' - import { addMethodsToModel } from './utils' import { RequestVideoQaduClass, @@ -83,15 +83,16 @@ function associate (models) { }) } -countTotalRequests = function (callback) { +countTotalRequests = function (callback: RequestVideoQaduMethods.CountTotalRequestsCallback) { const query = {} return RequestVideoQadu.count(query).asCallback(callback) } -listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { - const Pod = RequestVideoQadu['sequelize'].models.Pod +listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number, callback: RequestVideoQaduMethods.ListWithLimitAndRandomCallback) { + const Pod = db.Pod + const tableJoin = '' - Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', function (err, podIds) { + Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', tableJoin, function (err, podIds) { if (err) return callback(err) // We don't have friends that have requests @@ -122,7 +123,7 @@ listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { }) } -removeByRequestIdsAndPod = function (ids, podId, callback) { +removeByRequestIdsAndPod = function (ids: number[], podId: number, callback: RequestVideoQaduMethods.RemoveByRequestIdsAndPodCallback) { const query = { where: { id: { @@ -135,14 +136,14 @@ removeByRequestIdsAndPod = function (ids, podId, callback) { RequestVideoQadu.destroy(query).asCallback(callback) } -removeAll = function (callback) { +removeAll = function (callback: RequestVideoQaduMethods.RemoveAllCallback) { // Delete all requests RequestVideoQadu.truncate({ cascade: true }).asCallback(callback) } // --------------------------------------------------------------------------- -function groupAndTruncateRequests (requests, limitRequestsPerPod) { +function groupAndTruncateRequests (requests: RequestVideoQaduInstance[], limitRequestsPerPod: number) { const requestsGrouped = {} requests.forEach(function (request) { diff --git a/server/models/request.ts b/server/models/request.ts index 18fa291fa4a9acae8cbced3b26f7754164ca0f6b..71f81ae66fd78044f6f1c00a9e8a0a2db5b4fc44 100644 --- a/server/models/request.ts +++ b/server/models/request.ts @@ -1,15 +1,16 @@ import { values } from 'lodash' import * as Sequelize from 'sequelize' +import { database as db } from '../initializers/database' import { REQUEST_ENDPOINTS } from '../initializers' - import { addMethodsToModel } from './utils' import { RequestClass, RequestInstance, RequestAttributes, - RequestMethods + RequestMethods, + RequestsGrouped } from './request-interface' let Request: Sequelize.Model<RequestInstance, RequestAttributes> @@ -59,7 +60,7 @@ function associate (models) { }) } -countTotalRequests = function (callback) { +countTotalRequests = function (callback: RequestMethods.CountTotalRequestsCallback) { // We need to include Pod because there are no cascade delete when a pod is removed // So we could count requests that do not have existing pod anymore const query = { @@ -69,10 +70,11 @@ countTotalRequests = function (callback) { return Request.count(query).asCallback(callback) } -listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { - const Pod = Request['sequelize'].models.Pod +listWithLimitAndRandom = function (limitPods: number, limitRequestsPerPod: number, callback: RequestMethods.ListWithLimitAndRandomCallback) { + const Pod = db.Pod + const tableJoin = '' - Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', function (err, podIds) { + Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', '', function (err, podIds) { if (err) return callback(err) // We don't have friends that have requests @@ -105,12 +107,12 @@ listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { }) } -removeAll = function (callback) { +removeAll = function (callback: RequestMethods.RemoveAllCallback) { // Delete all requests Request.truncate({ cascade: true }).asCallback(callback) } -removeWithEmptyTo = function (callback) { +removeWithEmptyTo = function (callback?: RequestMethods.RemoveWithEmptyToCallback) { if (!callback) callback = function () { /* empty */ } const query = { @@ -128,8 +130,8 @@ removeWithEmptyTo = function (callback) { // --------------------------------------------------------------------------- -function groupAndTruncateRequests (requests, limitRequestsPerPod) { - const requestsGrouped = {} +function groupAndTruncateRequests (requests: RequestInstance[], limitRequestsPerPod: number) { + const requestsGrouped: RequestsGrouped = {} requests.forEach(function (request) { request.Pods.forEach(function (pod) { diff --git a/server/models/tag-interface.ts b/server/models/tag-interface.ts index f96e1e9c54283f2fb4843ab21aa69216eeed850a..e045e7ca56411ac094a9a96e8e44b113ff9bf325 100644 --- a/server/models/tag-interface.ts +++ b/server/models/tag-interface.ts @@ -1,7 +1,8 @@ import * as Sequelize from 'sequelize' export namespace TagMethods { - export type FindOrCreateTags = (tags, transaction, callback) => void + export type FindOrCreateTagsCallback = (err: Error, tagInstances: TagInstance[]) => void + export type FindOrCreateTags = (tags: string[], transaction: Sequelize.Transaction, callback: FindOrCreateTagsCallback) => void } export interface TagClass { diff --git a/server/models/tag.ts b/server/models/tag.ts index b2a9c9f81ddbfb3a8bd853ef735a73a3ded95584..c4402e83c2d19e2d5aa4e6581a8e274718b73e02 100644 --- a/server/models/tag.ts +++ b/server/models/tag.ts @@ -52,15 +52,10 @@ function associate (models) { }) } -findOrCreateTags = function (tags, transaction, callback) { - if (!callback) { - callback = transaction - transaction = null - } - +findOrCreateTags = function (tags: string[], transaction: Sequelize.Transaction, callback: TagMethods.FindOrCreateTagsCallback) { const tagInstances = [] - each(tags, function (tag, callbackEach) { + each<string, Error>(tags, function (tag, callbackEach) { const query: any = { where: { name: tag diff --git a/server/models/user-interface.ts b/server/models/user-interface.ts index a504f42a1bca74a68bb99e44f1d71f49b6980877..98963b7438f346e9267c8390ef17560b9fd69d11 100644 --- a/server/models/user-interface.ts +++ b/server/models/user-interface.ts @@ -1,17 +1,35 @@ import * as Sequelize from 'sequelize' +import * as Bluebird from 'bluebird' + +// Don't use barrel, import just what we need +import { User as FormatedUser } from '../../shared/models/user.model' export namespace UserMethods { - export type IsPasswordMatch = (password, callback) => void - export type ToFormatedJSON = () => void + export type IsPasswordMatchCallback = (err: Error, same: boolean) => void + export type IsPasswordMatch = (password: string, callback: IsPasswordMatchCallback) => void + + export type ToFormatedJSON = () => FormatedUser export type IsAdmin = () => boolean - export type CountTotal = (callback) => void - export type GetByUsername = (username) => any - export type List = (callback) => void - export type ListForApi = (start, count, sort, callback) => void - export type LoadById = (id, callback) => void - export type LoadByUsername = (username, callback) => void - export type LoadByUsernameOrEmail = (username, email, callback) => void + export type CountTotalCallback = (err: Error, total: number) => void + export type CountTotal = (callback: CountTotalCallback) => void + + export type GetByUsername = (username: string) => Bluebird<UserInstance> + + export type ListCallback = (err: Error, userInstances: UserInstance[]) => void + export type List = (callback: ListCallback) => void + + export type ListForApiCallback = (err: Error, userInstances?: UserInstance[], total?: number) => void + export type ListForApi = (start: number, count: number, sort: string, callback: ListForApiCallback) => void + + export type LoadByIdCallback = (err: Error, userInstance: UserInstance) => void + export type LoadById = (id: number, callback: LoadByIdCallback) => void + + export type LoadByUsernameCallback = (err: Error, userInstance: UserInstance) => void + export type LoadByUsername = (username: string, callback: LoadByUsernameCallback) => void + + export type LoadByUsernameOrEmailCallback = (err: Error, userInstance: UserInstance) => void + export type LoadByUsernameOrEmail = (username: string, email: string, callback: LoadByUsernameOrEmailCallback) => void } export interface UserClass { diff --git a/server/models/user-video-rate-interface.ts b/server/models/user-video-rate-interface.ts index 57d2e2b91d39b69fbac45acc50a2a022887a002e..e48869fd22a676d6d6a928579fb6b44f08cc3ffd 100644 --- a/server/models/user-video-rate-interface.ts +++ b/server/models/user-video-rate-interface.ts @@ -1,6 +1,7 @@ import * as Sequelize from 'sequelize' export namespace UserVideoRateMethods { + export type LoadCallback = (err: Error, userVideoRateInstance: UserVideoRateInstance) => void export type Load = (userId, videoId, transaction, callback) => void } @@ -12,7 +13,7 @@ export interface UserVideoRateAttributes { type: string } -export interface UserVideoRateInstance extends Sequelize.Instance<UserVideoRateAttributes> { +export interface UserVideoRateInstance extends UserVideoRateClass, UserVideoRateAttributes, Sequelize.Instance<UserVideoRateAttributes> { id: number createdAt: Date updatedAt: Date diff --git a/server/models/user-video-rate.ts b/server/models/user-video-rate.ts index 87886d8d00960c053cbd29918ab4a63af2dfa5b1..6b71e841263db7a1ea66ecdd95314305b8042782 100644 --- a/server/models/user-video-rate.ts +++ b/server/models/user-video-rate.ts @@ -67,7 +67,7 @@ function associate (models) { }) } -load = function (userId, videoId, transaction, callback) { +load = function (userId: number, videoId: number, transaction: Sequelize.Transaction, callback: UserVideoRateMethods.LoadCallback) { const options: Sequelize.FindOptions = { where: { userId, diff --git a/server/models/user.ts b/server/models/user.ts index 12ddaaeb7ec2a861e27d276abb71fd82b9cb5c31..0fbfdda50e005f92dbea0be10ed3f50fa7a784a2 100644 --- a/server/models/user.ts +++ b/server/models/user.ts @@ -117,7 +117,7 @@ export default function (sequelize, DataTypes) { return User } -function beforeCreateOrUpdate (user, options) { +function beforeCreateOrUpdate (user: UserInstance) { return new Promise(function (resolve, reject) { cryptPassword(user.password, function (err, hash) { if (err) return reject(err) @@ -131,7 +131,7 @@ function beforeCreateOrUpdate (user, options) { // ------------------------------ METHODS ------------------------------ -isPasswordMatch = function (password, callback) { +isPasswordMatch = function (password: string, callback: UserMethods.IsPasswordMatchCallback) { return comparePassword(password, this.password, callback) } @@ -164,11 +164,11 @@ function associate (models) { }) } -countTotal = function (callback) { +countTotal = function (callback: UserMethods.CountTotalCallback) { return this.count().asCallback(callback) } -getByUsername = function (username) { +getByUsername = function (username: string) { const query = { where: { username: username @@ -178,11 +178,11 @@ getByUsername = function (username) { return User.findOne(query) } -list = function (callback) { +list = function (callback: UserMethods.ListCallback) { return User.find().asCallback(callback) } -listForApi = function (start, count, sort, callback) { +listForApi = function (start: number, count: number, sort: string, callback: UserMethods.ListForApiCallback) { const query = { offset: start, limit: count, @@ -196,11 +196,11 @@ listForApi = function (start, count, sort, callback) { }) } -loadById = function (id, callback) { +loadById = function (id: number, callback: UserMethods.LoadByIdCallback) { return User.findById(id).asCallback(callback) } -loadByUsername = function (username, callback) { +loadByUsername = function (username: string, callback: UserMethods.LoadByUsernameCallback) { const query = { where: { username: username @@ -210,7 +210,7 @@ loadByUsername = function (username, callback) { return User.findOne(query).asCallback(callback) } -loadByUsernameOrEmail = function (username, email, callback) { +loadByUsernameOrEmail = function (username: string, email: string, callback: UserMethods.LoadByUsernameOrEmailCallback) { const query = { where: { $or: [ { username }, { email } ] diff --git a/server/models/utils.ts b/server/models/utils.ts index fd84a92399e5f2aaefab3ef826d022f4e4f5be32..7ba96815e282a512db020243c68816ea6899ca8a 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts @@ -1,7 +1,7 @@ // Translate for example "-name" to [ 'name', 'DESC' ] -function getSort (value) { - let field - let direction +function getSort (value: string) { + let field: string + let direction: 'ASC' | 'DESC' if (value.substring(0, 1) === '-') { direction = 'DESC' diff --git a/server/models/video-abuse-interface.ts b/server/models/video-abuse-interface.ts index 9b77fc6f5907ee66aacaad42b03c5aab7148dc47..d9cb93b42a32f5823967f78e6b306d6c366e7d16 100644 --- a/server/models/video-abuse-interface.ts +++ b/server/models/video-abuse-interface.ts @@ -1,9 +1,13 @@ import * as Sequelize from 'sequelize' +// Don't use barrel, import just what we need +import { VideoAbuse as FormatedVideoAbuse } from '../../shared/models/video-abuse.model' + export namespace VideoAbuseMethods { - export type toFormatedJSON = () => void + export type toFormatedJSON = () => FormatedVideoAbuse - export type ListForApi = (start, count, sort, callback) => void + export type ListForApiCallback = (err: Error, videoAbuseInstances?: VideoAbuseInstance[], total?: number) => void + export type ListForApi = (start: number, count: number, sort: string, callback: ListForApiCallback) => void } export interface VideoAbuseClass { @@ -15,7 +19,7 @@ export interface VideoAbuseAttributes { reason: string } -export interface VideoAbuseInstance extends Sequelize.Instance<VideoAbuseAttributes> { +export interface VideoAbuseInstance extends VideoAbuseClass, VideoAbuseAttributes, Sequelize.Instance<VideoAbuseAttributes> { id: number createdAt: Date updatedAt: Date diff --git a/server/models/video-blacklist-interface.ts b/server/models/video-blacklist-interface.ts index ae2cd6748e824068ae4b69f221158f146b3945a8..9747181926302425ca8803605d61919a07c7b97d 100644 --- a/server/models/video-blacklist-interface.ts +++ b/server/models/video-blacklist-interface.ts @@ -1,13 +1,25 @@ import * as Sequelize from 'sequelize' +// Don't use barrel, import just what we need +import { BlacklistedVideo as FormatedBlacklistedVideo } from '../../shared/models/video-blacklist.model' + export namespace BlacklistedVideoMethods { - export type ToFormatedJSON = () => void + export type ToFormatedJSON = () => FormatedBlacklistedVideo + + export type CountTotalCallback = (err: Error, total: number) => void + export type CountTotal = (callback: CountTotalCallback) => void + + export type ListCallback = (err: Error, backlistedVideoInstances: BlacklistedVideoInstance[]) => void + export type List = (callback: ListCallback) => void + + export type ListForApiCallback = (err: Error, blacklistedVIdeoInstances?: BlacklistedVideoInstance[], total?: number) => void + export type ListForApi = (start: number, count: number, sort: string, callback: ListForApiCallback) => void + + export type LoadByIdCallback = (err: Error, blacklistedVideoInstance: BlacklistedVideoInstance) => void + export type LoadById = (id: number, callback: LoadByIdCallback) => void - export type CountTotal = (callback) => void - export type List = (callback) => void - export type ListForApi = (start, count, sort, callback) => void - export type LoadById = (id, callback) => void - export type LoadByVideoId = (id, callback) => void + export type LoadByVideoIdCallback = (err: Error, blacklistedVideoInstance: BlacklistedVideoInstance) => void + export type LoadByVideoId = (id: string, callback: LoadByVideoIdCallback) => void } export interface BlacklistedVideoClass { diff --git a/server/models/video-blacklist.ts b/server/models/video-blacklist.ts index fe72d5d46eb46be11a911f0c32270e2d661d9691..f3675608573f7ed974ce0288e901054b88fefe85 100644 --- a/server/models/video-blacklist.ts +++ b/server/models/video-blacklist.ts @@ -66,15 +66,15 @@ function associate (models) { }) } -countTotal = function (callback) { +countTotal = function (callback: BlacklistedVideoMethods.CountTotalCallback) { return BlacklistedVideo.count().asCallback(callback) } -list = function (callback) { +list = function (callback: BlacklistedVideoMethods.ListCallback) { return BlacklistedVideo.findAll().asCallback(callback) } -listForApi = function (start, count, sort, callback) { +listForApi = function (start: number, count: number, sort: string, callback: BlacklistedVideoMethods.ListForApiCallback) { const query = { offset: start, limit: count, @@ -88,11 +88,11 @@ listForApi = function (start, count, sort, callback) { }) } -loadById = function (id, callback) { +loadById = function (id: number, callback: BlacklistedVideoMethods.LoadByIdCallback) { return BlacklistedVideo.findById(id).asCallback(callback) } -loadByVideoId = function (id, callback) { +loadByVideoId = function (id: string, callback: BlacklistedVideoMethods.LoadByIdCallback) { const query = { where: { videoId: id diff --git a/server/models/video-interface.ts b/server/models/video-interface.ts index b8dbeea357353409033bf5de2fc8d2a25179309f..7005f213c481bfdc88fcd2578ce6ccdb4654e825 100644 --- a/server/models/video-interface.ts +++ b/server/models/video-interface.ts @@ -1,28 +1,101 @@ import * as Sequelize from 'sequelize' +import { AuthorInstance } from './author-interface' +import { VideoTagInstance } from './video-tag-interface' + +// Don't use barrel, import just what we need +import { Video as FormatedVideo } from '../../shared/models/video.model' + +export type FormatedAddRemoteVideo = { + name: string + category: number + licence: number + language: number + nsfw: boolean + description: string + infoHash: string + remoteId: string + author: string + duration: number + thumbnailData: string + tags: string[] + createdAt: Date + updatedAt: Date + extname: string + views: number + likes: number + dislikes: number +} + +export type FormatedUpdateRemoteVideo = { + name: string + category: number + licence: number + language: number + nsfw: boolean + description: string + infoHash: string + remoteId: string + author: string + duration: number + tags: string[] + createdAt: Date + updatedAt: Date + extname: string + views: number + likes: number + dislikes: number +} + export namespace VideoMethods { - export type GenerateMagnetUri = () => void - export type GetVideoFilename = () => void - export type GetThumbnailName = () => void - export type GetPreviewName = () => void - export type GetTorrentName = () => void - export type IsOwned = () => void - export type ToFormatedJSON = () => void - export type ToAddRemoteJSON = (callback) => void - export type ToUpdateRemoteJSON = (callback) => void - export type TranscodeVideofile = (callback) => void - - export type GenerateThumbnailFromData = (video, thumbnailData, callback) => void + export type GenerateMagnetUri = () => string + export type GetVideoFilename = () => string + export type GetThumbnailName = () => string + export type GetPreviewName = () => string + export type GetTorrentName = () => string + export type IsOwned = () => boolean + export type ToFormatedJSON = () => FormatedVideo + + export type ToAddRemoteJSONCallback = (err: Error, videoFormated?: FormatedAddRemoteVideo) => void + export type ToAddRemoteJSON = (callback: ToAddRemoteJSONCallback) => void + + export type ToUpdateRemoteJSON = () => FormatedUpdateRemoteVideo + + export type TranscodeVideofileCallback = (err: Error) => void + export type TranscodeVideofile = (callback: TranscodeVideofileCallback) => void + + export type GenerateThumbnailFromDataCallback = (err: Error, thumbnailName?: string) => void + export type GenerateThumbnailFromData = (video: VideoInstance, thumbnailData: string, callback: GenerateThumbnailFromDataCallback) => void + + export type GetDurationFromFileCallback = (err: Error, duration?: number) => void export type GetDurationFromFile = (videoPath, callback) => void - export type List = (callback) => void - export type ListForApi = (start, count, sort, callback) => void - export type LoadByHostAndRemoteId = (fromHost, remoteId, callback) => void - export type ListOwnedAndPopulateAuthorAndTags = (callback) => void - export type ListOwnedByAuthor = (author, callback) => void - export type Load = (id, callback) => void - export type LoadAndPopulateAuthor = (id, callback) => void - export type LoadAndPopulateAuthorAndPodAndTags = (id, callback) => void - export type SearchAndPopulateAuthorAndPodAndTags = (value, field, start, count, sort, callback) => void + + export type ListCallback = () => void + export type List = (callback: ListCallback) => void + + export type ListForApiCallback = (err: Error, videoInstances?: VideoInstance[], total?: number) => void + export type ListForApi = (start: number, count: number, sort: string, callback: ListForApiCallback) => void + + export type LoadByHostAndRemoteIdCallback = (err: Error, videoInstance: VideoInstance) => void + export type LoadByHostAndRemoteId = (fromHost: string, remoteId: string, callback: LoadByHostAndRemoteIdCallback) => void + + export type ListOwnedAndPopulateAuthorAndTagsCallback = (err: Error, videoInstances: VideoInstance[]) => void + export type ListOwnedAndPopulateAuthorAndTags = (callback: ListOwnedAndPopulateAuthorAndTagsCallback) => void + + export type ListOwnedByAuthorCallback = (err: Error, videoInstances: VideoInstance[]) => void + export type ListOwnedByAuthor = (author: string, callback: ListOwnedByAuthorCallback) => void + + export type LoadCallback = (err: Error, videoInstance: VideoInstance) => void + export type Load = (id: string, callback: LoadCallback) => void + + export type LoadAndPopulateAuthorCallback = (err: Error, videoInstance: VideoInstance) => void + export type LoadAndPopulateAuthor = (id: string, callback: LoadAndPopulateAuthorCallback) => void + + export type LoadAndPopulateAuthorAndPodAndTagsCallback = (err: Error, videoInstance: VideoInstance) => void + export type LoadAndPopulateAuthorAndPodAndTags = (id: string, callback: LoadAndPopulateAuthorAndPodAndTagsCallback) => void + + export type SearchAndPopulateAuthorAndPodAndTagsCallback = (err: Error, videoInstances?: VideoInstance[], total?: number) => void + export type SearchAndPopulateAuthorAndPodAndTags = (value: string, field: string, start: number, count: number, sort: string, callback: SearchAndPopulateAuthorAndPodAndTagsCallback) => void } export interface VideoClass { @@ -64,6 +137,9 @@ export interface VideoAttributes { views?: number likes?: number dislikes?: number + + Author?: AuthorInstance + Tags?: VideoTagInstance[] } export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.Instance<VideoAttributes> { diff --git a/server/models/video-tag-interface.ts b/server/models/video-tag-interface.ts index 468827b8c77093521424a522f13107f100e0a615..f928cecffd0d5efcca59af4dd82c8bc08da4225d 100644 --- a/server/models/video-tag-interface.ts +++ b/server/models/video-tag-interface.ts @@ -9,7 +9,7 @@ export interface VideoTagClass { export interface VideoTagAttributes { } -export interface VideoTagInstance extends Sequelize.Instance<VideoTagAttributes> { +export interface VideoTagInstance extends VideoTagClass, VideoTagAttributes, Sequelize.Instance<VideoTagAttributes> { id: number createdAt: Date updatedAt: Date diff --git a/server/models/video.ts b/server/models/video.ts index 5558a7c3bf1391dd78c7b4acd27945d388681f3c..3f808b811f9d4b63b571d97fa5b62c59ddb98776 100644 --- a/server/models/video.ts +++ b/server/models/video.ts @@ -11,6 +11,7 @@ import { join } from 'path' import * as Sequelize from 'sequelize' import { database as db } from '../initializers/database' +import { VideoTagInstance } from './video-tag-interface' import { logger, isVideoNameValid, @@ -266,7 +267,7 @@ export default function (sequelize, DataTypes) { return Video } -function beforeValidate (video, options) { +function beforeValidate (video: VideoInstance) { // Put a fake infoHash if it does not exists yet if (video.isOwned() && !video.infoHash) { // 40 hexa length @@ -274,7 +275,7 @@ function beforeValidate (video, options) { } } -function beforeCreate (video, options) { +function beforeCreate (video: VideoInstance, options: { transaction: Sequelize.Transaction }) { return new Promise(function (resolve, reject) { const tasks = [] @@ -318,7 +319,7 @@ function beforeCreate (video, options) { }) } -function afterDestroy (video, options) { +function afterDestroy (video: VideoInstance) { return new Promise(function (resolve, reject) { const tasks = [] @@ -401,7 +402,7 @@ generateMagnetUri = function () { } const xs = baseUrlHttp + STATIC_PATHS.TORRENTS + this.getTorrentName() - const announce = baseUrlWs + '/tracker/socket' + const announce = [ baseUrlWs + '/tracker/socket' ] const urlList = [ baseUrlHttp + STATIC_PATHS.WEBSEED + this.getVideoFilename() ] const magnetHash = { @@ -496,7 +497,7 @@ toFormatedJSON = function () { return json } -toAddRemoteJSON = function (callback) { +toAddRemoteJSON = function (callback: VideoMethods.ToAddRemoteJSONCallback) { // Get thumbnail data to send to the other pod const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName()) fs.readFile(thumbnailPath, (err, thumbnailData) => { @@ -517,7 +518,7 @@ toAddRemoteJSON = function (callback) { author: this.Author.name, duration: this.duration, thumbnailData: thumbnailData.toString('binary'), - tags: map(this.Tags, 'name'), + tags: map<VideoTagInstance, string>(this.Tags, 'name'), createdAt: this.createdAt, updatedAt: this.updatedAt, extname: this.extname, @@ -530,7 +531,7 @@ toAddRemoteJSON = function (callback) { }) } -toUpdateRemoteJSON = function (callback) { +toUpdateRemoteJSON = function () { const json = { name: this.name, category: this.category, @@ -542,7 +543,7 @@ toUpdateRemoteJSON = function (callback) { remoteId: this.id, author: this.Author.name, duration: this.duration, - tags: map(this.Tags, 'name'), + tags: map<VideoTagInstance, string>(this.Tags, 'name'), createdAt: this.createdAt, updatedAt: this.updatedAt, extname: this.extname, @@ -554,7 +555,7 @@ toUpdateRemoteJSON = function (callback) { return json } -transcodeVideofile = function (finalCallback) { +transcodeVideofile = function (finalCallback: VideoMethods.TranscodeVideofileCallback) { const video = this const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR @@ -591,9 +592,9 @@ transcodeVideofile = function (finalCallback) { video.save().asCallback(callback) } - ], function (err) { + ], function (err: Error) { if (err) { - // Autodescruction... + // Autodesctruction... video.destroy().asCallback(function (err) { if (err) logger.error('Cannot destruct video after transcoding failure.', { error: err }) }) @@ -609,7 +610,7 @@ transcodeVideofile = function (finalCallback) { // ------------------------------ STATICS ------------------------------ -generateThumbnailFromData = function (video, thumbnailData, callback) { +generateThumbnailFromData = function (video: VideoInstance, thumbnailData: string, callback: VideoMethods.GenerateThumbnailFromDataCallback) { // Creating the thumbnail for a remote video const thumbnailName = video.getThumbnailName() @@ -621,7 +622,7 @@ generateThumbnailFromData = function (video, thumbnailData, callback) { }) } -getDurationFromFile = function (videoPath, callback) { +getDurationFromFile = function (videoPath: string, callback: VideoMethods.GetDurationFromFileCallback) { ffmpeg.ffprobe(videoPath, function (err, metadata) { if (err) return callback(err) @@ -629,11 +630,11 @@ getDurationFromFile = function (videoPath, callback) { }) } -list = function (callback) { +list = function (callback: VideoMethods.ListCallback) { return Video.findAll().asCallback(callback) } -listForApi = function (start, count, sort, callback) { +listForApi = function (start: number, count: number, sort: string, callback: VideoMethods.ListForApiCallback) { // Exclude Blakclisted videos from the list const query = { distinct: true, @@ -658,7 +659,7 @@ listForApi = function (start, count, sort, callback) { }) } -loadByHostAndRemoteId = function (fromHost, remoteId, callback) { +loadByHostAndRemoteId = function (fromHost: string, remoteId: string, callback: VideoMethods.LoadByHostAndRemoteIdCallback) { const query = { where: { remoteId: remoteId @@ -682,7 +683,7 @@ loadByHostAndRemoteId = function (fromHost, remoteId, callback) { return Video.findOne(query).asCallback(callback) } -listOwnedAndPopulateAuthorAndTags = function (callback) { +listOwnedAndPopulateAuthorAndTags = function (callback: VideoMethods.ListOwnedAndPopulateAuthorAndTagsCallback) { // If remoteId is null this is *our* video const query = { where: { @@ -694,7 +695,7 @@ listOwnedAndPopulateAuthorAndTags = function (callback) { return Video.findAll(query).asCallback(callback) } -listOwnedByAuthor = function (author, callback) { +listOwnedByAuthor = function (author: string, callback: VideoMethods.ListOwnedByAuthorCallback) { const query = { where: { remoteId: null @@ -712,11 +713,11 @@ listOwnedByAuthor = function (author, callback) { return Video.findAll(query).asCallback(callback) } -load = function (id, callback) { +load = function (id: string, callback: VideoMethods.LoadCallback) { return Video.findById(id).asCallback(callback) } -loadAndPopulateAuthor = function (id, callback) { +loadAndPopulateAuthor = function (id: string, callback: VideoMethods.LoadAndPopulateAuthorCallback) { const options = { include: [ Video['sequelize'].models.Author ] } @@ -724,7 +725,7 @@ loadAndPopulateAuthor = function (id, callback) { return Video.findById(id, options).asCallback(callback) } -loadAndPopulateAuthorAndPodAndTags = function (id, callback) { +loadAndPopulateAuthorAndPodAndTags = function (id: string, callback: VideoMethods.LoadAndPopulateAuthorAndPodAndTagsCallback) { const options = { include: [ { @@ -738,7 +739,14 @@ loadAndPopulateAuthorAndPodAndTags = function (id, callback) { return Video.findById(id, options).asCallback(callback) } -searchAndPopulateAuthorAndPodAndTags = function (value, field, start, count, sort, callback) { +searchAndPopulateAuthorAndPodAndTags = function ( + value: string, + field: string, + start: number, + count: number, + sort: string, + callback: VideoMethods.SearchAndPopulateAuthorAndPodAndTagsCallback +) { const podInclude: any = { model: Video['sequelize'].models.Pod, required: false @@ -821,27 +829,27 @@ function createBaseVideosWhere () { } } -function removeThumbnail (video, callback) { +function removeThumbnail (video: VideoInstance, callback: (err: Error) => void) { const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName()) fs.unlink(thumbnailPath, callback) } -function removeFile (video, callback) { +function removeFile (video: VideoInstance, callback: (err: Error) => void) { const filePath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename()) fs.unlink(filePath, callback) } -function removeTorrent (video, callback) { +function removeTorrent (video: VideoInstance, callback: (err: Error) => void) { const torrenPath = join(CONFIG.STORAGE.TORRENTS_DIR, video.getTorrentName()) fs.unlink(torrenPath, callback) } -function removePreview (video, callback) { +function removePreview (video: VideoInstance, callback: (err: Error) => void) { // Same name than video thumnail fs.unlink(CONFIG.STORAGE.PREVIEWS_DIR + video.getPreviewName(), callback) } -function createTorrentFromVideo (video, videoPath, callback) { +function createTorrentFromVideo (video: VideoInstance, videoPath: string, callback: (err: Error) => void) { const options = { announceList: [ [ CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT + '/tracker/socket' ] @@ -865,24 +873,23 @@ function createTorrentFromVideo (video, videoPath, callback) { }) } -function createPreview (video, videoPath, callback) { - generateImage(video, videoPath, CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName(), callback) +function createPreview (video: VideoInstance, videoPath: string, callback: (err: Error) => void) { + generateImage(video, videoPath, CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName(), null, callback) } -function createThumbnail (video, videoPath, callback) { +function createThumbnail (video: VideoInstance, videoPath: string, callback: (err: Error) => void) { generateImage(video, videoPath, CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName(), THUMBNAILS_SIZE, callback) } -function generateImage (video, videoPath, folder, imageName, size, callback?) { +type GenerateImageCallback = (err: Error, imageName: string) => void +function generateImage (video: VideoInstance, videoPath: string, folder: string, imageName: string, size: string, callback?: GenerateImageCallback) { const options: any = { filename: imageName, count: 1, folder } - if (!callback) { - callback = size - } else { + if (size) { options.size = size } @@ -894,7 +901,7 @@ function generateImage (video, videoPath, folder, imageName, size, callback?) { .thumbnail(options) } -function removeFromBlacklist (video, callback) { +function removeFromBlacklist (video: VideoInstance, callback: (err: Error) => void) { // Find the blacklisted video db.BlacklistedVideo.loadByVideoId(video.id, function (err, video) { // If an error occured, stop here @@ -908,7 +915,7 @@ function removeFromBlacklist (video, callback) { video.destroy().asCallback(callback) } else { // If haven't found it, simply ignore it and do nothing - return callback() + return callback(null) } }) } diff --git a/shared/index.ts b/shared/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad200c539fecac3c127bf35fdcfd7e02e766d560 --- /dev/null +++ b/shared/index.ts @@ -0,0 +1 @@ +export * from './models' diff --git a/shared/models/index.ts b/shared/models/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..b498d620a662ac83ba5b23b1f02ae99227a87367 --- /dev/null +++ b/shared/models/index.ts @@ -0,0 +1,5 @@ +export * from './pod.model' +export * from './user.model' +export * from './video-abuse.model' +export * from './video-blacklist.model' +export * from './video.model' diff --git a/shared/models/pod.model.ts b/shared/models/pod.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..d254219364a6d8fa920562be65b5946fe85fde0f --- /dev/null +++ b/shared/models/pod.model.ts @@ -0,0 +1,7 @@ +export interface Pod { + id: number, + host: string, + email: string, + score: number, + createdAt: Date +} diff --git a/shared/models/user.model.ts b/shared/models/user.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..01cc380d3c17bc7f233dd21825783416d456d86f --- /dev/null +++ b/shared/models/user.model.ts @@ -0,0 +1,8 @@ +export interface User { + id: number + username: string + email: string + displayNSFW: boolean + role: string[] + createdAt: Date +} diff --git a/shared/models/video-abuse.model.ts b/shared/models/video-abuse.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..e005a1fd52b0d104797f3970eedcb2b9d83ce309 --- /dev/null +++ b/shared/models/video-abuse.model.ts @@ -0,0 +1,8 @@ +export interface VideoAbuse { + id: number + reporterPodHost: string + reason: string + reporterUsername: string + videoId: number + createdAt: Date +} diff --git a/shared/models/video-blacklist.model.ts b/shared/models/video-blacklist.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..6086250ac3ccfc906f810d15a56bee042402f1e0 --- /dev/null +++ b/shared/models/video-blacklist.model.ts @@ -0,0 +1,5 @@ +export interface BlacklistedVideo { + id: number + videoId: number + createdAt: Date +} diff --git a/shared/models/video.model.ts b/shared/models/video.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..355e912d2e12d665a76e45dac6fb0fee61130721 --- /dev/null +++ b/shared/models/video.model.ts @@ -0,0 +1,3 @@ +export interface Video { + +} diff --git a/yarn.lock b/yarn.lock index 28d33fa975d2e86902b8d43ef870840027b0faf4..c219dcea3a0fae2735f6ef8df63e3bcbba7c3700 100644 --- a/yarn.lock +++ b/yarn.lock @@ -52,6 +52,12 @@ version "4.14.64" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.64.tgz#979cf3a3d4a368670840bf9b3e448dc33ffe84ee" +"@types/magnet-uri@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/magnet-uri/-/magnet-uri-5.1.1.tgz#861aaf64c92a3137dd848fefc55cd352a8ea851a" + dependencies: + "@types/node" "*" + "@types/mime@*": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/mime/-/mime-0.0.29.tgz#fbcfd330573b912ef59eeee14602bface630754b" @@ -66,6 +72,12 @@ dependencies: "@types/express" "*" +"@types/multer@^0.0.34": + version "0.0.34" + resolved "https://registry.yarnpkg.com/@types/multer/-/multer-0.0.34.tgz#4b542b380dcf59bced8b66294654dc67a7fab383" + dependencies: + "@types/express" "*" + "@types/node@*", "@types/node@^7.0.18": version "7.0.22" resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.22.tgz#4593f4d828bdd612929478ea40c67b4f403ca255"