From e02643f32e4c97ca307f8fc5b69be79c40d70a3b Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 22 May 2017 20:58:25 +0200 Subject: [PATCH] Type models --- package.json | 5 +- server.ts | 14 +- server/controllers/api/clients.ts | 2 +- server/controllers/api/config.ts | 2 +- server/controllers/api/pods.ts | 6 +- server/controllers/api/remote/pods.ts | 4 +- server/controllers/api/remote/videos.ts | 2 +- server/controllers/api/users.ts | 4 +- server/controllers/api/videos/abuse.ts | 2 +- server/controllers/api/videos/blacklist.ts | 2 +- server/controllers/api/videos/index.ts | 2 +- server/controllers/api/videos/rate.ts | 2 +- server/controllers/client.ts | 7 +- server/helpers/database-utils.ts | 4 +- server/helpers/logger.ts | 7 - server/helpers/utils.ts | 9 +- server/initializers/checker.ts | 2 +- server/initializers/constants.ts | 22 +- server/initializers/database.ts | 59 ++- server/initializers/installer.ts | 9 +- server/initializers/migrator.ts | 8 +- server/lib/friends.ts | 6 +- server/lib/jobs/handlers/video-transcoder.ts | 2 +- server/lib/jobs/job-scheduler.ts | 6 +- server/lib/oauth-model.ts | 4 +- server/lib/request/base-request-scheduler.ts | 4 +- server/lib/request/request-scheduler.ts | 9 +- .../request/request-video-event-scheduler.ts | 2 +- .../request/request-video-qadu-scheduler.ts | 2 +- server/middlewares/admin.ts | 2 +- server/middlewares/oauth.ts | 8 +- server/middlewares/pagination.ts | 4 +- server/middlewares/pods.ts | 6 +- server/middlewares/secure.ts | 10 +- server/middlewares/validators/pods.ts | 2 +- server/middlewares/validators/users.ts | 2 +- server/middlewares/validators/videos.ts | 2 +- server/models/application-interface.ts | 23 ++ server/models/application.ts | 38 +- server/models/author-interface.ts | 21 + server/models/author.ts | 36 +- server/models/index.ts | 17 + server/models/job-interface.ts | 23 ++ server/models/job.ts | 29 +- server/models/oauth-client-interface.ts | 28 ++ server/models/oauth-client.ts | 55 ++- server/models/oauth-token-interface.ts | 34 ++ server/models/oauth-token.ts | 75 ++-- server/models/pod-interface.ts | 46 +++ server/models/pod.ts | 125 +++--- server/models/request-interface.ts | 32 ++ server/models/request-to-pod-interface.ts | 20 + server/models/request-to-pod.ts | 32 +- .../models/request-video-event-interface.ts | 26 ++ server/models/request-video-event.ts | 72 ++-- server/models/request-video-qadu-interface.ts | 25 ++ server/models/request-video-qadu.ts | 68 +-- server/models/request.ts | 69 ++-- server/models/tag-interface.ts | 19 + server/models/tag.ts | 38 +- server/models/user-interface.ts | 45 ++ server/models/user-video-rate-interface.ts | 21 + server/models/user-video-rate.ts | 48 ++- server/models/user.ts | 108 +++-- server/models/utils.ts | 6 + server/models/video-abuse-interface.ts | 24 ++ server/models/video-abuse.ts | 121 +++--- server/models/video-blacklist-interface.ts | 31 ++ server/models/video-blacklist.ts | 76 ++-- server/models/video-interface.ts | 75 ++++ server/models/video-tag-interface.ts | 18 + server/models/video-tag.ts | 17 +- server/models/video.ts | 387 ++++++++++-------- server/tests/api/video-transcoder.js | 2 +- server/tests/utils/servers.js | 2 +- yarn.lock | 349 ++++++++-------- 76 files changed, 1710 insertions(+), 816 deletions(-) create mode 100644 server/models/application-interface.ts create mode 100644 server/models/author-interface.ts create mode 100644 server/models/index.ts create mode 100644 server/models/job-interface.ts create mode 100644 server/models/oauth-client-interface.ts create mode 100644 server/models/oauth-token-interface.ts create mode 100644 server/models/pod-interface.ts create mode 100644 server/models/request-interface.ts create mode 100644 server/models/request-to-pod-interface.ts create mode 100644 server/models/request-video-event-interface.ts create mode 100644 server/models/request-video-qadu-interface.ts create mode 100644 server/models/tag-interface.ts create mode 100644 server/models/user-interface.ts create mode 100644 server/models/user-video-rate-interface.ts create mode 100644 server/models/video-abuse-interface.ts create mode 100644 server/models/video-blacklist-interface.ts create mode 100644 server/models/video-interface.ts create mode 100644 server/models/video-tag-interface.ts diff --git a/package.json b/package.json index 00d0bb5ee..118a0aef6 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "rimraf": "^2.5.4", "safe-buffer": "^5.0.1", "scripty": "^1.5.0", - "sequelize": "^3.27.0", + "sequelize": "4.0.0-2", "typescript": "~2.2.0", "winston": "^2.1.1", "ws": "^2.0.0" @@ -85,12 +85,13 @@ "@types/morgan": "^1.7.32", "@types/node": "^7.0.18", "@types/request": "^0.0.43", - "@types/sequelize": "3", + "@types/sequelize": "^4.0.55", "@types/winston": "^2.3.2", "@types/ws": "^0.0.41", "chai": "^3.3.0", "commander": "^2.9.0", "mocha": "^3.0.1", + "source-map-support": "^0.4.15", "standard": "^10.0.0", "supertest": "^3.0.0", "tslint": "^5.2.0", diff --git a/server.ts b/server.ts index 119c0c61d..f5413b8e3 100644 --- a/server.ts +++ b/server.ts @@ -1,3 +1,7 @@ +if ([ 'dev', 'test'].indexOf(process.env.NODE_ENV) !== -1) { + require('source-map-support').install() +} + // ----------- Node modules ----------- import bodyParser = require('body-parser') import express = require('express') @@ -20,8 +24,8 @@ const app = express() import { logger } from './server/helpers/logger' import { API_VERSION, CONFIG } from './server/initializers/constants' // Initialize database and models -const db = require('./server/initializers/database') -db.init(onDatabaseInitDone) +import { database as db } from './server/initializers/database' +db.init(false, onDatabaseInitDone) // ----------- Checker ----------- import { checkMissedConfig, checkFFmpeg, checkConfig } from './server/initializers/checker' @@ -52,7 +56,9 @@ import { apiRouter, clientsRouter, staticRouter } from './server/controllers' // ----------- App ----------- // For the logger -// app.use(morgan('combined', { stream: logger.stream })) +app.use(morgan('combined', { + stream: { write: logger.info } +})) // For body requests app.use(bodyParser.json({ limit: '500kb' })) app.use(bodyParser.urlencoded({ extended: false })) @@ -75,7 +81,7 @@ app.use('/', staticRouter) // Always serve index client page (the client is a single page application, let it handle routing) app.use('/*', function (req, res, next) { - res.sendFile(path.join(__dirname, './client/dist/index.html')) + res.sendFile(path.join(__dirname, '../client/dist/index.html')) }) // ----------- Tracker ----------- diff --git a/server/controllers/api/clients.ts b/server/controllers/api/clients.ts index 902f62995..614163c83 100644 --- a/server/controllers/api/clients.ts +++ b/server/controllers/api/clients.ts @@ -2,7 +2,7 @@ import express = require('express') import { CONFIG } from '../../initializers'; import { logger } from '../../helpers' -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' const clientsRouter = express.Router() diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 8f3fa2473..8bdde61b3 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts @@ -1,6 +1,6 @@ import express = require('express') -import { CONFIG } from '../../initializers'; +import { CONFIG } from '../../initializers' const configRouter = express.Router() diff --git a/server/controllers/api/pods.ts b/server/controllers/api/pods.ts index 06dfd8295..4ff1f5d9f 100644 --- a/server/controllers/api/pods.ts +++ b/server/controllers/api/pods.ts @@ -1,7 +1,7 @@ import express = require('express') import { waterfall } from 'async' -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { CONFIG } from '../../initializers' import { logger, @@ -35,12 +35,12 @@ podsRouter.post('/makefriends', ensureIsAdmin, makeFriendsValidator, setBodyHostsPort, - makeFriends + makeFriendsController ) podsRouter.get('/quitfriends', authenticate, ensureIsAdmin, - quitFriends + quitFriendsController ) // --------------------------------------------------------------------------- diff --git a/server/controllers/api/remote/pods.ts b/server/controllers/api/remote/pods.ts index 85ef7bb42..7a9a0c4f0 100644 --- a/server/controllers/api/remote/pods.ts +++ b/server/controllers/api/remote/pods.ts @@ -1,7 +1,7 @@ import express = require('express') -import { waterfall } from 'async/waterfall' +import * as waterfall from 'async/waterfall' -const db = require('../../../initializers/database') +import { database as db } from '../../../initializers/database' import { checkSignature, signatureValidator } from '../../../middlewares' const remotePodsRouter = express.Router() diff --git a/server/controllers/api/remote/videos.ts b/server/controllers/api/remote/videos.ts index df4ba8309..178a21e7c 100644 --- a/server/controllers/api/remote/videos.ts +++ b/server/controllers/api/remote/videos.ts @@ -1,7 +1,7 @@ import express = require('express') import { eachSeries, waterfall } from 'async' -const db = require('../../../initializers/database') +import { database as db } from '../../../initializers/database' import { REQUEST_ENDPOINT_ACTIONS, REQUEST_ENDPOINTS, diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts index 981a4706a..97a744f54 100644 --- a/server/controllers/api/users.ts +++ b/server/controllers/api/users.ts @@ -1,7 +1,7 @@ import express = require('express') import { waterfall } from 'async' -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { CONFIG, USER_ROLES } from '../../initializers' import { logger, getFormatedObjects } from '../../helpers' import { @@ -114,7 +114,7 @@ function getUserVideoRating (req, res, next) { const videoId = req.params.videoId const userId = res.locals.oauth.token.User.id - db.UserVideoRate.load(userId, videoId, function (err, ratingObj) { + db.UserVideoRate.load(userId, videoId, null, function (err, ratingObj) { if (err) return next(err) const rating = ratingObj ? ratingObj.type : 'none' diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts index 88204120f..3dd884354 100644 --- a/server/controllers/api/videos/abuse.ts +++ b/server/controllers/api/videos/abuse.ts @@ -1,7 +1,7 @@ import express = require('express') import { waterfall } from 'async' -const db = require('../../../initializers/database') +import { database as db } from '../../../initializers/database' import friends = require('../../../lib/friends') import { logger, diff --git a/server/controllers/api/videos/blacklist.ts b/server/controllers/api/videos/blacklist.ts index db6d95e73..fb4d57d7b 100644 --- a/server/controllers/api/videos/blacklist.ts +++ b/server/controllers/api/videos/blacklist.ts @@ -1,6 +1,6 @@ import express = require('express') -const db = require('../../../initializers/database') +import { database as db } from '../../../initializers/database' import { logger } from '../../../helpers' import { authenticate, diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 5fbf03676..6eda7159b 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -4,7 +4,7 @@ import multer = require('multer') import path = require('path') import { waterfall } from 'async' -const db = require('../../../initializers/database') +import { database as db } from '../../../initializers/database' import { CONFIG, REQUEST_VIDEO_QADU_TYPES, diff --git a/server/controllers/api/videos/rate.ts b/server/controllers/api/videos/rate.ts index 21053792a..571ff68e3 100644 --- a/server/controllers/api/videos/rate.ts +++ b/server/controllers/api/videos/rate.ts @@ -1,7 +1,7 @@ import express = require('express') import { waterfall } from 'async' -const db = require('../../../initializers/database') +import { database as db } from '../../../initializers/database' import { logger, retryTransactionWrapper, diff --git a/server/controllers/client.ts b/server/controllers/client.ts index aaa04889a..ce5608c9b 100644 --- a/server/controllers/client.ts +++ b/server/controllers/client.ts @@ -6,20 +6,21 @@ import expressValidator = require('express-validator') // TODO: use .validator when express-validator typing will have validator field const validator = expressValidator['validator'] -const db = require('../initializers/database') +import { database as db } from '../initializers/database' import { CONFIG, REMOTE_SCHEME, STATIC_PATHS, STATIC_MAX_AGE } from '../initializers' +import { root } from '../helpers' const clientsRouter = express.Router() // TODO: move to constants const opengraphComment = '' -const distPath = join(__dirname, '..', '..', 'client/dist') -const embedPath = join(distPath, 'standalone/videos/embed.html') +const distPath = join(root(), 'client', 'dist') +const embedPath = join(distPath, 'standalone', 'videos', 'embed.html') const indexPath = join(distPath, 'index.html') // Special route that add OpenGraph tags diff --git a/server/helpers/database-utils.ts b/server/helpers/database-utils.ts index b842ab9ec..7d6ce4ec8 100644 --- a/server/helpers/database-utils.ts +++ b/server/helpers/database-utils.ts @@ -1,7 +1,7 @@ // TODO: import from ES6 when retry typing file will include errorFilter function import retry = require('async/retry') -const db = require('../initializers/database') +import { database as db } from '../initializers/database' import { logger } from './logger' function commitTransaction (t, callback) { @@ -52,7 +52,7 @@ function transactionRetryer (func, callback) { } function startSerializableTransaction (callback) { - db.sequelize.transaction({ isolationLevel: 'SERIALIZABLE' }).asCallback(function (err, t) { + 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/logger.ts b/server/helpers/logger.ts index 3c35e41e0..7c99db55f 100644 --- a/server/helpers/logger.ts +++ b/server/helpers/logger.ts @@ -36,13 +36,6 @@ const logger = new winston.Logger({ exitOnError: true }) -// TODO: useful? -// logger.stream = { -// write: function (message) { -// logger.info(message) -// } -// } - // --------------------------------------------------------------------------- export { logger } diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index 09c35a533..bc76cfb26 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts @@ -1,4 +1,5 @@ import { pseudoRandomBytes } from 'crypto' +import { join } from 'path' import { logger } from './logger' @@ -42,6 +43,11 @@ function getFormatedObjects (objects, objectsTotal) { } } +function root () { + // We are in /dist/helpers/utils.js + return join(__dirname, '..', '..', '..') +} + // --------------------------------------------------------------------------- export { @@ -50,5 +56,6 @@ export { cleanForExit, generateRandomString, isTestInstance, - getFormatedObjects + getFormatedObjects, + root } diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts index 370dff2d4..0ee01b0e3 100644 --- a/server/initializers/checker.ts +++ b/server/initializers/checker.ts @@ -1,6 +1,6 @@ import config = require('config') -const db = require('./database') +import { database as db } from './database' import { CONFIG } from './constants' // Some checks on configuration files diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 6bdc261ad..1072d0de0 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -1,6 +1,9 @@ import config = require('config') import { join } from 'path' +// Do not use barrels, remain constants as independent as possible +import { root, isTestInstance } from '../helpers/utils' + // --------------------------------------------------------------------------- const LAST_MIGRATION_VERSION = 50 @@ -44,12 +47,12 @@ const CONFIG = { PASSWORD: config.get('database.password') }, STORAGE: { - CERT_DIR: join(__dirname, '..', '..', config.get('storage.certs')), - LOG_DIR: join(__dirname, '..', '..', config.get('storage.logs')), - VIDEOS_DIR: join(__dirname, '..', '..', config.get('storage.videos')), - THUMBNAILS_DIR: join(__dirname, '..', '..', config.get('storage.thumbnails')), - PREVIEWS_DIR: join(__dirname, '..', '..', config.get('storage.previews')), - TORRENTS_DIR: join(__dirname, '..', '..', config.get('storage.torrents')) + CERT_DIR: join(root(), config.get('storage.certs')), + LOG_DIR: join(root(), config.get('storage.logs')), + VIDEOS_DIR: join(root(), config.get('storage.videos')), + THUMBNAILS_DIR: join(root(), config.get('storage.thumbnails')), + PREVIEWS_DIR: join(root(), config.get('storage.previews')), + TORRENTS_DIR: join(root(), config.get('storage.torrents')) }, WEBSERVER: { SCHEME: config.get('webserver.https') === true ? 'https' : 'http', @@ -334,10 +337,3 @@ export { VIDEO_LICENCES, VIDEO_RATE_TYPES } - -// --------------------------------------------------------------------------- - -// This method exists in utils module but we want to let the constants module independent -function isTestInstance () { - return (process.env.NODE_ENV === 'test') -} diff --git a/server/initializers/database.ts b/server/initializers/database.ts index 753a06669..c89a8b23c 100644 --- a/server/initializers/database.ts +++ b/server/initializers/database.ts @@ -6,12 +6,52 @@ import { CONFIG } from './constants' // Do not use barrel, we need to load database first import { logger } from '../helpers/logger' import { isTestInstance } from '../helpers/utils' +import { + ApplicationModel, + AuthorModel, + JobModel, + OAuthClientModel, + OAuthTokenModel, + PodModel, + RequestModel, + RequestToPodModel, + RequestVideoEventModel, + RequestVideoQaduModel, + TagModel, + UserModel, + UserVideoRateModel, + VideoAbuseModel, + BlacklistedVideoModel, + VideoTagModel, + VideoModel +} from '../models' const dbname = CONFIG.DATABASE.DBNAME const username = CONFIG.DATABASE.USERNAME const password = CONFIG.DATABASE.PASSWORD -const database: any = {} +const database: { + sequelize?: Sequelize.Sequelize, + init?: (silent: any, callback: any) => void, + + Application?: ApplicationModel, + Author?: AuthorModel, + Job?: JobModel, + OAuthClient?: OAuthClientModel, + OAuthToken?: OAuthTokenModel, + Pod?: PodModel, + RequestToPod?: RequestToPodModel, + RequestVideoEvent?: RequestVideoEventModel, + RequestVideoQadu?: RequestVideoQaduModel, + Request?: RequestModel, + Tag?: TagModel, + UserVideoRate?: UserVideoRateModel, + User?: UserModel, + VideoAbuse?: VideoAbuseModel, + BlacklistedVideo?: BlacklistedVideoModel, + VideoTag?: VideoTagModel, + Video?: VideoModel +} = {} const sequelize = new Sequelize(dbname, username, password, { dialect: 'postgres', @@ -32,12 +72,6 @@ const sequelize = new Sequelize(dbname, username, password, { database.sequelize = sequelize database.init = function (silent, callback) { - if (!callback) { - callback = silent - silent = false - } - - if (!callback) callback = function () { /* empty */ } const modelDirectory = join(__dirname, '..', 'models') fs.readdir(modelDirectory, function (err, files) { @@ -45,7 +79,12 @@ database.init = function (silent, callback) { files.filter(function (file) { // For all models but not utils.js - if (file === 'utils.js') return false + if ( + file === 'index.js' || + file === 'utils.js' || + file.endsWith('-interface.js') || + file.endsWith('.js.map') + ) return false return true }) @@ -69,4 +108,6 @@ database.init = function (silent, callback) { // --------------------------------------------------------------------------- -module.exports = database +export { + database +} diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index cd1404d48..467164107 100644 --- a/server/initializers/installer.ts +++ b/server/initializers/installer.ts @@ -4,10 +4,10 @@ import { each, series } from 'async' import mkdirp = require('mkdirp') import passwordGenerator = require('password-generator') -const db = require('./database') +import { database as db } from './database' import { USER_ROLES, CONFIG, LAST_MIGRATION_VERSION } from './constants' import { clientsExist, usersExist } from './checker' -import { logger, createCertsIfNotExist } from '../helpers' +import { logger, createCertsIfNotExist, root } from '../helpers' function installApplication (callback) { series([ @@ -47,7 +47,7 @@ function createDirectoriesIfNotExist (callback) { each(Object.keys(storages), function (key, callbackEach) { const dir = storages[key] - mkdirp(join(__dirname, '..', '..', dir), callbackEach) + mkdirp(join(root(), dir), callbackEach) }, callback) } @@ -65,7 +65,8 @@ function createOAuthClientIfNotExist (callback) { const client = db.OAuthClient.build({ clientId: id, clientSecret: secret, - grants: [ 'password', 'refresh_token' ] + grants: [ 'password', 'refresh_token' ], + redirectUris: null }) client.save().asCallback(function (err, createdClient) { diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts index cfa3220e0..d42cb3ccc 100644 --- a/server/initializers/migrator.ts +++ b/server/initializers/migrator.ts @@ -1,10 +1,12 @@ import { waterfall, eachSeries } from 'async' import fs = require('fs') import path = require('path') +import * as Sequelize from 'sequelize' -const db = require('./database') +import { database as db } from './database' import { LAST_MIGRATION_VERSION } from './constants' import { logger } from '../helpers' +import { ApplicationInstance } from '../models' function migrate (finalCallback) { waterfall([ @@ -94,7 +96,7 @@ function getMigrationScripts (callback) { } function executeMigration (actualVersion, entity, callback) { - const versionScript = parseInt(entity.version) + const versionScript = parseInt(entity.version, 10) // Do not execute old migration scripts if (versionScript <= actualVersion) return callback(null) @@ -112,7 +114,7 @@ function executeMigration (actualVersion, entity, callback) { transaction: t, queryInterface: db.sequelize.getQueryInterface(), sequelize: db.sequelize, - Sequelize: db.Sequelize + Sequelize: Sequelize } migrationScript.up(options, function (err) { if (err) { diff --git a/server/lib/friends.ts b/server/lib/friends.ts index b32783019..08b776e83 100644 --- a/server/lib/friends.ts +++ b/server/lib/friends.ts @@ -1,7 +1,7 @@ import { each, eachLimit, eachSeries, series, waterfall } from 'async' import request = require('request') -const db = require('../initializers/database') +import { database as db } from '../initializers/database' import { API_VERSION, CONFIG, @@ -329,7 +329,7 @@ function makeRequestsToWinningPods (cert, podsList, callback) { // Flush pool requests requestScheduler.forceSend() - eachLimit(podsList, REQUESTS_IN_PARALLEL, function (pod: any, callbackEach) { + eachLimit(podsList, REQUESTS_IN_PARALLEL, function (pod: { host: string }, callbackEach) { const params = { url: REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + API_VERSION + '/pods/', method: 'POST', @@ -340,7 +340,7 @@ function makeRequestsToWinningPods (cert, podsList, callback) { } } - makeRetryRequest(params, function (err, res, body) { + makeRetryRequest(params, function (err, res, body: { cert: string, email: string }) { if (err) { logger.error('Error with adding %s pod.', pod.host, { error: err }) // Don't break the process diff --git a/server/lib/jobs/handlers/video-transcoder.ts b/server/lib/jobs/handlers/video-transcoder.ts index 35db5fb96..43599356a 100644 --- a/server/lib/jobs/handlers/video-transcoder.ts +++ b/server/lib/jobs/handlers/video-transcoder.ts @@ -1,4 +1,4 @@ -const db = require('../../../initializers/database') +import { database as db } from '../../../initializers/database' import { logger } from '../../../helpers' import { addVideoToFriends } from '../../../lib' diff --git a/server/lib/jobs/job-scheduler.ts b/server/lib/jobs/job-scheduler.ts index 7b8c6faf9..ad5f7f6d9 100644 --- a/server/lib/jobs/job-scheduler.ts +++ b/server/lib/jobs/job-scheduler.ts @@ -1,6 +1,6 @@ import { forever, queue } from 'async' -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { JOBS_FETCHING_INTERVAL, JOBS_FETCH_LIMIT_PER_CYCLE, @@ -24,7 +24,7 @@ class JobScheduler { logger.info('Jobs scheduler activated.') - const jobsQueue = queue(this.processJob) + const jobsQueue = queue(this.processJob.bind(this)) // Finish processing jobs from a previous start const state = JOB_STATES.PROCESSING @@ -58,7 +58,7 @@ class JobScheduler { }) } - createJob (transaction, handlerName, handlerInputData, callback) { + createJob (transaction, handlerName: string, handlerInputData: object, callback) { const createQuery = { state: JOB_STATES.PENDING, handlerName, diff --git a/server/lib/oauth-model.ts b/server/lib/oauth-model.ts index 00b1afcf5..3bdf0f478 100644 --- a/server/lib/oauth-model.ts +++ b/server/lib/oauth-model.ts @@ -1,4 +1,4 @@ -const db = require('../initializers/database') +import { database as db } from '../initializers/database' import { logger } from '../helpers' // --------------------------------------------------------------------------- @@ -72,7 +72,7 @@ function saveToken (token, client, user) { userId: user.id } - return db.OAuthToken.create(tokenToCreate).then(function (tokenCreated) { + return db.OAuthToken.create(tokenToCreate).then(function (tokenCreated: any) { tokenCreated.client = client tokenCreated.user = user diff --git a/server/lib/request/base-request-scheduler.ts b/server/lib/request/base-request-scheduler.ts index 7fc88b5f1..b7ef6abf9 100644 --- a/server/lib/request/base-request-scheduler.ts +++ b/server/lib/request/base-request-scheduler.ts @@ -1,6 +1,6 @@ -import { eachLimit } from 'async/eachLimit' +import * as eachLimit from 'async/eachLimit' -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { logger, makeSecureRequest } from '../../helpers' import { API_VERSION, diff --git a/server/lib/request/request-scheduler.ts b/server/lib/request/request-scheduler.ts index 2006a6f03..26ffbfb86 100644 --- a/server/lib/request/request-scheduler.ts +++ b/server/lib/request/request-scheduler.ts @@ -1,4 +1,4 @@ -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { BaseRequestScheduler } from './base-request-scheduler' import { logger } from '../../helpers' import { @@ -59,13 +59,14 @@ class RequestScheduler extends BaseRequestScheduler { const toIds = options.toIds const transaction = options.transaction - const pods = [] + // TODO: check the setPods works + const podIds = [] // If there are no destination pods abort if (toIds.length === 0) return callback(null) toIds.forEach(toPod => { - pods.push(db.Pod.build({ id: toPod })) + podIds.push(toPod) }) const createQuery = { @@ -83,7 +84,7 @@ class RequestScheduler extends BaseRequestScheduler { return db.Request.create(createQuery, dbRequestOptions).asCallback((err, request) => { if (err) return callback(err) - return request.setPods(pods, dbRequestOptions).asCallback(callback) + return request.setPods(podIds, dbRequestOptions).asCallback(callback) }) } diff --git a/server/lib/request/request-video-event-scheduler.ts b/server/lib/request/request-video-event-scheduler.ts index 6e5306c7d..bde50b1d3 100644 --- a/server/lib/request/request-video-event-scheduler.ts +++ b/server/lib/request/request-video-event-scheduler.ts @@ -1,4 +1,4 @@ -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { BaseRequestScheduler } from './base-request-scheduler' import { REQUESTS_VIDEO_EVENT_LIMIT_PODS, diff --git a/server/lib/request/request-video-qadu-scheduler.ts b/server/lib/request/request-video-qadu-scheduler.ts index d81822723..dab526088 100644 --- a/server/lib/request/request-video-qadu-scheduler.ts +++ b/server/lib/request/request-video-qadu-scheduler.ts @@ -1,4 +1,4 @@ -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { BaseRequestScheduler } from './base-request-scheduler' import { logger } from '../../helpers' import { diff --git a/server/middlewares/admin.ts b/server/middlewares/admin.ts index ebafa36a4..28b6a9a12 100644 --- a/server/middlewares/admin.ts +++ b/server/middlewares/admin.ts @@ -1,4 +1,4 @@ -const logger = require('../helpers/logger') +import { logger } from '../helpers' function ensureIsAdmin (req, res, next) { const user = res.locals.oauth.token.user diff --git a/server/middlewares/oauth.ts b/server/middlewares/oauth.ts index 31ae1e000..07bbded57 100644 --- a/server/middlewares/oauth.ts +++ b/server/middlewares/oauth.ts @@ -1,11 +1,11 @@ import OAuthServer = require('express-oauth-server') -const constants = require('../initializers/constants') -const logger = require('../helpers/logger') +import { OAUTH_LIFETIME } from '../initializers' +import { logger } from '../helpers' const oAuthServer = new OAuthServer({ - accessTokenLifetime: constants.OAUTH_LIFETIME.ACCESS_TOKEN, - refreshTokenLifetime: constants.OAUTH_LIFETIME.REFRESH_TOKEN, + accessTokenLifetime: OAUTH_LIFETIME.ACCESS_TOKEN, + refreshTokenLifetime: OAUTH_LIFETIME.REFRESH_TOKEN, model: require('../lib/oauth-model') }) diff --git a/server/middlewares/pagination.ts b/server/middlewares/pagination.ts index 8fe9f9082..cadd76980 100644 --- a/server/middlewares/pagination.ts +++ b/server/middlewares/pagination.ts @@ -1,10 +1,10 @@ -const constants = require('../initializers/constants') +import { PAGINATION_COUNT_DEFAULT } from '../initializers' function setPagination (req, res, next) { if (!req.query.start) req.query.start = 0 else req.query.start = parseInt(req.query.start, 10) - if (!req.query.count) req.query.count = constants.PAGINATION_COUNT_DEFAULT + if (!req.query.count) req.query.count = PAGINATION_COUNT_DEFAULT else req.query.count = parseInt(req.query.count, 10) return next() diff --git a/server/middlewares/pods.ts b/server/middlewares/pods.ts index e405f265e..c255be899 100644 --- a/server/middlewares/pods.ts +++ b/server/middlewares/pods.ts @@ -1,6 +1,4 @@ -'use strict' - -const constants = require('../initializers/constants') +import { REMOTE_SCHEME } from '../initializers' function setBodyHostsPort (req, res, next) { if (!req.body.hosts) return next() @@ -48,7 +46,7 @@ function getHostWithPort (host) { // The port was not specified if (splitted.length === 1) { - if (constants.REMOTE_SCHEME.HTTP === 'https') return host + ':443' + if (REMOTE_SCHEME.HTTP === 'https') return host + ':443' return host + ':80' } diff --git a/server/middlewares/secure.ts b/server/middlewares/secure.ts index ee8545028..bd7cfa918 100644 --- a/server/middlewares/secure.ts +++ b/server/middlewares/secure.ts @@ -1,6 +1,8 @@ -const db = require('../initializers/database') -const logger = require('../helpers/logger') -const peertubeCrypto = require('../helpers/peertube-crypto') +import { database as db } from '../initializers' +import { + logger, + checkSignature as peertubeCryptoCheckSignature +} from '../helpers' function checkSignature (req, res, next) { const host = req.body.signature.host @@ -26,7 +28,7 @@ function checkSignature (req, res, next) { signatureShouldBe = host } - const signatureOk = peertubeCrypto.checkSignature(pod.publicKey, signatureShouldBe, req.body.signature.signature) + const signatureOk = peertubeCryptoCheckSignature(pod.publicKey, signatureShouldBe, req.body.signature.signature) if (signatureOk === true) { res.locals.secure = { diff --git a/server/middlewares/validators/pods.ts b/server/middlewares/validators/pods.ts index fbfd268d0..c55a88b85 100644 --- a/server/middlewares/validators/pods.ts +++ b/server/middlewares/validators/pods.ts @@ -1,4 +1,4 @@ -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { checkErrors } from './utils' import { logger } from '../../helpers' import { CONFIG } from '../../initializers' diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index a9149fe1b..e0d1d917a 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts @@ -1,4 +1,4 @@ -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { checkErrors } from './utils' import { logger } from '../../helpers' diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts index 5a49cf73c..47825975c 100644 --- a/server/middlewares/validators/videos.ts +++ b/server/middlewares/validators/videos.ts @@ -1,4 +1,4 @@ -const db = require('../../initializers/database') +import { database as db } from '../../initializers/database' import { checkErrors } from './utils' import { CONSTRAINTS_FIELDS, SEARCHABLE_COLUMNS } from '../../initializers' import { logger, isVideoDurationValid } from '../../helpers' diff --git a/server/models/application-interface.ts b/server/models/application-interface.ts new file mode 100644 index 000000000..826d25df0 --- /dev/null +++ b/server/models/application-interface.ts @@ -0,0 +1,23 @@ +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 interface ApplicationClass { + loadMigrationVersion: ApplicationMethods.LoadMigrationVersion + updateMigrationVersion: ApplicationMethods.UpdateMigrationVersion +} + +export interface ApplicationAttributes { + migrationVersion: number +} + +export interface ApplicationInstance extends ApplicationClass, ApplicationAttributes, Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface ApplicationModel extends ApplicationClass, Sequelize.Model {} diff --git a/server/models/application.ts b/server/models/application.ts index 38a57e327..acd0dfbf2 100644 --- a/server/models/application.ts +++ b/server/models/application.ts @@ -1,5 +1,20 @@ -module.exports = function (sequelize, DataTypes) { - const Application = sequelize.define('Application', +import * as Sequelize from 'sequelize' + +import { addMethodsToModel } from './utils' +import { + ApplicationClass, + ApplicationAttributes, + ApplicationInstance, + + ApplicationMethods +} from './application-interface' + +let Application: Sequelize.Model +let loadMigrationVersion: ApplicationMethods.LoadMigrationVersion +let updateMigrationVersion: ApplicationMethods.UpdateMigrationVersion + +export default function defineApplication (sequelize: Sequelize.Sequelize, DataTypes) { + Application = sequelize.define('Application', { migrationVersion: { type: DataTypes.INTEGER, @@ -9,34 +24,31 @@ module.exports = function (sequelize, DataTypes) { isInt: true } } - }, - { - classMethods: { - loadMigrationVersion, - updateMigrationVersion - } } ) + const classMethods = [ loadMigrationVersion, updateMigrationVersion ] + addMethodsToModel(Application, classMethods) + return Application } // --------------------------------------------------------------------------- -function loadMigrationVersion (callback) { +loadMigrationVersion = function (callback: (err: Error, version: number) => void) { const query = { attributes: [ 'migrationVersion' ] } - return this.findOne(query).asCallback(function (err, data) { + return Application.findOne(query).asCallback(function (err, data) { const version = data ? data.migrationVersion : null return callback(err, version) }) } -function updateMigrationVersion (newVersion, transaction, callback) { - const options: { where?: any, transaction?: any } = { +updateMigrationVersion = function (newVersion: number, transaction: any, callback: any) { + const options: Sequelize.UpdateOptions = { where: {} } @@ -46,5 +58,5 @@ function updateMigrationVersion (newVersion, transaction, callback) { options.transaction = transaction } - return this.update({ migrationVersion: newVersion }, options).asCallback(callback) + return Application.update({ migrationVersion: newVersion }, options).asCallback(callback) } diff --git a/server/models/author-interface.ts b/server/models/author-interface.ts new file mode 100644 index 000000000..d2475c3bd --- /dev/null +++ b/server/models/author-interface.ts @@ -0,0 +1,21 @@ +import * as Sequelize from 'sequelize' + +export namespace AuthorMethods { + export type FindOrCreateAuthor = (name, podId, userId, transaction, callback) => void +} + +export interface AuthorClass { + findOrCreateAuthor: AuthorMethods.FindOrCreateAuthor +} + +export interface AuthorAttributes { + name: string +} + +export interface AuthorInstance extends AuthorClass, AuthorAttributes, Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface AuthorModel extends AuthorClass, Sequelize.Model {} diff --git a/server/models/author.ts b/server/models/author.ts index 4a7396929..b543d17a0 100644 --- a/server/models/author.ts +++ b/server/models/author.ts @@ -1,7 +1,21 @@ +import * as Sequelize from 'sequelize' + import { isUserUsernameValid } from '../helpers' -module.exports = function (sequelize, DataTypes) { - const Author = sequelize.define('Author', +import { addMethodsToModel } from './utils' +import { + AuthorClass, + AuthorInstance, + AuthorAttributes, + + AuthorMethods +} from './author-interface' + +let Author: Sequelize.Model +let findOrCreateAuthor: AuthorMethods.FindOrCreateAuthor + +export default function defineAuthor (sequelize: Sequelize.Sequelize, DataTypes) { + Author = sequelize.define('Author', { name: { type: DataTypes.STRING, @@ -30,22 +44,20 @@ module.exports = function (sequelize, DataTypes) { fields: [ 'name', 'podId' ], unique: true } - ], - classMethods: { - associate, - - findOrCreateAuthor - } + ] } ) + const classMethods = [ associate, findOrCreateAuthor ] + addMethodsToModel(Author, classMethods) + return Author } // --------------------------------------------------------------------------- function associate (models) { - this.belongsTo(models.Pod, { + Author.belongsTo(models.Pod, { foreignKey: { name: 'podId', allowNull: true @@ -53,7 +65,7 @@ function associate (models) { onDelete: 'cascade' }) - this.belongsTo(models.User, { + Author.belongsTo(models.User, { foreignKey: { name: 'userId', allowNull: true @@ -62,7 +74,7 @@ function associate (models) { }) } -function findOrCreateAuthor (name, podId, userId, transaction, callback) { +findOrCreateAuthor = function (name, podId, userId, transaction, callback) { if (!callback) { callback = transaction transaction = null @@ -81,7 +93,7 @@ function findOrCreateAuthor (name, podId, userId, transaction, callback) { if (transaction) query.transaction = transaction - this.findOrCreate(query).asCallback(function (err, result) { + Author.findOrCreate(query).asCallback(function (err, result) { if (err) return callback(err) // [ instance, wasCreated ] diff --git a/server/models/index.ts b/server/models/index.ts new file mode 100644 index 000000000..432c0dc4a --- /dev/null +++ b/server/models/index.ts @@ -0,0 +1,17 @@ +export * from './application-interface' +export * from './author-interface' +export * from './job-interface' +export * from './oauth-client-interface' +export * from './oauth-token-interface' +export * from './pod-interface' +export * from './request-interface' +export * from './request-to-pod-interface' +export * from './request-video-event-interface' +export * from './request-video-qadu-interface' +export * from './tag-interface' +export * from './user-video-rate-interface' +export * from './user-interface' +export * from './video-abuse-interface' +export * from './video-blacklist-interface' +export * from './video-tag-interface' +export * from './video-interface' diff --git a/server/models/job-interface.ts b/server/models/job-interface.ts new file mode 100644 index 000000000..ad4e2d2b0 --- /dev/null +++ b/server/models/job-interface.ts @@ -0,0 +1,23 @@ +import * as Sequelize from 'sequelize' + +export namespace JobMethods { + export type ListWithLimit = (limit, state, callback) => void +} + +export interface JobClass { + listWithLimit: JobMethods.ListWithLimit +} + +export interface JobAttributes { + state: string + handlerName: string + handlerInputData: object +} + +export interface JobInstance extends JobClass, JobAttributes, Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface JobModel extends JobClass, Sequelize.Model {} diff --git a/server/models/job.ts b/server/models/job.ts index 6843e399b..982b51499 100644 --- a/server/models/job.ts +++ b/server/models/job.ts @@ -1,11 +1,22 @@ import { values } from 'lodash' +import * as Sequelize from 'sequelize' import { JOB_STATES } from '../initializers' -// --------------------------------------------------------------------------- +import { addMethodsToModel } from './utils' +import { + JobClass, + JobInstance, + JobAttributes, -module.exports = function (sequelize, DataTypes) { - const Job = sequelize.define('Job', + JobMethods +} from './job-interface' + +let Job: Sequelize.Model +let listWithLimit: JobMethods.ListWithLimit + +export default function defineJob (sequelize: Sequelize.Sequelize, DataTypes) { + Job = sequelize.define('Job', { state: { type: DataTypes.ENUM(values(JOB_STATES)), @@ -25,19 +36,19 @@ module.exports = function (sequelize, DataTypes) { { fields: [ 'state' ] } - ], - classMethods: { - listWithLimit - } + ] } ) + const classMethods = [ listWithLimit ] + addMethodsToModel(Job, classMethods) + return Job } // --------------------------------------------------------------------------- -function listWithLimit (limit, state, callback) { +listWithLimit = function (limit, state, callback) { const query = { order: [ [ 'id', 'ASC' ] @@ -48,5 +59,5 @@ function listWithLimit (limit, state, callback) { } } - return this.findAll(query).asCallback(callback) + return Job.findAll(query).asCallback(callback) } diff --git a/server/models/oauth-client-interface.ts b/server/models/oauth-client-interface.ts new file mode 100644 index 000000000..4efd6212a --- /dev/null +++ b/server/models/oauth-client-interface.ts @@ -0,0 +1,28 @@ +import * as Sequelize from 'sequelize' + +export namespace OAuthClientMethods { + export type CountTotal = (callback) => void + export type LoadFirstClient = (callback) => void + export type GetByIdAndSecret = (clientId, clientSecret) => void +} + +export interface OAuthClientClass { + countTotal: OAuthClientMethods.CountTotal + loadFirstClient: OAuthClientMethods.LoadFirstClient + getByIdAndSecret: OAuthClientMethods.GetByIdAndSecret +} + +export interface OAuthClientAttributes { + clientId: string + clientSecret: string + grants: string[] + redirectUris: string[] +} + +export interface OAuthClientInstance extends OAuthClientClass, OAuthClientAttributes, Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface OAuthClientModel extends OAuthClientClass, Sequelize.Model {} diff --git a/server/models/oauth-client.ts b/server/models/oauth-client.ts index 3198a85ef..2cefb5cb9 100644 --- a/server/models/oauth-client.ts +++ b/server/models/oauth-client.ts @@ -1,5 +1,21 @@ -module.exports = function (sequelize, DataTypes) { - const OAuthClient = sequelize.define('OAuthClient', +import * as Sequelize from 'sequelize' + +import { addMethodsToModel } from './utils' +import { + OAuthClientClass, + OAuthClientInstance, + OAuthClientAttributes, + + OAuthClientMethods +} from './oauth-client-interface' + +let OAuthClient: Sequelize.Model +let countTotal: OAuthClientMethods.CountTotal +let loadFirstClient: OAuthClientMethods.LoadFirstClient +let getByIdAndSecret: OAuthClientMethods.GetByIdAndSecret + +export default function (sequelize, DataTypes) { + OAuthClient = sequelize.define('OAuthClient', { clientId: { type: DataTypes.STRING, @@ -26,29 +42,40 @@ module.exports = function (sequelize, DataTypes) { fields: [ 'clientId', 'clientSecret' ], unique: true } - ], - classMethods: { - countTotal, - getByIdAndSecret, - loadFirstClient - } + ] } ) + const classMethods = [ + associate, + + countTotal, + getByIdAndSecret, + loadFirstClient + ] + addMethodsToModel(OAuthClient, classMethods) + return OAuthClient } // --------------------------------------------------------------------------- -function countTotal (callback) { - return this.count().asCallback(callback) +function associate (models) { + OAuthClient.hasMany(models.OAuthToken, { + foreignKey: 'oAuthClientId', + onDelete: 'cascade' + }) } -function loadFirstClient (callback) { - return this.findOne().asCallback(callback) +countTotal = function (callback) { + return OAuthClient.count().asCallback(callback) } -function getByIdAndSecret (clientId, clientSecret) { +loadFirstClient = function (callback) { + return OAuthClient.findOne().asCallback(callback) +} + +getByIdAndSecret = function (clientId, clientSecret) { const query = { where: { clientId: clientId, @@ -56,5 +83,5 @@ function getByIdAndSecret (clientId, clientSecret) { } } - return this.findOne(query) + return OAuthClient.findOne(query) } diff --git a/server/models/oauth-token-interface.ts b/server/models/oauth-token-interface.ts new file mode 100644 index 000000000..a0cd1ffe7 --- /dev/null +++ b/server/models/oauth-token-interface.ts @@ -0,0 +1,34 @@ +import * as Sequelize from 'sequelize' + +import { UserModel } from './user-interface' + +export namespace OAuthTokenMethods { + export type GetByRefreshTokenAndPopulateClient = (refreshToken) => void + export type GetByTokenAndPopulateUser = (bearerToken) => void + export type GetByRefreshTokenAndPopulateUser = (refreshToken) => any + export type RemoveByUserId = (userId, callback) => void +} + +export interface OAuthTokenClass { + getByRefreshTokenAndPopulateClient: OAuthTokenMethods.GetByRefreshTokenAndPopulateClient + getByTokenAndPopulateUser: OAuthTokenMethods.GetByTokenAndPopulateUser + getByRefreshTokenAndPopulateUser: OAuthTokenMethods.GetByRefreshTokenAndPopulateUser + removeByUserId: OAuthTokenMethods.RemoveByUserId +} + +export interface OAuthTokenAttributes { + accessToken: string + accessTokenExpiresAt: Date + refreshToken: string + refreshTokenExpiresAt: Date + + User?: UserModel +} + +export interface OAuthTokenInstance extends OAuthTokenClass, OAuthTokenAttributes, Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface OAuthTokenModel extends OAuthTokenClass, Sequelize.Model {} diff --git a/server/models/oauth-token.ts b/server/models/oauth-token.ts index 74c9180eb..567df1c12 100644 --- a/server/models/oauth-token.ts +++ b/server/models/oauth-token.ts @@ -1,9 +1,24 @@ +import * as Sequelize from 'sequelize' + import { logger } from '../helpers' -// --------------------------------------------------------------------------- +import { addMethodsToModel } from './utils' +import { + OAuthTokenClass, + OAuthTokenInstance, + OAuthTokenAttributes, -module.exports = function (sequelize, DataTypes) { - const OAuthToken = sequelize.define('OAuthToken', + OAuthTokenMethods +} from './oauth-token-interface' + +let OAuthToken: Sequelize.Model +let getByRefreshTokenAndPopulateClient: OAuthTokenMethods.GetByRefreshTokenAndPopulateClient +let getByTokenAndPopulateUser: OAuthTokenMethods.GetByTokenAndPopulateUser +let getByRefreshTokenAndPopulateUser: OAuthTokenMethods.GetByRefreshTokenAndPopulateUser +let removeByUserId: OAuthTokenMethods.RemoveByUserId + +export default function (sequelize, DataTypes) { + OAuthToken = sequelize.define('OAuthToken', { accessToken: { type: DataTypes.STRING, @@ -38,25 +53,27 @@ module.exports = function (sequelize, DataTypes) { { fields: [ 'oAuthClientId' ] } - ], - classMethods: { - associate, - - getByRefreshTokenAndPopulateClient, - getByTokenAndPopulateUser, - getByRefreshTokenAndPopulateUser, - removeByUserId - } + ] } ) + const classMethods = [ + associate, + + getByRefreshTokenAndPopulateClient, + getByTokenAndPopulateUser, + getByRefreshTokenAndPopulateUser, + removeByUserId + ] + addMethodsToModel(OAuthToken, classMethods) + return OAuthToken } // --------------------------------------------------------------------------- function associate (models) { - this.belongsTo(models.User, { + OAuthToken.belongsTo(models.User, { foreignKey: { name: 'userId', allowNull: false @@ -64,7 +81,7 @@ function associate (models) { onDelete: 'cascade' }) - this.belongsTo(models.OAuthClient, { + OAuthToken.belongsTo(models.OAuthClient, { foreignKey: { name: 'oAuthClientId', allowNull: false @@ -73,25 +90,25 @@ function associate (models) { }) } -function getByRefreshTokenAndPopulateClient (refreshToken) { +getByRefreshTokenAndPopulateClient = function (refreshToken) { const query = { where: { refreshToken: refreshToken }, - include: [ this.associations.OAuthClient ] + include: [ OAuthToken['sequelize'].models.OAuthClient ] } - return this.findOne(query).then(function (token) { + return OAuthToken.findOne(query).then(function (token) { if (!token) return token const tokenInfos = { refreshToken: token.refreshToken, refreshTokenExpiresAt: token.refreshTokenExpiresAt, client: { - id: token.client.id + id: token['client'].id }, user: { - id: token.user + id: token['user'] } } @@ -101,42 +118,42 @@ function getByRefreshTokenAndPopulateClient (refreshToken) { }) } -function getByTokenAndPopulateUser (bearerToken) { +getByTokenAndPopulateUser = function (bearerToken) { const query = { where: { accessToken: bearerToken }, - include: [ this.sequelize.models.User ] + include: [ OAuthToken['sequelize'].models.User ] } - return this.findOne(query).then(function (token) { - if (token) token.user = token.User + return OAuthToken.findOne(query).then(function (token) { + if (token) token['user'] = token.User return token }) } -function getByRefreshTokenAndPopulateUser (refreshToken) { +getByRefreshTokenAndPopulateUser = function (refreshToken) { const query = { where: { refreshToken: refreshToken }, - include: [ this.sequelize.models.User ] + include: [ OAuthToken['sequelize'].models.User ] } - return this.findOne(query).then(function (token) { - token.user = token.User + return OAuthToken.findOne(query).then(function (token) { + token['user'] = token.User return token }) } -function removeByUserId (userId, callback) { +removeByUserId = function (userId, callback) { const query = { where: { userId: userId } } - return this.destroy(query).asCallback(callback) + return OAuthToken.destroy(query).asCallback(callback) } diff --git a/server/models/pod-interface.ts b/server/models/pod-interface.ts new file mode 100644 index 000000000..14c88bec6 --- /dev/null +++ b/server/models/pod-interface.ts @@ -0,0 +1,46 @@ +import * as Sequelize from 'sequelize' + +export namespace PodMethods { + export type ToFormatedJSON = () => 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 interface PodClass { + countAll: PodMethods.CountAll + incrementScores: PodMethods.IncrementScores + list: PodMethods.List + listAllIds: PodMethods.ListAllIds + listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest + listBadPods: PodMethods.ListBadPods + load: PodMethods.Load + loadByHost: PodMethods.LoadByHost + removeAll: PodMethods.RemoveAll + updatePodsScore: PodMethods.UpdatePodsScore +} + +export interface PodAttributes { + host?: string + publicKey?: string + score?: number | Sequelize.literal // Sequelize literal for 'score +' + value + email?: string +} + +export interface PodInstance extends PodClass, PodAttributes, Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date + + toFormatedJSON: PodMethods.ToFormatedJSON, +} + +export interface PodModel extends PodClass, Sequelize.Model {} diff --git a/server/models/pod.ts b/server/models/pod.ts index 0e0262978..2df32e4a4 100644 --- a/server/models/pod.ts +++ b/server/models/pod.ts @@ -1,13 +1,34 @@ import { each, waterfall } from 'async' import { map } from 'lodash' +import * as Sequelize from 'sequelize' import { FRIEND_SCORE, PODS_SCORE } from '../initializers' import { logger, isHostValid } from '../helpers' -// --------------------------------------------------------------------------- +import { addMethodsToModel } from './utils' +import { + PodClass, + PodInstance, + PodAttributes, -module.exports = function (sequelize, DataTypes) { - const Pod = sequelize.define('Pod', + PodMethods +} from './pod-interface' + +let Pod: Sequelize.Model +let toFormatedJSON: PodMethods.ToFormatedJSON +let countAll: PodMethods.CountAll +let incrementScores: PodMethods.IncrementScores +let list: PodMethods.List +let listAllIds: PodMethods.ListAllIds +let listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest +let listBadPods: PodMethods.ListBadPods +let load: PodMethods.Load +let loadByHost: PodMethods.LoadByHost +let removeAll: PodMethods.RemoveAll +let updatePodsScore: PodMethods.UpdatePodsScore + +export default function (sequelize, DataTypes) { + Pod = sequelize.define('Pod', { host: { type: DataTypes.STRING, @@ -49,33 +70,33 @@ module.exports = function (sequelize, DataTypes) { { fields: [ 'score' ] } - ], - classMethods: { - associate, - - countAll, - incrementScores, - list, - listAllIds, - listRandomPodIdsWithRequest, - listBadPods, - load, - loadByHost, - updatePodsScore, - removeAll - }, - instanceMethods: { - toFormatedJSON - } + ] } ) + const classMethods = [ + associate, + + countAll, + incrementScores, + list, + listAllIds, + listRandomPodIdsWithRequest, + listBadPods, + load, + loadByHost, + updatePodsScore, + removeAll + ] + const instanceMethods = [ toFormatedJSON ] + addMethodsToModel(Pod, classMethods, instanceMethods) + return Pod } // ------------------------------ METHODS ------------------------------ -function toFormatedJSON () { +toFormatedJSON = function () { const json = { id: this.id, host: this.host, @@ -90,22 +111,22 @@ function toFormatedJSON () { // ------------------------------ Statics ------------------------------ function associate (models) { - this.belongsToMany(models.Request, { + Pod.belongsToMany(models.Request, { foreignKey: 'podId', through: models.RequestToPod, onDelete: 'cascade' }) } -function countAll (callback) { - return this.count().asCallback(callback) +countAll = function (callback) { + return Pod.count().asCallback(callback) } -function incrementScores (ids, value, callback) { +incrementScores = function (ids, value, callback) { if (!callback) callback = function () { /* empty */ } const update = { - score: this.sequelize.literal('score +' + value) + score: Sequelize.literal('score +' + value) } const options = { @@ -118,14 +139,14 @@ function incrementScores (ids, value, callback) { validate: false } - return this.update(update, options).asCallback(callback) + return Pod.update(update, options).asCallback(callback) } -function list (callback) { - return this.findAll().asCallback(callback) +list = function (callback) { + return Pod.findAll().asCallback(callback) } -function listAllIds (transaction, callback) { +listAllIds = function (transaction, callback) { if (!callback) { callback = transaction transaction = null @@ -137,22 +158,20 @@ function listAllIds (transaction, callback) { if (transaction) query.transaction = transaction - return this.findAll(query).asCallback(function (err, pods) { + return Pod.findAll(query).asCallback(function (err, pods) { if (err) return callback(err) return callback(null, map(pods, 'id')) }) } -function listRandomPodIdsWithRequest (limit, tableWithPods, tableWithPodsJoins, callback) { +listRandomPodIdsWithRequest = function (limit, tableWithPods, tableWithPodsJoins, callback) { if (!callback) { callback = tableWithPodsJoins tableWithPodsJoins = '' } - const self = this - - self.count().asCallback(function (err, count) { + Pod.count().asCallback(function (err, count) { if (err) return callback(err) // Optimization... @@ -171,13 +190,13 @@ function listRandomPodIdsWithRequest (limit, tableWithPods, tableWithPodsJoins, where: { id: { $in: [ - this.sequelize.literal(`SELECT DISTINCT "${tableWithPods}"."podId" FROM "${tableWithPods}" ${tableWithPodsJoins}`) + Sequelize.literal(`SELECT DISTINCT "${tableWithPods}"."podId" FROM "${tableWithPods}" ${tableWithPodsJoins}`) ] } } } - return this.findAll(query).asCallback(function (err, pods) { + return Pod.findAll(query).asCallback(function (err, pods) { if (err) return callback(err) return callback(null, map(pods, 'id')) @@ -185,49 +204,47 @@ function listRandomPodIdsWithRequest (limit, tableWithPods, tableWithPodsJoins, }) } -function listBadPods (callback) { +listBadPods = function (callback) { const query = { where: { score: { $lte: 0 } } } - return this.findAll(query).asCallback(callback) + return Pod.findAll(query).asCallback(callback) } -function load (id, callback) { - return this.findById(id).asCallback(callback) +load = function (id, callback) { + return Pod.findById(id).asCallback(callback) } -function loadByHost (host, callback) { +loadByHost = function (host, callback) { const query = { where: { host: host } } - return this.findOne(query).asCallback(callback) + return Pod.findOne(query).asCallback(callback) } -function removeAll (callback) { - return this.destroy().asCallback(callback) +removeAll = function (callback) { + return Pod.destroy().asCallback(callback) } -function updatePodsScore (goodPods, badPods) { - const self = this - +updatePodsScore = function (goodPods, badPods) { logger.info('Updating %d good pods and %d bad pods scores.', goodPods.length, badPods.length) if (goodPods.length !== 0) { - this.incrementScores(goodPods, PODS_SCORE.BONUS, function (err) { + incrementScores(goodPods, PODS_SCORE.BONUS, function (err) { if (err) logger.error('Cannot increment scores of good pods.', { error: err }) }) } if (badPods.length !== 0) { - this.incrementScores(badPods, PODS_SCORE.MALUS, function (err) { + incrementScores(badPods, PODS_SCORE.MALUS, function (err) { if (err) logger.error('Cannot decrement scores of bad pods.', { error: err }) - removeBadPods.call(self) + removeBadPods() }) } } @@ -236,11 +253,9 @@ function updatePodsScore (goodPods, badPods) { // Remove pods with a score of 0 (too many requests where they were unreachable) function removeBadPods () { - const self = this - waterfall([ function findBadPods (callback) { - self.sequelize.models.Pod.listBadPods(function (err, pods) { + listBadPods(function (err, pods) { if (err) { logger.error('Cannot find bad pods.', { error: err }) return callback(err) diff --git a/server/models/request-interface.ts b/server/models/request-interface.ts new file mode 100644 index 000000000..2bba8ce7f --- /dev/null +++ b/server/models/request-interface.ts @@ -0,0 +1,32 @@ +import * as Sequelize from 'sequelize' + +import { PodAttributes } from './pod-interface' + +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 interface RequestClass { + countTotalRequests: RequestMethods.CountTotalRequests + listWithLimitAndRandom: RequestMethods.ListWithLimitAndRandom + removeWithEmptyTo: RequestMethods.RemoveWithEmptyTo + removeAll: RequestMethods.RemoveAll +} + +export interface RequestAttributes { + request: object + endpoint: string +} + +export interface RequestInstance extends Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date + + setPods: Sequelize.HasManySetAssociationsMixin +} + +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 new file mode 100644 index 000000000..52116d6c4 --- /dev/null +++ b/server/models/request-to-pod-interface.ts @@ -0,0 +1,20 @@ +import * as Sequelize from 'sequelize' + +export namespace RequestToPodMethods { + export type RemoveByRequestIdsAndPod = (requestsIds, podId, callback) => void +} + +export interface RequestToPodClass { + removeByRequestIdsAndPod: RequestToPodMethods.RemoveByRequestIdsAndPod +} + +export interface RequestToPodAttributes { +} + +export interface RequestToPodInstance extends Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface RequestToPodModel extends RequestToPodClass, Sequelize.Model {} diff --git a/server/models/request-to-pod.ts b/server/models/request-to-pod.ts index 479202e40..681f808b7 100644 --- a/server/models/request-to-pod.ts +++ b/server/models/request-to-pod.ts @@ -1,5 +1,19 @@ -module.exports = function (sequelize, DataTypes) { - const RequestToPod = sequelize.define('RequestToPod', {}, { +import * as Sequelize from 'sequelize' + +import { addMethodsToModel } from './utils' +import { + RequestToPodClass, + RequestToPodInstance, + RequestToPodAttributes, + + RequestToPodMethods +} from './request-to-pod-interface' + +let RequestToPod: Sequelize.Model +let removeByRequestIdsAndPod: RequestToPodMethods.RemoveByRequestIdsAndPod + +export default function (sequelize, DataTypes) { + RequestToPod = sequelize.define('RequestToPod', {}, { indexes: [ { fields: [ 'requestId' ] @@ -11,18 +25,20 @@ module.exports = function (sequelize, DataTypes) { fields: [ 'requestId', 'podId' ], unique: true } - ], - classMethods: { - removeByRequestIdsAndPod - } + ] }) + const classMethods = [ + removeByRequestIdsAndPod + ] + addMethodsToModel(RequestToPod, classMethods) + return RequestToPod } // --------------------------------------------------------------------------- -function removeByRequestIdsAndPod (requestsIds, podId, callback) { +removeByRequestIdsAndPod = function (requestsIds, podId, callback) { if (!callback) callback = function () { /* empty */ } const query = { @@ -34,5 +50,5 @@ function removeByRequestIdsAndPod (requestsIds, podId, callback) { } } - this.destroy(query).asCallback(callback) + RequestToPod.destroy(query).asCallback(callback) } diff --git a/server/models/request-video-event-interface.ts b/server/models/request-video-event-interface.ts new file mode 100644 index 000000000..a31c7108f --- /dev/null +++ b/server/models/request-video-event-interface.ts @@ -0,0 +1,26 @@ +import * as Sequelize from 'sequelize' + +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 interface RequestVideoEventClass { + countTotalRequests: RequestVideoEventMethods.CountTotalRequests + listWithLimitAndRandom: RequestVideoEventMethods.ListWithLimitAndRandom + removeByRequestIdsAndPod: RequestVideoEventMethods.RemoveByRequestIdsAndPod + removeAll: RequestVideoEventMethods.RemoveAll +} + +export interface RequestVideoEventAttributes { + type: string + count: number +} + +export interface RequestVideoEventInstance extends Sequelize.Instance { + id: number +} + +export interface RequestVideoEventModel extends RequestVideoEventClass, Sequelize.Model {} diff --git a/server/models/request-video-event.ts b/server/models/request-video-event.ts index c61525029..234e2a8a9 100644 --- a/server/models/request-video-event.ts +++ b/server/models/request-video-event.ts @@ -3,14 +3,28 @@ */ import { values } from 'lodash' +import * as Sequelize from 'sequelize' import { REQUEST_VIDEO_EVENT_TYPES } from '../initializers' import { isVideoEventCountValid } from '../helpers' -// --------------------------------------------------------------------------- +import { addMethodsToModel } from './utils' +import { + RequestVideoEventClass, + RequestVideoEventInstance, + RequestVideoEventAttributes, -module.exports = function (sequelize, DataTypes) { - const RequestVideoEvent = sequelize.define('RequestVideoEvent', + RequestVideoEventMethods +} from './request-video-event-interface' + +let RequestVideoEvent: Sequelize.Model +let countTotalRequests: RequestVideoEventMethods.CountTotalRequests +let listWithLimitAndRandom: RequestVideoEventMethods.ListWithLimitAndRandom +let removeByRequestIdsAndPod: RequestVideoEventMethods.RemoveByRequestIdsAndPod +let removeAll: RequestVideoEventMethods.RemoveAll + +export default function (sequelize, DataTypes) { + RequestVideoEvent = sequelize.define('RequestVideoEvent', { type: { type: DataTypes.ENUM(values(REQUEST_VIDEO_EVENT_TYPES)), @@ -33,26 +47,27 @@ module.exports = function (sequelize, DataTypes) { { fields: [ 'videoId' ] } - ], - classMethods: { - associate, - - listWithLimitAndRandom, - - countTotalRequests, - removeAll, - removeByRequestIdsAndPod - } + ] } ) + const classMethods = [ + associate, + + listWithLimitAndRandom, + countTotalRequests, + removeAll, + removeByRequestIdsAndPod + ] + addMethodsToModel(RequestVideoEvent, classMethods) + return RequestVideoEvent } // ------------------------------ STATICS ------------------------------ function associate (models) { - this.belongsTo(models.Video, { + RequestVideoEvent.belongsTo(models.Video, { foreignKey: { name: 'videoId', allowNull: false @@ -61,14 +76,13 @@ function associate (models) { }) } -function countTotalRequests (callback) { +countTotalRequests = function (callback) { const query = {} - return this.count(query).asCallback(callback) + return RequestVideoEvent.count(query).asCallback(callback) } -function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { - const self = this - const Pod = this.sequelize.models.Pod +listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { + const Pod = RequestVideoEvent['sequelize'].models.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" ' + @@ -86,13 +100,13 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { ], include: [ { - model: self.sequelize.models.Video, + model: RequestVideoEvent['sequelize'].models.Video, include: [ { - model: self.sequelize.models.Author, + model: RequestVideoEvent['sequelize'].models.Author, include: [ { - model: self.sequelize.models.Pod, + model: RequestVideoEvent['sequelize'].models.Pod, where: { id: { $in: podIds @@ -106,7 +120,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { ] } - self.findAll(query).asCallback(function (err, requests) { + RequestVideoEvent.findAll(query).asCallback(function (err, requests) { if (err) return callback(err) const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) @@ -115,7 +129,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { }) } -function removeByRequestIdsAndPod (ids, podId, callback) { +removeByRequestIdsAndPod = function (ids, podId, callback) { const query = { where: { id: { @@ -124,10 +138,10 @@ function removeByRequestIdsAndPod (ids, podId, callback) { }, include: [ { - model: this.sequelize.models.Video, + model: RequestVideoEvent['sequelize'].models.Video, include: [ { - model: this.sequelize.models.Author, + model: RequestVideoEvent['sequelize'].models.Author, where: { podId } @@ -137,12 +151,12 @@ function removeByRequestIdsAndPod (ids, podId, callback) { ] } - this.destroy(query).asCallback(callback) + RequestVideoEvent.destroy(query).asCallback(callback) } -function removeAll (callback) { +removeAll = function (callback) { // Delete all requests - this.truncate({ cascade: true }).asCallback(callback) + RequestVideoEvent.truncate({ cascade: true }).asCallback(callback) } // --------------------------------------------------------------------------- diff --git a/server/models/request-video-qadu-interface.ts b/server/models/request-video-qadu-interface.ts new file mode 100644 index 000000000..6fe34ee91 --- /dev/null +++ b/server/models/request-video-qadu-interface.ts @@ -0,0 +1,25 @@ +import * as Sequelize from 'sequelize' + +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 interface RequestVideoQaduClass { + countTotalRequests: RequestVideoQaduMethods.CountTotalRequests + listWithLimitAndRandom: RequestVideoQaduMethods.ListWithLimitAndRandom + removeByRequestIdsAndPod: RequestVideoQaduMethods.RemoveByRequestIdsAndPod + removeAll: RequestVideoQaduMethods.RemoveAll +} + +export interface RequestVideoQaduAttributes { + type: string +} + +export interface RequestVideoQaduInstance extends Sequelize.Instance { + id: number +} + +export interface RequestVideoQaduModel extends RequestVideoQaduClass, Sequelize.Model {} diff --git a/server/models/request-video-qadu.ts b/server/models/request-video-qadu.ts index 2b1ed07c9..e914e06cd 100644 --- a/server/models/request-video-qadu.ts +++ b/server/models/request-video-qadu.ts @@ -10,13 +10,27 @@ */ import { values } from 'lodash' +import * as Sequelize from 'sequelize' import { REQUEST_VIDEO_QADU_TYPES } from '../initializers' -// --------------------------------------------------------------------------- +import { addMethodsToModel } from './utils' +import { + RequestVideoQaduClass, + RequestVideoQaduInstance, + RequestVideoQaduAttributes, -module.exports = function (sequelize, DataTypes) { - const RequestVideoQadu = sequelize.define('RequestVideoQadu', + RequestVideoQaduMethods +} from './request-video-qadu-interface' + +let RequestVideoQadu: Sequelize.Model +let countTotalRequests: RequestVideoQaduMethods.CountTotalRequests +let listWithLimitAndRandom: RequestVideoQaduMethods.ListWithLimitAndRandom +let removeByRequestIdsAndPod: RequestVideoQaduMethods.RemoveByRequestIdsAndPod +let removeAll: RequestVideoQaduMethods.RemoveAll + +export default function (sequelize, DataTypes) { + RequestVideoQadu = sequelize.define('RequestVideoQadu', { type: { type: DataTypes.ENUM(values(REQUEST_VIDEO_QADU_TYPES)), @@ -32,26 +46,27 @@ module.exports = function (sequelize, DataTypes) { { fields: [ 'videoId' ] } - ], - classMethods: { - associate, - - listWithLimitAndRandom, - - countTotalRequests, - removeAll, - removeByRequestIdsAndPod - } + ] } ) + const classMethods = [ + associate, + + listWithLimitAndRandom, + countTotalRequests, + removeAll, + removeByRequestIdsAndPod + ] + addMethodsToModel(RequestVideoQadu, classMethods) + return RequestVideoQadu } // ------------------------------ STATICS ------------------------------ function associate (models) { - this.belongsTo(models.Pod, { + RequestVideoQadu.belongsTo(models.Pod, { foreignKey: { name: 'podId', allowNull: false @@ -59,7 +74,7 @@ function associate (models) { onDelete: 'CASCADE' }) - this.belongsTo(models.Video, { + RequestVideoQadu.belongsTo(models.Video, { foreignKey: { name: 'videoId', allowNull: false @@ -68,14 +83,13 @@ function associate (models) { }) } -function countTotalRequests (callback) { +countTotalRequests = function (callback) { const query = {} - return this.count(query).asCallback(callback) + return RequestVideoQadu.count(query).asCallback(callback) } -function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { - const self = this - const Pod = this.sequelize.models.Pod +listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { + const Pod = RequestVideoQadu['sequelize'].models.Pod Pod.listRandomPodIdsWithRequest(limitPods, 'RequestVideoQadus', function (err, podIds) { if (err) return callback(err) @@ -86,7 +100,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { const query = { include: [ { - model: self.sequelize.models.Pod, + model: RequestVideoQadu['sequelize'].models.Pod, where: { id: { $in: podIds @@ -94,12 +108,12 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { } }, { - model: self.sequelize.models.Video + model: RequestVideoQadu['sequelize'].models.Video } ] } - self.findAll(query).asCallback(function (err, requests) { + RequestVideoQadu.findAll(query).asCallback(function (err, requests) { if (err) return callback(err) const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) @@ -108,7 +122,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { }) } -function removeByRequestIdsAndPod (ids, podId, callback) { +removeByRequestIdsAndPod = function (ids, podId, callback) { const query = { where: { id: { @@ -118,12 +132,12 @@ function removeByRequestIdsAndPod (ids, podId, callback) { } } - this.destroy(query).asCallback(callback) + RequestVideoQadu.destroy(query).asCallback(callback) } -function removeAll (callback) { +removeAll = function (callback) { // Delete all requests - this.truncate({ cascade: true }).asCallback(callback) + RequestVideoQadu.truncate({ cascade: true }).asCallback(callback) } // --------------------------------------------------------------------------- diff --git a/server/models/request.ts b/server/models/request.ts index 672f79d11..18fa291fa 100644 --- a/server/models/request.ts +++ b/server/models/request.ts @@ -1,11 +1,25 @@ import { values } from 'lodash' +import * as Sequelize from 'sequelize' import { REQUEST_ENDPOINTS } from '../initializers' -// --------------------------------------------------------------------------- +import { addMethodsToModel } from './utils' +import { + RequestClass, + RequestInstance, + RequestAttributes, -module.exports = function (sequelize, DataTypes) { - const Request = sequelize.define('Request', + RequestMethods +} from './request-interface' + +let Request: Sequelize.Model +let countTotalRequests: RequestMethods.CountTotalRequests +let listWithLimitAndRandom: RequestMethods.ListWithLimitAndRandom +let removeWithEmptyTo: RequestMethods.RemoveWithEmptyTo +let removeAll: RequestMethods.RemoveAll + +export default function (sequelize, DataTypes) { + Request = sequelize.define('Request', { request: { type: DataTypes.JSON, @@ -15,27 +29,27 @@ module.exports = function (sequelize, DataTypes) { type: DataTypes.ENUM(values(REQUEST_ENDPOINTS)), allowNull: false } - }, - { - classMethods: { - associate, - - listWithLimitAndRandom, - - countTotalRequests, - removeAll, - removeWithEmptyTo - } } ) + const classMethods = [ + associate, + + listWithLimitAndRandom, + + countTotalRequests, + removeAll, + removeWithEmptyTo + ] + addMethodsToModel(Request, classMethods) + return Request } // ------------------------------ STATICS ------------------------------ function associate (models) { - this.belongsToMany(models.Pod, { + Request.belongsToMany(models.Pod, { foreignKey: { name: 'requestId', allowNull: false @@ -45,19 +59,18 @@ function associate (models) { }) } -function countTotalRequests (callback) { +countTotalRequests = function (callback) { // 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 = { - include: [ this.sequelize.models.Pod ] + include: [ Request['sequelize'].models.Pod ] } - return this.count(query).asCallback(callback) + return Request.count(query).asCallback(callback) } -function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { - const self = this - const Pod = this.sequelize.models.Pod +listWithLimitAndRandom = function (limitPods, limitRequestsPerPod, callback) { + const Pod = Request['sequelize'].models.Pod Pod.listRandomPodIdsWithRequest(limitPods, 'RequestToPods', function (err, podIds) { if (err) return callback(err) @@ -73,7 +86,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { ], include: [ { - model: self.sequelize.models.Pod, + model: Request['sequelize'].models.Pod, where: { id: { $in: podIds @@ -83,7 +96,7 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { ] } - self.findAll(query).asCallback(function (err, requests) { + Request.findAll(query).asCallback(function (err, requests) { if (err) return callback(err) const requestsGrouped = groupAndTruncateRequests(requests, limitRequestsPerPod) @@ -92,25 +105,25 @@ function listWithLimitAndRandom (limitPods, limitRequestsPerPod, callback) { }) } -function removeAll (callback) { +removeAll = function (callback) { // Delete all requests - this.truncate({ cascade: true }).asCallback(callback) + Request.truncate({ cascade: true }).asCallback(callback) } -function removeWithEmptyTo (callback) { +removeWithEmptyTo = function (callback) { if (!callback) callback = function () { /* empty */ } const query = { where: { id: { $notIn: [ - this.sequelize.literal('SELECT "requestId" FROM "RequestToPods"') + Sequelize.literal('SELECT "requestId" FROM "RequestToPods"') ] } } } - this.destroy(query).asCallback(callback) + Request.destroy(query).asCallback(callback) } // --------------------------------------------------------------------------- diff --git a/server/models/tag-interface.ts b/server/models/tag-interface.ts new file mode 100644 index 000000000..f96e1e9c5 --- /dev/null +++ b/server/models/tag-interface.ts @@ -0,0 +1,19 @@ +import * as Sequelize from 'sequelize' + +export namespace TagMethods { + export type FindOrCreateTags = (tags, transaction, callback) => void +} + +export interface TagClass { + findOrCreateTags: TagMethods.FindOrCreateTags +} + +export interface TagAttributes { + name: string +} + +export interface TagInstance extends TagClass, TagAttributes, Sequelize.Instance { + id: number +} + +export interface TagModel extends TagClass, Sequelize.Model {} diff --git a/server/models/tag.ts b/server/models/tag.ts index 85a0442d2..b2a9c9f81 100644 --- a/server/models/tag.ts +++ b/server/models/tag.ts @@ -1,9 +1,20 @@ import { each } from 'async' +import * as Sequelize from 'sequelize' -// --------------------------------------------------------------------------- +import { addMethodsToModel } from './utils' +import { + TagClass, + TagInstance, + TagAttributes, -module.exports = function (sequelize, DataTypes) { - const Tag = sequelize.define('Tag', + TagMethods +} from './tag-interface' + +let Tag: Sequelize.Model +let findOrCreateTags: TagMethods.FindOrCreateTags + +export default function (sequelize, DataTypes) { + Tag = sequelize.define('Tag', { name: { type: DataTypes.STRING, @@ -17,35 +28,36 @@ module.exports = function (sequelize, DataTypes) { fields: [ 'name' ], unique: true } - ], - classMethods: { - associate, - - findOrCreateTags - } + ] } ) + const classMethods = [ + associate, + + findOrCreateTags + ] + addMethodsToModel(Tag, classMethods) + return Tag } // --------------------------------------------------------------------------- function associate (models) { - this.belongsToMany(models.Video, { + Tag.belongsToMany(models.Video, { foreignKey: 'tagId', through: models.VideoTag, onDelete: 'cascade' }) } -function findOrCreateTags (tags, transaction, callback) { +findOrCreateTags = function (tags, transaction, callback) { if (!callback) { callback = transaction transaction = null } - const self = this const tagInstances = [] each(tags, function (tag, callbackEach) { @@ -60,7 +72,7 @@ function findOrCreateTags (tags, transaction, callback) { if (transaction) query.transaction = transaction - self.findOrCreate(query).asCallback(function (err, res) { + Tag.findOrCreate(query).asCallback(function (err, res) { if (err) return callbackEach(err) // res = [ tag, isCreated ] diff --git a/server/models/user-interface.ts b/server/models/user-interface.ts new file mode 100644 index 000000000..a504f42a1 --- /dev/null +++ b/server/models/user-interface.ts @@ -0,0 +1,45 @@ +import * as Sequelize from 'sequelize' + +export namespace UserMethods { + export type IsPasswordMatch = (password, callback) => void + export type ToFormatedJSON = () => void + 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 interface UserClass { + isPasswordMatch: UserMethods.IsPasswordMatch, + toFormatedJSON: UserMethods.ToFormatedJSON, + isAdmin: UserMethods.IsAdmin, + + countTotal: UserMethods.CountTotal, + getByUsername: UserMethods.GetByUsername, + list: UserMethods.List, + listForApi: UserMethods.ListForApi, + loadById: UserMethods.LoadById, + loadByUsername: UserMethods.LoadByUsername, + loadByUsernameOrEmail: UserMethods.LoadByUsernameOrEmail +} + +export interface UserAttributes { + password: string + username: string + email: string + displayNSFW?: boolean + role: string +} + +export interface UserInstance extends UserClass, UserAttributes, Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface UserModel extends UserClass, Sequelize.Model {} diff --git a/server/models/user-video-rate-interface.ts b/server/models/user-video-rate-interface.ts new file mode 100644 index 000000000..57d2e2b91 --- /dev/null +++ b/server/models/user-video-rate-interface.ts @@ -0,0 +1,21 @@ +import * as Sequelize from 'sequelize' + +export namespace UserVideoRateMethods { + export type Load = (userId, videoId, transaction, callback) => void +} + +export interface UserVideoRateClass { + load: UserVideoRateMethods.Load +} + +export interface UserVideoRateAttributes { + type: string +} + +export interface UserVideoRateInstance extends Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface UserVideoRateModel extends UserVideoRateClass, Sequelize.Model {} diff --git a/server/models/user-video-rate.ts b/server/models/user-video-rate.ts index 6603c7862..87886d8d0 100644 --- a/server/models/user-video-rate.ts +++ b/server/models/user-video-rate.ts @@ -3,13 +3,24 @@ */ import { values } from 'lodash' +import * as Sequelize from 'sequelize' import { VIDEO_RATE_TYPES } from '../initializers' -// --------------------------------------------------------------------------- +import { addMethodsToModel } from './utils' +import { + UserVideoRateClass, + UserVideoRateInstance, + UserVideoRateAttributes, -module.exports = function (sequelize, DataTypes) { - const UserVideoRate = sequelize.define('UserVideoRate', + UserVideoRateMethods +} from './user-video-rate-interface' + +let UserVideoRate: Sequelize.Model +let load: UserVideoRateMethods.Load + +export default function (sequelize, DataTypes) { + UserVideoRate = sequelize.define('UserVideoRate', { type: { type: DataTypes.ENUM(values(VIDEO_RATE_TYPES)), @@ -22,22 +33,24 @@ module.exports = function (sequelize, DataTypes) { fields: [ 'videoId', 'userId', 'type' ], unique: true } - ], - classMethods: { - associate, - - load - } + ] } ) + const classMethods = [ + associate, + + load + ] + addMethodsToModel(UserVideoRate, classMethods) + return UserVideoRate } // ------------------------------ STATICS ------------------------------ function associate (models) { - this.belongsTo(models.Video, { + UserVideoRate.belongsTo(models.Video, { foreignKey: { name: 'videoId', allowNull: false @@ -45,7 +58,7 @@ function associate (models) { onDelete: 'CASCADE' }) - this.belongsTo(models.User, { + UserVideoRate.belongsTo(models.User, { foreignKey: { name: 'userId', allowNull: false @@ -54,21 +67,14 @@ function associate (models) { }) } -function load (userId, videoId, transaction, callback) { - if (!callback) { - callback = transaction - transaction = null - } - - const query = { +load = function (userId, videoId, transaction, callback) { + const options: Sequelize.FindOptions = { where: { userId, videoId } } - - const options: any = {} if (transaction) options.transaction = transaction - return this.findOne(query, options).asCallback(callback) + return UserVideoRate.findOne(options).asCallback(callback) } diff --git a/server/models/user.ts b/server/models/user.ts index d63a50cc4..12ddaaeb7 100644 --- a/server/models/user.ts +++ b/server/models/user.ts @@ -1,4 +1,5 @@ import { values } from 'lodash' +import * as Sequelize from 'sequelize' import { getSort } from './utils' import { USER_ROLES } from '../initializers' @@ -10,10 +11,29 @@ import { isUserDisplayNSFWValid } from '../helpers' -// --------------------------------------------------------------------------- +import { addMethodsToModel } from './utils' +import { + UserClass, + UserInstance, + UserAttributes, -module.exports = function (sequelize, DataTypes) { - const User = sequelize.define('User', + UserMethods +} from './user-interface' + +let User: Sequelize.Model +let isPasswordMatch: UserMethods.IsPasswordMatch +let toFormatedJSON: UserMethods.ToFormatedJSON +let isAdmin: UserMethods.IsAdmin +let countTotal: UserMethods.CountTotal +let getByUsername: UserMethods.GetByUsername +let list: UserMethods.List +let listForApi: UserMethods.ListForApi +let loadById: UserMethods.LoadById +let loadByUsername: UserMethods.LoadByUsername +let loadByUsernameOrEmail: UserMethods.LoadByUsernameOrEmail + +export default function (sequelize, DataTypes) { + User = sequelize.define('User', { password: { type: DataTypes.STRING, @@ -69,22 +89,6 @@ module.exports = function (sequelize, DataTypes) { unique: true } ], - classMethods: { - associate, - - countTotal, - getByUsername, - list, - listForApi, - loadById, - loadByUsername, - loadByUsernameOrEmail - }, - instanceMethods: { - isPasswordMatch, - toFormatedJSON, - isAdmin - }, hooks: { beforeCreate: beforeCreateOrUpdate, beforeUpdate: beforeCreateOrUpdate @@ -92,26 +96,46 @@ module.exports = function (sequelize, DataTypes) { } ) + const classMethods = [ + associate, + + countTotal, + getByUsername, + list, + listForApi, + loadById, + loadByUsername, + loadByUsernameOrEmail + ] + const instanceMethods = [ + isPasswordMatch, + toFormatedJSON, + isAdmin + ] + addMethodsToModel(User, classMethods, instanceMethods) + return User } -function beforeCreateOrUpdate (user, options, next) { - cryptPassword(user.password, function (err, hash) { - if (err) return next(err) +function beforeCreateOrUpdate (user, options) { + return new Promise(function (resolve, reject) { + cryptPassword(user.password, function (err, hash) { + if (err) return reject(err) - user.password = hash + user.password = hash - return next() + return resolve() + }) }) } // ------------------------------ METHODS ------------------------------ -function isPasswordMatch (password, callback) { +isPasswordMatch = function (password, callback) { return comparePassword(password, this.password, callback) } -function toFormatedJSON () { +toFormatedJSON = function () { return { id: this.id, username: this.username, @@ -122,76 +146,76 @@ function toFormatedJSON () { } } -function isAdmin () { +isAdmin = function () { return this.role === USER_ROLES.ADMIN } // ------------------------------ STATICS ------------------------------ function associate (models) { - this.hasOne(models.Author, { + User.hasOne(models.Author, { foreignKey: 'userId', onDelete: 'cascade' }) - this.hasMany(models.OAuthToken, { + User.hasMany(models.OAuthToken, { foreignKey: 'userId', onDelete: 'cascade' }) } -function countTotal (callback) { +countTotal = function (callback) { return this.count().asCallback(callback) } -function getByUsername (username) { +getByUsername = function (username) { const query = { where: { username: username } } - return this.findOne(query) + return User.findOne(query) } -function list (callback) { - return this.find().asCallback(callback) +list = function (callback) { + return User.find().asCallback(callback) } -function listForApi (start, count, sort, callback) { +listForApi = function (start, count, sort, callback) { const query = { offset: start, limit: count, order: [ getSort(sort) ] } - return this.findAndCountAll(query).asCallback(function (err, result) { + return User.findAndCountAll(query).asCallback(function (err, result) { if (err) return callback(err) return callback(null, result.rows, result.count) }) } -function loadById (id, callback) { - return this.findById(id).asCallback(callback) +loadById = function (id, callback) { + return User.findById(id).asCallback(callback) } -function loadByUsername (username, callback) { +loadByUsername = function (username, callback) { const query = { where: { username: username } } - return this.findOne(query).asCallback(callback) + return User.findOne(query).asCallback(callback) } -function loadByUsernameOrEmail (username, email, callback) { +loadByUsernameOrEmail = function (username, email, callback) { const query = { where: { $or: [ { username }, { email } ] } } - return this.findOne(query).asCallback(callback) + return User.findOne(query).asCallback(callback) } diff --git a/server/models/utils.ts b/server/models/utils.ts index 601811913..fd84a9239 100644 --- a/server/models/utils.ts +++ b/server/models/utils.ts @@ -14,8 +14,14 @@ function getSort (value) { return [ field, direction ] } +function addMethodsToModel (model: any, classMethods: Function[], instanceMethods: Function[] = []) { + classMethods.forEach(m => model[m.name] = m) + instanceMethods.forEach(m => model.prototype[m.name] = m) +} + // --------------------------------------------------------------------------- export { + addMethodsToModel, getSort } diff --git a/server/models/video-abuse-interface.ts b/server/models/video-abuse-interface.ts new file mode 100644 index 000000000..9b77fc6f5 --- /dev/null +++ b/server/models/video-abuse-interface.ts @@ -0,0 +1,24 @@ +import * as Sequelize from 'sequelize' + +export namespace VideoAbuseMethods { + export type toFormatedJSON = () => void + + export type ListForApi = (start, count, sort, callback) => void +} + +export interface VideoAbuseClass { + listForApi: VideoAbuseMethods.ListForApi +} + +export interface VideoAbuseAttributes { + reporterUsername: string + reason: string +} + +export interface VideoAbuseInstance extends Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface VideoAbuseModel extends VideoAbuseClass, Sequelize.Model {} diff --git a/server/models/video-abuse.ts b/server/models/video-abuse.ts index 2a18a293d..92168439c 100644 --- a/server/models/video-abuse.ts +++ b/server/models/video-abuse.ts @@ -1,9 +1,22 @@ +import * as Sequelize from 'sequelize' + import { CONFIG } from '../initializers' import { isVideoAbuseReporterUsernameValid, isVideoAbuseReasonValid } from '../helpers' -import { getSort } from './utils' -module.exports = function (sequelize, DataTypes) { - const VideoAbuse = sequelize.define('VideoAbuse', +import { addMethodsToModel, getSort } from './utils' +import { + VideoAbuseClass, + VideoAbuseInstance, + VideoAbuseAttributes, + + VideoAbuseMethods +} from './video-abuse-interface' + +let VideoAbuse: Sequelize.Model +let listForApi: VideoAbuseMethods.ListForApi + +export default function (sequelize, DataTypes) { + VideoAbuse = sequelize.define('VideoAbuse', { reporterUsername: { type: DataTypes.STRING, @@ -34,60 +47,24 @@ module.exports = function (sequelize, DataTypes) { { fields: [ 'reporterPodId' ] } - ], - classMethods: { - associate, - - listForApi - }, - instanceMethods: { - toFormatedJSON - } + ] } ) + const classMethods = [ + associate, + + listForApi + ] + const instanceMethods = [ + toFormatedJSON + ] + addMethodsToModel(VideoAbuse, classMethods, instanceMethods) + return VideoAbuse } -// --------------------------------------------------------------------------- - -function associate (models) { - this.belongsTo(models.Pod, { - foreignKey: { - name: 'reporterPodId', - allowNull: true - }, - onDelete: 'cascade' - }) - - this.belongsTo(models.Video, { - foreignKey: { - name: 'videoId', - allowNull: false - }, - onDelete: 'cascade' - }) -} - -function listForApi (start, count, sort, callback) { - const query = { - offset: start, - limit: count, - order: [ getSort(sort) ], - include: [ - { - model: this.sequelize.models.Pod, - required: false - } - ] - } - - return this.findAndCountAll(query).asCallback(function (err, result) { - if (err) return callback(err) - - return callback(null, result.rows, result.count) - }) -} +// ------------------------------ METHODS ------------------------------ function toFormatedJSON () { let reporterPodHost @@ -110,3 +87,45 @@ function toFormatedJSON () { return json } + +// ------------------------------ STATICS ------------------------------ + +function associate (models) { + VideoAbuse.belongsTo(models.Pod, { + foreignKey: { + name: 'reporterPodId', + allowNull: true + }, + onDelete: 'cascade' + }) + + VideoAbuse.belongsTo(models.Video, { + foreignKey: { + name: 'videoId', + allowNull: false + }, + onDelete: 'cascade' + }) +} + +listForApi = function (start, count, sort, callback) { + const query = { + offset: start, + limit: count, + order: [ getSort(sort) ], + include: [ + { + model: VideoAbuse['sequelize'].models.Pod, + required: false + } + ] + } + + return VideoAbuse.findAndCountAll(query).asCallback(function (err, result) { + if (err) return callback(err) + + return callback(null, result.rows, result.count) + }) +} + + diff --git a/server/models/video-blacklist-interface.ts b/server/models/video-blacklist-interface.ts new file mode 100644 index 000000000..ae2cd6748 --- /dev/null +++ b/server/models/video-blacklist-interface.ts @@ -0,0 +1,31 @@ +import * as Sequelize from 'sequelize' + +export namespace BlacklistedVideoMethods { + export type ToFormatedJSON = () => 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 interface BlacklistedVideoClass { + toFormatedJSON: BlacklistedVideoMethods.ToFormatedJSON + countTotal: BlacklistedVideoMethods.CountTotal + list: BlacklistedVideoMethods.List + listForApi: BlacklistedVideoMethods.ListForApi + loadById: BlacklistedVideoMethods.LoadById + loadByVideoId: BlacklistedVideoMethods.LoadByVideoId +} + +export interface BlacklistedVideoAttributes { +} + +export interface BlacklistedVideoInstance extends BlacklistedVideoClass, BlacklistedVideoAttributes, Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface BlacklistedVideoModel extends BlacklistedVideoClass, Sequelize.Model {} diff --git a/server/models/video-blacklist.ts b/server/models/video-blacklist.ts index 1f00702c7..fe72d5d46 100644 --- a/server/models/video-blacklist.ts +++ b/server/models/video-blacklist.ts @@ -1,9 +1,24 @@ -import { getSort } from './utils' +import * as Sequelize from 'sequelize' -// --------------------------------------------------------------------------- +import { addMethodsToModel, getSort } from './utils' +import { + BlacklistedVideoClass, + BlacklistedVideoInstance, + BlacklistedVideoAttributes, -module.exports = function (sequelize, DataTypes) { - const BlacklistedVideo = sequelize.define('BlacklistedVideo', + BlacklistedVideoMethods +} from './video-blacklist-interface' + +let BlacklistedVideo: Sequelize.Model +let toFormatedJSON: BlacklistedVideoMethods.ToFormatedJSON +let countTotal: BlacklistedVideoMethods.CountTotal +let list: BlacklistedVideoMethods.List +let listForApi: BlacklistedVideoMethods.ListForApi +let loadById: BlacklistedVideoMethods.LoadById +let loadByVideoId: BlacklistedVideoMethods.LoadByVideoId + +export default function (sequelize, DataTypes) { + BlacklistedVideo = sequelize.define('BlacklistedVideo', {}, { indexes: [ @@ -11,29 +26,30 @@ module.exports = function (sequelize, DataTypes) { fields: [ 'videoId' ], unique: true } - ], - classMethods: { - associate, - - countTotal, - list, - listForApi, - loadById, - loadByVideoId - }, - instanceMethods: { - toFormatedJSON - }, - hooks: {} + ] } ) + const classMethods = [ + associate, + + countTotal, + list, + listForApi, + loadById, + loadByVideoId + ] + const instanceMethods = [ + toFormatedJSON + ] + addMethodsToModel(BlacklistedVideo, classMethods, instanceMethods) + return BlacklistedVideo } // ------------------------------ METHODS ------------------------------ -function toFormatedJSON () { +toFormatedJSON = function () { return { id: this.id, videoId: this.videoId, @@ -44,44 +60,44 @@ function toFormatedJSON () { // ------------------------------ STATICS ------------------------------ function associate (models) { - this.belongsTo(models.Video, { + BlacklistedVideo.belongsTo(models.Video, { foreignKey: 'videoId', onDelete: 'cascade' }) } -function countTotal (callback) { - return this.count().asCallback(callback) +countTotal = function (callback) { + return BlacklistedVideo.count().asCallback(callback) } -function list (callback) { - return this.findAll().asCallback(callback) +list = function (callback) { + return BlacklistedVideo.findAll().asCallback(callback) } -function listForApi (start, count, sort, callback) { +listForApi = function (start, count, sort, callback) { const query = { offset: start, limit: count, order: [ getSort(sort) ] } - return this.findAndCountAll(query).asCallback(function (err, result) { + return BlacklistedVideo.findAndCountAll(query).asCallback(function (err, result) { if (err) return callback(err) return callback(null, result.rows, result.count) }) } -function loadById (id, callback) { - return this.findById(id).asCallback(callback) +loadById = function (id, callback) { + return BlacklistedVideo.findById(id).asCallback(callback) } -function loadByVideoId (id, callback) { +loadByVideoId = function (id, callback) { const query = { where: { videoId: id } } - return this.find(query).asCallback(callback) + return BlacklistedVideo.find(query).asCallback(callback) } diff --git a/server/models/video-interface.ts b/server/models/video-interface.ts new file mode 100644 index 000000000..b8dbeea35 --- /dev/null +++ b/server/models/video-interface.ts @@ -0,0 +1,75 @@ +import * as Sequelize from 'sequelize' + +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 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 interface VideoClass { + generateMagnetUri: VideoMethods.GenerateMagnetUri + getVideoFilename: VideoMethods.GetVideoFilename + getThumbnailName: VideoMethods.GetThumbnailName + getPreviewName: VideoMethods.GetPreviewName + getTorrentName: VideoMethods.GetTorrentName + isOwned: VideoMethods.IsOwned + toFormatedJSON: VideoMethods.ToFormatedJSON + toAddRemoteJSON: VideoMethods.ToAddRemoteJSON + toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON + transcodeVideofile: VideoMethods.TranscodeVideofile + + generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData + getDurationFromFile: VideoMethods.GetDurationFromFile + list: VideoMethods.List + listForApi: VideoMethods.ListForApi + loadByHostAndRemoteId: VideoMethods.LoadByHostAndRemoteId + listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags + listOwnedByAuthor: VideoMethods.ListOwnedByAuthor + load: VideoMethods.Load + loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor + loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags + searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags +} + +export interface VideoAttributes { + name: string + extname: string + remoteId: string + category: number + licence: number + language: number + nsfw: boolean + description: string + infoHash?: string + duration: number + views?: number + likes?: number + dislikes?: number +} + +export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.Instance { + id: string + createdAt: Date + updatedAt: Date +} + +export interface VideoModel extends VideoClass, Sequelize.Model {} diff --git a/server/models/video-tag-interface.ts b/server/models/video-tag-interface.ts new file mode 100644 index 000000000..468827b8c --- /dev/null +++ b/server/models/video-tag-interface.ts @@ -0,0 +1,18 @@ +import * as Sequelize from 'sequelize' + +export namespace VideoTagMethods { +} + +export interface VideoTagClass { +} + +export interface VideoTagAttributes { +} + +export interface VideoTagInstance extends Sequelize.Instance { + id: number + createdAt: Date + updatedAt: Date +} + +export interface VideoTagModel extends VideoTagClass, Sequelize.Model {} diff --git a/server/models/video-tag.ts b/server/models/video-tag.ts index 83ff6053f..2ccaf820d 100644 --- a/server/models/video-tag.ts +++ b/server/models/video-tag.ts @@ -1,5 +1,18 @@ -module.exports = function (sequelize, DataTypes) { - const VideoTag = sequelize.define('VideoTag', {}, { +import * as Sequelize from 'sequelize' + +import { addMethodsToModel } from './utils' +import { + VideoTagClass, + VideoTagInstance, + VideoTagAttributes, + + VideoTagMethods +} from './video-tag-interface' + +let VideoTag: Sequelize.Model + +export default function (sequelize, DataTypes) { + VideoTag = sequelize.define('VideoTag', {}, { indexes: [ { fields: [ 'videoId' ] diff --git a/server/models/video.ts b/server/models/video.ts index 1e29f1355..9284dfeba 100644 --- a/server/models/video.ts +++ b/server/models/video.ts @@ -8,8 +8,9 @@ import { map, values } from 'lodash' import { parallel, series } from 'async' import parseTorrent = require('parse-torrent') import { join } from 'path' +import * as Sequelize from 'sequelize' -const db = require('../initializers/database') +import { database as db } from '../initializers/database' import { logger, isVideoNameValid, @@ -32,12 +33,42 @@ import { THUMBNAILS_SIZE } from '../initializers' import { JobScheduler, removeVideoToFriends } from '../lib' -import { getSort } from './utils' -// --------------------------------------------------------------------------- +import { addMethodsToModel, getSort } from './utils' +import { + VideoClass, + VideoInstance, + VideoAttributes, -module.exports = function (sequelize, DataTypes) { - const Video = sequelize.define('Video', + VideoMethods +} from './video-interface' + +let Video: Sequelize.Model +let generateMagnetUri: VideoMethods.GenerateMagnetUri +let getVideoFilename: VideoMethods.GetVideoFilename +let getThumbnailName: VideoMethods.GetThumbnailName +let getPreviewName: VideoMethods.GetPreviewName +let getTorrentName: VideoMethods.GetTorrentName +let isOwned: VideoMethods.IsOwned +let toFormatedJSON: VideoMethods.ToFormatedJSON +let toAddRemoteJSON: VideoMethods.ToAddRemoteJSON +let toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON +let transcodeVideofile: VideoMethods.TranscodeVideofile + +let generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData +let getDurationFromFile: VideoMethods.GetDurationFromFile +let list: VideoMethods.List +let listForApi: VideoMethods.ListForApi +let loadByHostAndRemoteId: VideoMethods.LoadByHostAndRemoteId +let listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags +let listOwnedByAuthor: VideoMethods.ListOwnedByAuthor +let load: VideoMethods.Load +let loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor +let loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags +let searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags + +export default function (sequelize, DataTypes) { + Video = sequelize.define('Video', { id: { type: DataTypes.UUID, @@ -194,34 +225,6 @@ module.exports = function (sequelize, DataTypes) { fields: [ 'likes' ] } ], - classMethods: { - associate, - - generateThumbnailFromData, - getDurationFromFile, - list, - listForApi, - listOwnedAndPopulateAuthorAndTags, - listOwnedByAuthor, - load, - loadByHostAndRemoteId, - loadAndPopulateAuthor, - loadAndPopulateAuthorAndPodAndTags, - searchAndPopulateAuthorAndPodAndTags - }, - instanceMethods: { - generateMagnetUri, - getVideoFilename, - getThumbnailName, - getPreviewName, - getTorrentName, - isOwned, - toFormatedJSON, - toAddRemoteJSON, - toUpdateRemoteJSON, - transcodeVideofile, - removeFromBlacklist - }, hooks: { beforeValidate, beforeCreate, @@ -230,99 +233,139 @@ module.exports = function (sequelize, DataTypes) { } ) + const classMethods = [ + associate, + + generateThumbnailFromData, + getDurationFromFile, + list, + listForApi, + listOwnedAndPopulateAuthorAndTags, + listOwnedByAuthor, + load, + loadByHostAndRemoteId, + loadAndPopulateAuthor, + loadAndPopulateAuthorAndPodAndTags, + searchAndPopulateAuthorAndPodAndTags + ] + const instanceMethods = [ + generateMagnetUri, + getVideoFilename, + getThumbnailName, + getPreviewName, + getTorrentName, + isOwned, + toFormatedJSON, + toAddRemoteJSON, + toUpdateRemoteJSON, + transcodeVideofile, + removeFromBlacklist + ] + addMethodsToModel(Video, classMethods, instanceMethods) + return Video } -function beforeValidate (video, options, next) { +function beforeValidate (video, options) { // Put a fake infoHash if it does not exists yet if (video.isOwned() && !video.infoHash) { // 40 hexa length video.infoHash = '0123456789abcdef0123456789abcdef01234567' } - - return next(null) } -function beforeCreate (video, options, next) { - const tasks = [] +function beforeCreate (video, options) { + return new Promise(function (resolve, reject) { + const tasks = [] - if (video.isOwned()) { - const videoPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename()) + if (video.isOwned()) { + const videoPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename()) + + tasks.push( + function createVideoTorrent (callback) { + createTorrentFromVideo(video, videoPath, callback) + }, + + function createVideoThumbnail (callback) { + createThumbnail(video, videoPath, callback) + }, + + function createVideoPreview (callback) { + createPreview(video, videoPath, callback) + } + ) + + if (CONFIG.TRANSCODING.ENABLED === true) { + tasks.push( + function createVideoTranscoderJob (callback) { + const dataInput = { + id: video.id + } + + JobScheduler.Instance.createJob(options.transaction, 'videoTranscoder', dataInput, callback) + } + ) + } + + return parallel(tasks, function (err) { + if (err) return reject(err) + + return resolve() + }) + } + + return resolve() + }) +} + +function afterDestroy (video, options) { + return new Promise(function (resolve, reject) { + const tasks = [] tasks.push( - function createVideoTorrent (callback) { - createTorrentFromVideo(video, videoPath, callback) - }, - - function createVideoThumbnail (callback) { - createThumbnail(video, videoPath, callback) - }, - - function createVideoPreview (callback) { - createPreview(video, videoPath, callback) + function (callback) { + removeThumbnail(video, callback) } ) - if (CONFIG.TRANSCODING.ENABLED === true) { + if (video.isOwned()) { tasks.push( - function createVideoTranscoderJob (callback) { - const dataInput = { - id: video.id + function removeVideoFile (callback) { + removeFile(video, callback) + }, + + function removeVideoTorrent (callback) { + removeTorrent(video, callback) + }, + + function removeVideoPreview (callback) { + removePreview(video, callback) + }, + + function notifyFriends (callback) { + const params = { + remoteId: video.id } - JobScheduler.Instance.createJob(options.transaction, 'videoTranscoder', dataInput, callback) + removeVideoToFriends(params) + + return callback() } ) } - return parallel(tasks, next) - } + parallel(tasks, function (err) { + if (err) return reject(err) - return next() -} - -function afterDestroy (video, options, next) { - const tasks = [] - - tasks.push( - function (callback) { - removeThumbnail(video, callback) - } - ) - - if (video.isOwned()) { - tasks.push( - function removeVideoFile (callback) { - removeFile(video, callback) - }, - - function removeVideoTorrent (callback) { - removeTorrent(video, callback) - }, - - function removeVideoPreview (callback) { - removePreview(video, callback) - }, - - function removeVideoToFriends (callback) { - const params = { - remoteId: video.id - } - - removeVideoToFriends(params) - - return callback() - } - ) - } - - parallel(tasks, next) + return resolve() + }) + }) } // ------------------------------ METHODS ------------------------------ function associate (models) { - this.belongsTo(models.Author, { + Video.belongsTo(models.Author, { foreignKey: { name: 'authorId', allowNull: false @@ -330,13 +373,13 @@ function associate (models) { onDelete: 'cascade' }) - this.belongsToMany(models.Tag, { + Video.belongsToMany(models.Tag, { foreignKey: 'videoId', through: models.VideoTag, onDelete: 'cascade' }) - this.hasMany(models.VideoAbuse, { + Video.hasMany(models.VideoAbuse, { foreignKey: { name: 'videoId', allowNull: false @@ -345,7 +388,7 @@ function associate (models) { }) } -function generateMagnetUri () { +generateMagnetUri = function () { let baseUrlHttp let baseUrlWs @@ -372,18 +415,18 @@ function generateMagnetUri () { return magnetUtil.encode(magnetHash) } -function getVideoFilename () { +getVideoFilename = function () { if (this.isOwned()) return this.id + this.extname return this.remoteId + this.extname } -function getThumbnailName () { +getThumbnailName = function () { // We always have a copy of the thumbnail return this.id + '.jpg' } -function getPreviewName () { +getPreviewName = function () { const extension = '.jpg' if (this.isOwned()) return this.id + extension @@ -391,7 +434,7 @@ function getPreviewName () { return this.remoteId + extension } -function getTorrentName () { +getTorrentName = function () { const extension = '.torrent' if (this.isOwned()) return this.id + extension @@ -399,11 +442,11 @@ function getTorrentName () { return this.remoteId + extension } -function isOwned () { +isOwned = function () { return this.remoteId === null } -function toFormatedJSON () { +toFormatedJSON = function () { let podHost if (this.Author.Pod) { @@ -453,43 +496,41 @@ function toFormatedJSON () { return json } -function toAddRemoteJSON (callback) { - const self = this - +toAddRemoteJSON = function (callback) { // Get thumbnail data to send to the other pod const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName()) - fs.readFile(thumbnailPath, function (err, thumbnailData) { + fs.readFile(thumbnailPath, (err, thumbnailData) => { if (err) { logger.error('Cannot read the thumbnail of the video') return callback(err) } const remoteVideo = { - name: self.name, - category: self.category, - licence: self.licence, - language: self.language, - nsfw: self.nsfw, - description: self.description, - infoHash: self.infoHash, - remoteId: self.id, - author: self.Author.name, - duration: self.duration, + name: this.name, + category: this.category, + licence: this.licence, + language: this.language, + nsfw: this.nsfw, + description: this.description, + infoHash: this.infoHash, + remoteId: this.id, + author: this.Author.name, + duration: this.duration, thumbnailData: thumbnailData.toString('binary'), - tags: map(self.Tags, 'name'), - createdAt: self.createdAt, - updatedAt: self.updatedAt, - extname: self.extname, - views: self.views, - likes: self.likes, - dislikes: self.dislikes + tags: map(this.Tags, 'name'), + createdAt: this.createdAt, + updatedAt: this.updatedAt, + extname: this.extname, + views: this.views, + likes: this.likes, + dislikes: this.dislikes } return callback(null, remoteVideo) }) } -function toUpdateRemoteJSON (callback) { +toUpdateRemoteJSON = function (callback) { const json = { name: this.name, category: this.category, @@ -513,7 +554,7 @@ function toUpdateRemoteJSON (callback) { return json } -function transcodeVideofile (finalCallback) { +transcodeVideofile = function (finalCallback) { const video = this const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR @@ -568,7 +609,7 @@ function transcodeVideofile (finalCallback) { // ------------------------------ STATICS ------------------------------ -function generateThumbnailFromData (video, thumbnailData, callback) { +generateThumbnailFromData = function (video, thumbnailData, callback) { // Creating the thumbnail for a remote video const thumbnailName = video.getThumbnailName() @@ -580,7 +621,7 @@ function generateThumbnailFromData (video, thumbnailData, callback) { }) } -function getDurationFromFile (videoPath, callback) { +getDurationFromFile = function (videoPath, callback) { ffmpeg.ffprobe(videoPath, function (err, metadata) { if (err) return callback(err) @@ -588,46 +629,46 @@ function getDurationFromFile (videoPath, callback) { }) } -function list (callback) { - return this.findAll().asCallback(callback) +list = function (callback) { + return Video.findAll().asCallback(callback) } -function listForApi (start, count, sort, callback) { +listForApi = function (start, count, sort, callback) { // Exclude Blakclisted videos from the list const query = { + distinct: true, offset: start, limit: count, - distinct: true, // For the count, a video can have many tags - order: [ getSort(sort), [ this.sequelize.models.Tag, 'name', 'ASC' ] ], + order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ], include: [ { - model: this.sequelize.models.Author, - include: [ { model: this.sequelize.models.Pod, required: false } ] + model: Video['sequelize'].models.Author, + include: [ { model: Video['sequelize'].models.Pod, required: false } ] }, - this.sequelize.models.Tag + Video['sequelize'].models.Tag ], - where: createBaseVideosWhere.call(this) + where: createBaseVideosWhere() } - return this.findAndCountAll(query).asCallback(function (err, result) { + return Video.findAndCountAll(query).asCallback(function (err, result) { if (err) return callback(err) return callback(null, result.rows, result.count) }) } -function loadByHostAndRemoteId (fromHost, remoteId, callback) { +loadByHostAndRemoteId = function (fromHost, remoteId, callback) { const query = { where: { remoteId: remoteId }, include: [ { - model: this.sequelize.models.Author, + model: Video['sequelize'].models.Author, include: [ { - model: this.sequelize.models.Pod, + model: Video['sequelize'].models.Pod, required: true, where: { host: fromHost @@ -638,29 +679,29 @@ function loadByHostAndRemoteId (fromHost, remoteId, callback) { ] } - return this.findOne(query).asCallback(callback) + return Video.findOne(query).asCallback(callback) } -function listOwnedAndPopulateAuthorAndTags (callback) { +listOwnedAndPopulateAuthorAndTags = function (callback) { // If remoteId is null this is *our* video const query = { where: { remoteId: null }, - include: [ this.sequelize.models.Author, this.sequelize.models.Tag ] + include: [ Video['sequelize'].models.Author, Video['sequelize'].models.Tag ] } - return this.findAll(query).asCallback(callback) + return Video.findAll(query).asCallback(callback) } -function listOwnedByAuthor (author, callback) { +listOwnedByAuthor = function (author, callback) { const query = { where: { remoteId: null }, include: [ { - model: this.sequelize.models.Author, + model: Video['sequelize'].models.Author, where: { name: author } @@ -668,58 +709,58 @@ function listOwnedByAuthor (author, callback) { ] } - return this.findAll(query).asCallback(callback) + return Video.findAll(query).asCallback(callback) } -function load (id, callback) { - return this.findById(id).asCallback(callback) +load = function (id, callback) { + return Video.findById(id).asCallback(callback) } -function loadAndPopulateAuthor (id, callback) { +loadAndPopulateAuthor = function (id, callback) { const options = { - include: [ this.sequelize.models.Author ] + include: [ Video['sequelize'].models.Author ] } - return this.findById(id, options).asCallback(callback) + return Video.findById(id, options).asCallback(callback) } -function loadAndPopulateAuthorAndPodAndTags (id, callback) { +loadAndPopulateAuthorAndPodAndTags = function (id, callback) { const options = { include: [ { - model: this.sequelize.models.Author, - include: [ { model: this.sequelize.models.Pod, required: false } ] + model: Video['sequelize'].models.Author, + include: [ { model: Video['sequelize'].models.Pod, required: false } ] }, - this.sequelize.models.Tag + Video['sequelize'].models.Tag ] } - return this.findById(id, options).asCallback(callback) + return Video.findById(id, options).asCallback(callback) } -function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, callback) { +searchAndPopulateAuthorAndPodAndTags = function (value, field, start, count, sort, callback) { const podInclude: any = { - model: this.sequelize.models.Pod, + model: Video['sequelize'].models.Pod, required: false } const authorInclude: any = { - model: this.sequelize.models.Author, + model: Video['sequelize'].models.Author, include: [ podInclude ] } const tagInclude: any = { - model: this.sequelize.models.Tag + model: Video['sequelize'].models.Tag } const query: any = { - where: createBaseVideosWhere.call(this), + distinct: true, + where: createBaseVideosWhere(), offset: start, limit: count, - distinct: true, // For the count, a video can have many tags - order: [ getSort(sort), [ this.sequelize.models.Tag, 'name', 'ASC' ] ] + order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ] } // Make an exact search with the magnet @@ -727,8 +768,8 @@ function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, const infoHash = magnetUtil.decode(value).infoHash query.where.infoHash = infoHash } else if (field === 'tags') { - const escapedValue = this.sequelize.escape('%' + value + '%') - query.where.id.$in = this.sequelize.literal( + const escapedValue = Video['sequelize'].escape('%' + value + '%') + query.where.id.$in = Video['sequelize'].literal( '(SELECT "VideoTags"."videoId" FROM "Tags" INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" WHERE name LIKE ' + escapedValue + ')' ) } else if (field === 'host') { @@ -758,10 +799,10 @@ function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, ] if (tagInclude.where) { - // query.include.push([ this.sequelize.models.Tag ]) + // query.include.push([ Video['sequelize'].models.Tag ]) } - return this.findAndCountAll(query).asCallback(function (err, result) { + return Video.findAndCountAll(query).asCallback(function (err, result) { if (err) return callback(err) return callback(null, result.rows, result.count) @@ -773,7 +814,7 @@ function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, function createBaseVideosWhere () { return { id: { - $notIn: this.sequelize.literal( + $notIn: Video['sequelize'].literal( '(SELECT "BlacklistedVideos"."videoId" FROM "BlacklistedVideos")' ) } diff --git a/server/tests/api/video-transcoder.js b/server/tests/api/video-transcoder.js index 3ff7b230a..c0b597668 100644 --- a/server/tests/api/video-transcoder.js +++ b/server/tests/api/video-transcoder.js @@ -12,7 +12,7 @@ const loginUtils = require('../utils/login') const serversUtils = require('../utils/servers') const videosUtils = require('../utils/videos') -describe('Test video blacklists', function () { +describe('Test video transcoding', function () { let servers = [] before(function (done) { diff --git a/server/tests/utils/servers.js b/server/tests/utils/servers.js index afb08e6fc..c753c1f1d 100644 --- a/server/tests/utils/servers.js +++ b/server/tests/utils/servers.js @@ -82,7 +82,7 @@ function runServer (number, callback) { detached: true } - server.app = fork(pathUtils.join(__dirname, '..', '..', '..', 'server.js'), [], options) + server.app = fork(pathUtils.join(__dirname, '..', '..', '..', 'dist', 'server.js'), [], options) server.app.stdout.on('data', function onStdout (data) { let dontContinue = false diff --git a/yarn.lock b/yarn.lock index c0ce443b3..857aa92e6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26,8 +26,8 @@ resolved "https://registry.yarnpkg.com/@types/config/-/config-0.0.32.tgz#c106055802d78e234e28374adc4dad460d098558" "@types/express-serve-static-core@*": - version "4.0.44" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.0.44.tgz#a1c3bd5d80e93c72fba91a03f5412c47f21d4ae7" + version "4.0.45" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.0.45.tgz#71bb1f87d7187482d0d8851f5b294458e1c78667" dependencies: "@types/node" "*" @@ -67,8 +67,8 @@ "@types/express" "*" "@types/node@*", "@types/node@^7.0.18": - version "7.0.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.18.tgz#cd67f27d3dc0cfb746f0bdd5e086c4c5d55be173" + version "7.0.22" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.22.tgz#4593f4d828bdd612929478ea40c67b4f403ca255" "@types/request@^0.0.43": version "0.0.43" @@ -77,9 +77,9 @@ "@types/form-data" "*" "@types/node" "*" -"@types/sequelize@3": - version "3.4.48" - resolved "https://registry.yarnpkg.com/@types/sequelize/-/sequelize-3.4.48.tgz#f88fac7cc4717d2e87f20f69ebb64aa869e7e4d1" +"@types/sequelize@^4.0.55": + version "4.0.55" + resolved "https://registry.yarnpkg.com/@types/sequelize/-/sequelize-4.0.55.tgz#957335a9de537f17ed9c9e16c088cc147b8805af" dependencies: "@types/bluebird" "*" "@types/lodash" "*" @@ -142,8 +142,8 @@ ajv-keywords@^1.0.0: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" ajv@^4.7.0, ajv@^4.9.1: - version "4.11.7" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.7.tgz#8655a5d86d0824985cc471a1d913fb6729a0ec48" + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" @@ -243,8 +243,8 @@ assertion-error@^1.0.1: resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" async@>=0.2.9, async@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9" + version "2.4.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7" dependencies: lodash "^4.14.0" @@ -381,8 +381,8 @@ bittorrent-tracker@^9.0.0: bufferutil "^3.0.0" bl@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.0.tgz#1397e7ec42c5f5dc387470c500e34a9f6be9ea98" + version "1.2.1" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" dependencies: readable-stream "^2.0.5" @@ -408,7 +408,7 @@ bluebird@^2.10.0, bluebird@^2.9.13: version "2.11.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" -bluebird@^3.0.5, bluebird@^3.3.4, bluebird@^3.4.0, bluebird@^3.4.6: +bluebird@^3.0.5, bluebird@^3.4.0, bluebird@^3.4.6: version "3.5.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" @@ -417,19 +417,19 @@ bn.js@^4.4.0: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" body-parser@^1.12.4: - version "1.17.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" + version "1.17.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.2.tgz#f8892abc8f9e627d42aedafbca66bf5ab99104ee" dependencies: bytes "2.4.0" content-type "~1.0.2" - debug "2.6.1" + debug "2.6.7" depd "~1.1.0" http-errors "~1.6.1" iconv-lite "0.4.15" on-finished "~2.3.0" qs "6.4.0" raw-body "~2.2.0" - type-is "~1.6.14" + type-is "~1.6.15" boom@2.x.x: version "2.10.1" @@ -437,7 +437,7 @@ boom@2.x.x: dependencies: hoek "2.x.x" -brace-expansion@^1.0.0: +brace-expansion@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" dependencies: @@ -570,6 +570,13 @@ closest-to@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/closest-to/-/closest-to-2.0.0.tgz#bb2a860edb7769b62d04821748ae50da24dbefaa" +cls-bluebird@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/cls-bluebird/-/cls-bluebird-2.0.1.tgz#c259a480ae02c0e506134307bb13db30446ee2e7" + dependencies: + is-bluebird "^1.0.2" + shimmer "^1.1.0" + co-bluebird@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/co-bluebird/-/co-bluebird-1.1.0.tgz#c8b9f3a9320a7ed30987dcca1a5c3cff59655c7c" @@ -649,10 +656,11 @@ concurrently@^3.1.0: tree-kill "^1.1.0" config@^1.14.0: - version "1.25.1" - resolved "https://registry.yarnpkg.com/config/-/config-1.25.1.tgz#72ac51cde81e2c77c6b3b66d0130dae527a19c92" + version "1.26.1" + resolved "https://registry.yarnpkg.com/config/-/config-1.26.1.tgz#f647ce32c345e80ba73a8eaa7a9a4b4e5b290ca1" dependencies: json5 "0.4.0" + os-homedir "1.0.2" console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" @@ -750,8 +758,8 @@ dashdash@^1.12.0: assert-plus "^1.0.0" date-fns@^1.23.0: - version "1.28.4" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.28.4.tgz#7938aec34ba31fc8bd134d2344bc2e0bbfd95165" + version "1.28.5" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.28.5.tgz#257cfc45d322df45ef5658665967ee841cd73faf" debug-log@^1.0.0: version "1.0.1" @@ -769,17 +777,17 @@ debug@2.6.0: dependencies: ms "0.7.2" -debug@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" +debug@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e" dependencies: - ms "0.7.2" + ms "2.0.0" -debug@2.6.4, debug@^2.0.0, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.5.2: - version "2.6.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.4.tgz#7586a9b3c39741c0282ae33445c4e8ac74734fe0" +debug@2.6.8, debug@^2.0.0, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.5.2: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" dependencies: - ms "0.7.3" + ms "2.0.0" deep-eql@^0.1.3: version "0.1.3" @@ -788,8 +796,8 @@ deep-eql@^0.1.3: type-detect "0.1.1" deep-extend@~0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" deep-is@~0.1.3: version "0.1.3" @@ -932,8 +940,8 @@ es-to-primitive@^1.1.1: is-symbol "^1.0.1" es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.15" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6" + version "0.10.21" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.21.tgz#19a725f9e51d0300bbc1e8e821109fd9daf55925" dependencies: es6-iterator "2" es6-symbol "~3.1" @@ -1107,8 +1115,8 @@ eslint@~3.19.0: user-home "^2.0.0" espree@^3.4.0: - version "3.4.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.2.tgz#38dbdedbedc95b8961a1fbf04734a8f6a9c8c592" + version "3.4.3" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" dependencies: acorn "^5.0.1" acorn-jsx "^3.0.0" @@ -1185,8 +1193,8 @@ express-validator@^3.1.0: validator "~6.2.0" express@^4.12.4, express@^4.13.3: - version "4.15.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" + version "4.15.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662" dependencies: accepts "~1.3.3" array-flatten "1.1.1" @@ -1194,32 +1202,32 @@ express@^4.12.4, express@^4.13.3: content-type "~1.0.2" cookie "0.3.1" cookie-signature "1.0.6" - debug "2.6.1" + debug "2.6.7" depd "~1.1.0" encodeurl "~1.0.1" escape-html "~1.0.3" etag "~1.8.0" - finalhandler "~1.0.0" + finalhandler "~1.0.3" fresh "0.5.0" merge-descriptors "1.0.1" methods "~1.1.2" on-finished "~2.3.0" parseurl "~1.3.1" path-to-regexp "0.1.7" - proxy-addr "~1.1.3" + proxy-addr "~1.1.4" qs "6.4.0" range-parser "~1.2.0" - send "0.15.1" - serve-static "1.12.1" + send "0.15.3" + serve-static "1.12.3" setprototypeof "1.0.3" statuses "~1.3.1" - type-is "~1.6.14" + type-is "~1.6.15" utils-merge "1.0.0" - vary "~1.1.0" + vary "~1.1.1" extend@^3.0.0, extend@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" extsprintf@1.0.2: version "1.0.2" @@ -1256,11 +1264,11 @@ filestream@^4.0.0: typedarray-to-buffer "^3.0.0" xtend "^4.0.1" -finalhandler@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.2.tgz#d0e36f9dbc557f2de14423df6261889e9d60c93a" +finalhandler@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89" dependencies: - debug "2.6.4" + debug "2.6.7" encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" @@ -1285,12 +1293,6 @@ find-up@^2.0.0: dependencies: locate-path "^2.0.0" -findup-sync@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.3.0.tgz#37930aa5d816b777c03445e1966cc6790a4c0b16" - dependencies: - glob "~5.0.0" - flat-cache@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" @@ -1375,7 +1377,7 @@ function-bind@^1.0.2, function-bind@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" -gauge@~2.7.1: +gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: @@ -1424,7 +1426,7 @@ github-from-package@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" -glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1: +glob@7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: @@ -1435,13 +1437,14 @@ glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@~5.0.0: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: + fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "2 || 3" + minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" @@ -1544,8 +1547,8 @@ iconv-lite@0.4.15: resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" ignore@^3.0.11, ignore@^3.0.9, ignore@^3.2.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.7.tgz#4810ca5f1d8eca5595213a34b94f2eb4ed926bbd" + version "3.3.3" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" immediate-chunk-store@^1.0.8: version "1.0.8" @@ -1555,9 +1558,9 @@ imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" -inflection@^1.6.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" +inflection@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.10.0.tgz#5bffcb1197ad3e81050f8e17e21668087ee9eb2f" inflight@^1.0.4: version "1.0.6" @@ -1618,6 +1621,10 @@ is-ascii@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-ascii/-/is-ascii-1.0.0.tgz#f02ad0259a0921cd199ff21ce1b09e0f6b4e3929" +is-bluebird@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-bluebird/-/is-bluebird-1.0.2.tgz#096439060f4aa411abee19143a84d6a55346d6e2" + is-callable@^1.1.1, is-callable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" @@ -1694,8 +1701,8 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" is-windows@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.0.tgz#c61d61020c3ebe99261b781bd3d1622395f547f8" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9" isarray@0.0.1: version "0.0.1" @@ -1724,8 +1731,8 @@ js-tokens@^3.0.0: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" js-yaml@^3.5.1, js-yaml@^3.5.4: - version "3.8.3" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.3.tgz#33a05ec481c850c8875929166fe1beb61c728766" + version "3.8.4" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" dependencies: argparse "^1.0.7" esprima "^3.1.1" @@ -1887,9 +1894,9 @@ lodash.keys@^3.0.0: lodash.isarguments "^3.0.0" lodash.isarray "^3.0.0" -lodash@4.12.0: - version "4.12.0" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.12.0.tgz#2bd6dc46a040f59e686c972ed21d93dc59053258" +lodash@4.15.0: + version "4.15.0" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.15.0.tgz#3162391d8f0140aa22cf8f6b3c34d6b7f63d3aa9" lodash@^3.3.1: version "3.10.1" @@ -1959,15 +1966,19 @@ mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: dependencies: mime-db "~1.27.0" -mime@1.3.4, mime@^1.3.4: +mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" +mime@^1.3.4: + version "1.3.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" + +minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: - brace-expansion "^1.0.0" + brace-expansion "^1.1.7" minimist@0.0.8, minimist@~0.0.1: version "0.0.8" @@ -1984,8 +1995,8 @@ mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: minimist "0.0.8" mocha@^3.0.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.3.0.tgz#d29b7428d3f52c82e2e65df1ecb7064e1aabbfb5" + version "3.4.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.4.2.tgz#d0ef4d332126dbf18d0d640c9b382dd48be97594" dependencies: browser-stdout "1.3.0" commander "2.9.0" @@ -2010,11 +2021,11 @@ moment-timezone@^0.5.4: resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" morgan@^1.5.3: - version "1.8.1" - resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.8.1.tgz#f93023d3887bd27b78dfd6023cea7892ee27a4b1" + version "1.8.2" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.8.2.tgz#784ac7734e4a453a9c6e6e8680a9329275c8b687" dependencies: basic-auth "~1.1.0" - debug "2.6.1" + debug "2.6.8" depd "~1.1.0" on-finished "~2.3.0" on-headers "~1.0.1" @@ -2042,9 +2053,9 @@ ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" -ms@0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" multer@^1.1.0: version "1.3.0" @@ -2091,8 +2102,8 @@ next-event@^1.0.0: resolved "https://registry.yarnpkg.com/next-event/-/next-event-1.0.0.tgz#e7778acde2e55802e0ad1879c39cf6f75eda61d8" node-abi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.0.0.tgz#443bfd151b599231028ae425e592e76cd31cb537" + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.0.2.tgz#00f3e0a58100eb480133b48c99a32cc1f9e6c93e" node-pre-gyp@0.6.32: version "0.6.32" @@ -2108,6 +2119,10 @@ node-pre-gyp@0.6.32: tar "~2.2.1" tar-pack "~3.3.0" +node-uuid@~1.4.4: + version "1.4.8" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" + noop-logger@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" @@ -2119,12 +2134,12 @@ nopt@~3.0.6: abbrev "1" npmlog@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + version "4.1.0" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" - gauge "~2.7.1" + gauge "~2.7.3" set-blocking "~2.0.0" number-is-nan@^1.0.0: @@ -2220,7 +2235,7 @@ optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -os-homedir@^1.0.0, os-homedir@^1.0.1: +os-homedir@1.0.2, os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -2240,9 +2255,9 @@ package-json-versionify@^1.0.2: dependencies: browserify-package-json "^1.0.0" -packet-reader@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-0.2.0.tgz#819df4d010b82d5ea5671f8a1a3acf039bcd7700" +packet-reader@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-0.3.1.tgz#cd62e60af8d7fea8a705ec4ff990871c46871f27" parse-json@^2.2.0: version "2.2.0" @@ -2336,11 +2351,11 @@ pg-types@1.*: postgres-interval "~1.0.0" pg@^6.1.0: - version "6.1.5" - resolved "https://registry.yarnpkg.com/pg/-/pg-6.1.5.tgz#204fa40c1252ab7220d7cf6992886b20d77862b8" + version "6.2.3" + resolved "https://registry.yarnpkg.com/pg/-/pg-6.2.3.tgz#8988b7c69a1875a997d73b92036c42590b5f8024" dependencies: buffer-writer "1.0.1" - packet-reader "0.2.0" + packet-reader "0.3.1" pg-connection-string "0.1.3" pg-pool "1.*" pg-types "1.*" @@ -2348,8 +2363,8 @@ pg@^6.1.0: semver "4.3.2" pgpass@1.x: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.1.tgz#0de8b5bef993295d90a7e17d976f568dcd25d49f" + version "1.0.2" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.2.tgz#2a7bb41b6065b67907e91da1b07c1847c877b306" dependencies: split "^1.0.0" @@ -2461,7 +2476,7 @@ promisify-any@2.0.1: co-bluebird "^1.1.0" is-generator "^1.0.2" -proxy-addr@~1.1.3: +proxy-addr@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" dependencies: @@ -2488,8 +2503,8 @@ qs@6.4.0, qs@^6.1.0, qs@~6.4.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" random-access-file@^1.0.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-1.7.0.tgz#3746e28dc27fe24e406ac0a396ffaeef22751983" + version "1.7.2" + resolved "https://registry.yarnpkg.com/random-access-file/-/random-access-file-1.7.2.tgz#053e2e8ec7670370a8e8b10da962e45753f22dbc" dependencies: buffer-alloc-unsafe "^1.0.0" debug "^2.5.2" @@ -2690,8 +2705,8 @@ run-series@^1.0.2: resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.4.tgz#89a73ddc5e75c9ef8ab6320c0a1600d6a41179b9" rusha@^0.8.1: - version "0.8.5" - resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.5.tgz#a30ae9bd5a4e80fbc96fbe7a13232b944be24f84" + version "0.8.6" + resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.6.tgz#b264ddaa4d49a1d67300061858ba9358c4adca14" rx-lite@^3.1.2: version "3.1.2" @@ -2721,11 +2736,11 @@ semver@5.3.0, semver@^5.0.1, semver@^5.3.0, semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" -send@0.15.1: - version "0.15.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" +send@0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309" dependencies: - debug "2.6.1" + debug "2.6.7" depd "~1.1.0" destroy "~1.0.4" encodeurl "~1.0.1" @@ -2734,7 +2749,7 @@ send@0.15.1: fresh "0.5.0" http-errors "~1.6.1" mime "1.3.4" - ms "0.7.2" + ms "2.0.0" on-finished "~2.3.0" range-parser "~1.2.0" statuses "~1.3.1" @@ -2745,35 +2760,36 @@ sentence-case@^1.1.1: dependencies: lower-case "^1.1.1" -sequelize@^3.27.0: - version "3.30.4" - resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-3.30.4.tgz#bda2df1e31854b099e4149a111e9fc0a5ca1d1a4" +sequelize@4.0.0-2: + version "4.0.0-2" + resolved "https://registry.yarnpkg.com/sequelize/-/sequelize-4.0.0-2.tgz#8143f50fa00ac62ba95394f4c81bd97e7c3600d5" dependencies: - bluebird "^3.3.4" + bluebird "^3.4.6" + cls-bluebird "^2.0.1" + debug "^2.2.0" depd "^1.1.0" dottie "^1.0.0" generic-pool "2.4.2" - inflection "^1.6.0" - lodash "4.12.0" + inflection "1.10.0" + lodash "4.15.0" moment "^2.13.0" moment-timezone "^0.5.4" + node-uuid "~1.4.4" retry-as-promised "^2.0.0" semver "^5.0.1" - shimmer "1.1.0" - terraformer-wkt-parser "^1.1.0" + terraformer-wkt-parser "^1.1.2" toposort-class "^1.0.1" - uuid "^3.0.0" - validator "^5.2.0" - wkx "0.2.0" + validator "^5.6.0" + wkx "0.3.0" -serve-static@1.12.1: - version "1.12.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" +serve-static@1.12.3: + version "1.12.3" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.3.tgz#9f4ba19e2f3030c547f8af99107838ec38d5b1e2" dependencies: encodeurl "~1.0.1" escape-html "~1.0.3" parseurl "~1.3.1" - send "0.15.1" + send "0.15.3" set-blocking@~2.0.0: version "2.0.0" @@ -2801,7 +2817,7 @@ shelljs@^0.7.5: interpret "^1.0.0" rechoir "^0.6.2" -shimmer@1.1.0: +shimmer@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.1.0.tgz#97d7377137ffbbab425522e429fe0aa89a488b35" @@ -2866,6 +2882,16 @@ sntp@1.x.x: dependencies: hoek "2.x.x" +source-map-support@^0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" + dependencies: + source-map "^0.5.6" + +source-map@^0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + spawn-command@^0.0.2-1: version "0.0.2" resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" @@ -2900,8 +2926,8 @@ sshpk@^1.7.0: tweetnacl "~0.14.0" stack-trace@0.0.x: - version "0.0.9" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" standard-engine@~7.0.0: version "7.0.0" @@ -2962,7 +2988,7 @@ streamsearch@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" -string-width@^1.0.1: +string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -2989,10 +3015,10 @@ string_decoder@~0.10.x: resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" string_decoder@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667" + version "1.0.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.1.tgz#62e200f039955a6810d8df0a33ffc0f013662d98" dependencies: - buffer-shims "~1.0.0" + safe-buffer "^5.0.1" stringstream@~0.0.4: version "0.0.5" @@ -3094,8 +3120,8 @@ tar-pack@~3.3.0: uid-number "~0.0.6" tar-stream@^1.1.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.2.tgz#fbc6c6e83c1a19d4cb48c7d96171fc248effc7bf" + version "1.5.4" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.4.tgz#36549cf04ed1aee9b2a30c0143252238daf94016" dependencies: bl "^1.0.0" end-of-stream "^1.0.0" @@ -3110,7 +3136,7 @@ tar@~2.2.1: fstream "^1.0.2" inherits "2" -terraformer-wkt-parser@^1.1.0: +terraformer-wkt-parser@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/terraformer-wkt-parser/-/terraformer-wkt-parser-1.1.2.tgz#336a0c8fc82094a5aff83288f69aedecd369bf0c" dependencies: @@ -3127,8 +3153,8 @@ text-table@~0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" thenify@^3.0.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.2.1.tgz#251fd1c80aff6e5cf57cb179ab1fcb724269bd11" + version "3.3.0" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" dependencies: any-promise "^1.0.0" @@ -3182,8 +3208,8 @@ tryit@^1.0.1: resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" tslib@^1.0.0, tslib@^1.6.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.0.tgz#6e8366695f72961252b35167b0dd4fbeeafba491" + version "1.7.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" tslint-config-standard@^5.0.2: version "5.0.2" @@ -3192,31 +3218,34 @@ tslint-config-standard@^5.0.2: tslint-eslint-rules "^4.0.0" tslint-eslint-rules@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-4.0.0.tgz#4e0e59ecd5701c9a48c66ed47bdcafb1c635d27b" + version "4.1.0" + resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-4.1.0.tgz#8fee295c42f4c8078139deb16ee7b4510fd516b7" dependencies: doctrine "^0.7.2" tslib "^1.0.0" tsutils "^1.4.0" tslint@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.2.0.tgz#16a2addf20cb748385f544e9a0edab086bc34114" + version "5.3.2" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.3.2.tgz#e56459fb095a7307f103b84052174f5e3bbef6ed" dependencies: babel-code-frame "^6.22.0" colors "^1.1.2" diff "^3.2.0" - findup-sync "~0.3.0" glob "^7.1.1" optimist "~0.6.0" resolve "^1.3.2" semver "^5.3.0" tslib "^1.6.0" - tsutils "^1.8.0" + tsutils "^2.0.0" -tsutils@^1.4.0, tsutils@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.8.0.tgz#bf8118ed8e80cd5c9fc7d75728c7963d44ed2f52" +tsutils@^1.4.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-1.9.1.tgz#b9f9ab44e55af9681831d5f28d0aeeaf5c750cb0" + +tsutils@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.1.0.tgz#5be8376c929528f65b302de9e17b0004e4c1eb20" tunnel-agent@^0.4.3: version "0.4.3" @@ -3246,7 +3275,7 @@ type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" -type-is@^1.6.0, type-is@^1.6.4, type-is@~1.6.14: +type-is@^1.6.0, type-is@^1.6.4, type-is@~1.6.15: version "1.6.15" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" dependencies: @@ -3349,7 +3378,7 @@ validator.js@^1.1.1: version "1.2.3" resolved "https://registry.yarnpkg.com/validator.js/-/validator.js-1.2.3.tgz#f8e623f60e53bada54880333649970996a3446e1" -validator@^5.2.0: +validator@^5.6.0: version "5.7.0" resolved "https://registry.yarnpkg.com/validator/-/validator-5.7.0.tgz#7a87a58146b695ac486071141c0c49d67da05e5c" @@ -3357,7 +3386,7 @@ validator@~6.2.0: version "6.2.1" resolved "https://registry.yarnpkg.com/validator/-/validator-6.2.1.tgz#bc575b78d15beb2e338a665ba9530c7f409ef667" -vary@^1, vary@~1.1.0: +vary@^1, vary@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" @@ -3434,10 +3463,10 @@ which@^1.1.1, which@^1.2.9: isexe "^2.0.0" wide-align@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" dependencies: - string-width "^1.0.1" + string-width "^1.0.2" winston@^2.1.1: version "2.3.1" @@ -3450,9 +3479,9 @@ winston@^2.1.1: isstream "0.1.x" stack-trace "0.0.x" -wkx@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.2.0.tgz#76c24f16acd0cd8f93cd34aa331e0f7961256e84" +wkx@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.3.0.tgz#4f24948d879aca65e501674469855e04c2ad78dd" wordwrap@~0.0.2: version "0.0.3"