From 69818c9394366b954b6ba3bd697bd9d2b09f2a16 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Sat, 10 Jun 2017 22:15:25 +0200 Subject: [PATCH] Type functions --- package.json | 2 + server/controllers/api/clients.ts | 4 +- server/controllers/api/config.ts | 2 +- server/controllers/api/index.ts | 2 +- server/controllers/api/pods.ts | 17 +-- server/controllers/api/remote/pods.ts | 2 +- server/controllers/api/remote/videos.ts | 40 +++--- server/controllers/api/requests.ts | 5 +- server/controllers/api/users.ts | 22 ++-- server/controllers/api/videos/abuse.ts | 9 +- server/controllers/api/videos/blacklist.ts | 2 +- server/controllers/api/videos/index.ts | 29 ++--- server/controllers/api/videos/rate.ts | 7 +- server/controllers/client.ts | 13 +- server/helpers/custom-validators/misc.ts | 13 +- server/helpers/custom-validators/pods.ts | 17 ++- .../helpers/custom-validators/remote/index.ts | 2 +- .../custom-validators/remote/videos.ts | 32 +++-- server/helpers/custom-validators/users.ts | 24 +++- server/helpers/custom-validators/videos.ts | 110 ++++++++++------ server/helpers/database-utils.ts | 13 +- server/helpers/peertube-crypto.ts | 26 ++-- server/helpers/requests.ts | 19 ++- server/helpers/utils.ts | 16 +-- server/initializers/checker.ts | 8 +- server/initializers/constants.ts | 2 +- server/initializers/database.ts | 4 +- server/initializers/installer.ts | 8 +- server/initializers/migrator.ts | 9 +- server/lib/friends.ts | 94 ++++++++------ server/lib/jobs/handlers/index.ts | 10 +- server/lib/jobs/handlers/video-transcoder.ts | 7 +- server/lib/jobs/job-scheduler.ts | 24 ++-- server/lib/oauth-model.ts | 15 ++- server/lib/request/base-request-scheduler.ts | 16 +-- server/lib/request/index.ts | 1 + server/lib/request/request-scheduler.ts | 23 ++-- .../request/request-video-event-scheduler.ts | 21 ++-- .../request/request-video-qadu-scheduler.ts | 21 ++-- server/middlewares/admin.ts | 5 +- server/middlewares/index.ts | 16 +-- server/middlewares/oauth.ts | 6 +- server/middlewares/pagination.ts | 5 +- server/middlewares/pods.ts | 9 +- server/middlewares/search.ts | 5 +- server/middlewares/secure.ts | 5 +- server/middlewares/sort.ts | 9 +- server/middlewares/validators/pagination.ts | 5 +- server/middlewares/validators/pods.ts | 7 +- .../validators/remote/signature.ts | 5 +- .../middlewares/validators/remote/videos.ts | 9 +- server/middlewares/validators/sort.ts | 13 +- server/middlewares/validators/users.ts | 11 +- server/middlewares/validators/utils.ts | 5 +- server/middlewares/validators/videos.ts | 28 +++-- server/models/application-interface.ts | 7 +- server/models/application.ts | 13 +- server/models/author-interface.ts | 8 +- server/models/author.ts | 15 +-- server/models/job-interface.ts | 3 +- server/models/job.ts | 2 +- server/models/oauth-client-interface.ts | 8 +- server/models/oauth-client.ts | 6 +- server/models/oauth-token-interface.ts | 20 ++- server/models/oauth-token.ts | 13 +- server/models/pod-interface.ts | 41 ++++-- server/models/pod.ts | 34 ++--- server/models/request-interface.ts | 27 +++- server/models/request-to-pod-interface.ts | 5 +- server/models/request-to-pod.ts | 2 +- .../models/request-video-event-interface.ts | 32 ++++- server/models/request-video-event.ts | 19 +-- server/models/request-video-qadu-interface.ts | 31 ++++- server/models/request-video-qadu.ts | 17 +-- server/models/request.ts | 22 ++-- server/models/tag-interface.ts | 3 +- server/models/tag.ts | 9 +- server/models/user-interface.ts | 36 ++++-- server/models/user-video-rate-interface.ts | 3 +- server/models/user-video-rate.ts | 2 +- server/models/user.ts | 18 +-- server/models/utils.ts | 6 +- server/models/video-abuse-interface.ts | 10 +- server/models/video-blacklist-interface.ts | 24 +++- server/models/video-blacklist.ts | 10 +- server/models/video-interface.ts | 118 ++++++++++++++---- server/models/video-tag-interface.ts | 2 +- server/models/video.ts | 79 ++++++------ shared/index.ts | 1 + shared/models/index.ts | 5 + shared/models/pod.model.ts | 7 ++ shared/models/user.model.ts | 8 ++ shared/models/video-abuse.model.ts | 8 ++ shared/models/video-blacklist.model.ts | 5 + shared/models/video.model.ts | 3 + yarn.lock | 12 ++ 96 files changed, 987 insertions(+), 541 deletions(-) create mode 100644 shared/index.ts create mode 100644 shared/models/index.ts create mode 100644 shared/models/pod.model.ts create mode 100644 shared/models/user.model.ts create mode 100644 shared/models/video-abuse.model.ts create mode 100644 shared/models/video-blacklist.model.ts create mode 100644 shared/models/video.model.ts diff --git a/package.json b/package.json index e7d0c39a4..71cd789ba 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 f6499556a..8c460096b 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 57c9398ec..c63981797 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 98004544d..ac3972ac6 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 a028c4ab9..283105f6c 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([ 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 9c9d2164d..b0d6642c1 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 d97a3db31..d9cc08fb4 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 ff4b4ac1a..2c18fe046 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 44c5ec13c..ffe5881e5 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 68db025b7..78e8e8b3d 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 58960798b..4b42fc2d7 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 b82b0936f..bfa018031 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 1bc575675..afdd099f8 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 c3d28245c..503eff750 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 83f50a7fe..b1291ba7a 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 ee939ad04..ec9f26cc8 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 d6f9a7e77..e29a9b767 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 4b904d011..1df7316aa 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 f303ab8db..7792ffd74 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 6389998e1..c5ef4cb5f 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 4f49c5825..f8ee9a454 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 feb32a4cd..0ac875127 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 48b1fd703..b40fc8e39 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 bc76cfb26..1dcbd31c4 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 8c3d64b60..7007f2c0b 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 7ab019f44..6dcb4bb91 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 b0f47876e..78ca5ab84 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 2f9b58991..f105c8292 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 379d43af5..d72c60638 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 6b0fbd2bf..e097f9254 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 ae5440031..7d0263b15 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 { + 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 } = { videoTranscoder } diff --git a/server/lib/jobs/handlers/video-transcoder.ts b/server/lib/jobs/handlers/video-transcoder.ts index 43599356a..efa18ef2d 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 ad5f7f6d9..2f01387e7 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(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, 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, 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, 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 3bdf0f478..7cf42e94c 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 b7ef6abf9..26bdc2bff 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 c98f956db..110d0ed78 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 26ffbfb86..69d840eeb 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 bde50b1d3..9da82585e 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 dab526088..436fd8e50 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 28b6a9a12..812397352 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 2c1c5fa53..d71dd2452 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 468e41810..d545b3e58 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 cadd76980..26a8cacf0 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 c255be899..eaf9aa144 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 05a2e7442..6fe83d25b 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 bd7cfa918..fbfd08c7b 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 ab9ccf524..632b2fae4 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 de719c05b..cca8295ff 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 c55a88b85..d8eb90168 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 6e3ebe7db..eb5c196eb 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 3380c29e2..2037c0085 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 ebc7333c7..3baee9fb3 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 e0d1d917a..b7b9ef370 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 710e65529..0424d5942 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 47825975c..e99cdefb1 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 826d25df0..c03513db1 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 acd0dfbf2..14b87777a 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 d2475c3bd..b57ce2a6b 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 {} diff --git a/server/models/author.ts b/server/models/author.ts index b543d17a0..3264d3a88 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 ad4e2d2b0..ab6678257 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 982b51499..1afae8f08 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 4efd6212a..3b4325740 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 2cefb5cb9..22fae2842 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 a0cd1ffe7..88526697e 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 + export type GetByTokenAndPopulateUser = (bearerToken: string) => Bluebird + export type GetByRefreshTokenAndPopulateUser = (refreshToken: string) => Bluebird + + 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 567df1c12..d70bd2bce 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 @@ -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 14c88bec6..8f362bd5c 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 2df32e4a4..107744c43 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 2bba8ce7f..4bbd79966 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 { +export interface RequestInstance extends RequestClass, RequestAttributes, Sequelize.Instance { id: number createdAt: Date updatedAt: Date setPods: Sequelize.HasManySetAssociationsMixin + Pods: PodInstance[] } export interface RequestModel extends RequestClass, Sequelize.Model {} diff --git a/server/models/request-to-pod-interface.ts b/server/models/request-to-pod-interface.ts index 52116d6c4..6d75ca6e5 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 { +export interface RequestToPodInstance extends RequestToPodClass, RequestToPodAttributes, Sequelize.Instance { id: number createdAt: Date updatedAt: Date diff --git a/server/models/request-to-pod.ts b/server/models/request-to-pod.ts index 681f808b7..3562069cc 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 a31c7108f..ad576a2b1 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 { +export interface RequestVideoEventInstance extends RequestVideoEventClass, RequestVideoEventAttributes, Sequelize.Instance { id: number + + Video: VideoInstance } export interface RequestVideoEventModel extends RequestVideoEventClass, Sequelize.Model {} diff --git a/server/models/request-video-event.ts b/server/models/request-video-event.ts index 234e2a8a9..e422649af 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 @@ -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 6fe34ee91..04de7f159 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 { +export interface RequestVideoQaduInstance extends RequestVideoQaduClass, RequestVideoQaduAttributes, Sequelize.Instance { id: number + + Pod: PodInstance + Video: VideoInstance } export interface RequestVideoQaduModel extends RequestVideoQaduClass, Sequelize.Model {} diff --git a/server/models/request-video-qadu.ts b/server/models/request-video-qadu.ts index e914e06cd..38627ad55 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 18fa291fa..71f81ae66 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 @@ -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 f96e1e9c5..e045e7ca5 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 b2a9c9f81..c4402e83c 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(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 a504f42a1..98963b743 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 + + 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 57d2e2b91..e48869fd2 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 { +export interface UserVideoRateInstance extends UserVideoRateClass, UserVideoRateAttributes, Sequelize.Instance { id: number createdAt: Date updatedAt: Date diff --git a/server/models/user-video-rate.ts b/server/models/user-video-rate.ts index 87886d8d0..6b71e8412 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 12ddaaeb7..0fbfdda50 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 fd84a9239..7ba96815e 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 9b77fc6f5..d9cb93b42 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 { +export interface VideoAbuseInstance extends VideoAbuseClass, VideoAbuseAttributes, Sequelize.Instance { id: number createdAt: Date updatedAt: Date diff --git a/server/models/video-blacklist-interface.ts b/server/models/video-blacklist-interface.ts index ae2cd6748..974718192 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 fe72d5d46..f36756085 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 b8dbeea35..7005f213c 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 { diff --git a/server/models/video-tag-interface.ts b/server/models/video-tag-interface.ts index 468827b8c..f928cecff 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 { +export interface VideoTagInstance extends VideoTagClass, VideoTagAttributes, Sequelize.Instance { id: number createdAt: Date updatedAt: Date diff --git a/server/models/video.ts b/server/models/video.ts index 5558a7c3b..3f808b811 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(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(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 000000000..ad200c539 --- /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 000000000..b498d620a --- /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 000000000..d25421936 --- /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 000000000..01cc380d3 --- /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 000000000..e005a1fd5 --- /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 000000000..6086250ac --- /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 000000000..355e912d2 --- /dev/null +++ b/shared/models/video.model.ts @@ -0,0 +1,3 @@ +export interface Video { + +} diff --git a/yarn.lock b/yarn.lock index 28d33fa97..c219dcea3 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" -- 2.25.1