aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/initializers
diff options
context:
space:
mode:
Diffstat (limited to 'server/initializers')
-rw-r--r--server/initializers/checker.ts52
-rw-r--r--server/initializers/database.ts99
-rw-r--r--server/initializers/installer.ts75
-rw-r--r--server/initializers/migrations/0005-email-pod.ts38
-rw-r--r--server/initializers/migrations/0010-email-user.ts39
-rw-r--r--server/initializers/migrations/0015-video-views.ts13
-rw-r--r--server/initializers/migrations/0020-video-likes.ts13
-rw-r--r--server/initializers/migrations/0025-video-dislikes.ts13
-rw-r--r--server/initializers/migrations/0030-video-category.ts29
-rw-r--r--server/initializers/migrations/0035-video-licence.ts30
-rw-r--r--server/initializers/migrations/0040-video-nsfw.ts29
-rw-r--r--server/initializers/migrations/0045-user-display-nsfw.ts13
-rw-r--r--server/initializers/migrations/0050-video-language.ts13
-rw-r--r--server/initializers/migrator.ts133
14 files changed, 262 insertions, 327 deletions
diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts
index 7007f2c0b..fb69e05fc 100644
--- a/server/initializers/checker.ts
+++ b/server/initializers/checker.ts
@@ -2,6 +2,7 @@ import * as config from 'config'
2 2
3import { database as db } from './database' 3import { database as db } from './database'
4import { CONFIG } from './constants' 4import { CONFIG } from './constants'
5import { promisify0 } from '../helpers/core-utils'
5 6
6// Some checks on configuration files 7// Some checks on configuration files
7function checkConfig () { 8function checkConfig () {
@@ -35,41 +36,36 @@ function checkMissedConfig () {
35} 36}
36 37
37// Check the available codecs 38// Check the available codecs
38function checkFFmpeg (callback: (err: Error) => void) { 39function checkFFmpeg () {
39 const Ffmpeg = require('fluent-ffmpeg') 40 const Ffmpeg = require('fluent-ffmpeg')
40 41 const getAvailableCodecsPromise = promisify0(Ffmpeg.getAvailableCodecs)
41 Ffmpeg.getAvailableCodecs(function (err, codecs) { 42
42 if (err) return callback(err) 43 getAvailableCodecsPromise()
43 if (CONFIG.TRANSCODING.ENABLED === false) return callback(null) 44 .then(codecs => {
44 45 if (CONFIG.TRANSCODING.ENABLED === false) return undefined
45 const canEncode = [ 'libx264' ] 46
46 canEncode.forEach(function (codec) { 47 const canEncode = [ 'libx264' ]
47 if (codecs[codec] === undefined) { 48 canEncode.forEach(function (codec) {
48 return callback(new Error('Unknown codec ' + codec + ' in FFmpeg.')) 49 if (codecs[codec] === undefined) {
49 } 50 throw new Error('Unknown codec ' + codec + ' in FFmpeg.')
50 51 }
51 if (codecs[codec].canEncode !== true) { 52
52 return callback(new Error('Unavailable encode codec ' + codec + ' in FFmpeg')) 53 if (codecs[codec].canEncode !== true) {
53 } 54 throw new Error('Unavailable encode codec ' + codec + ' in FFmpeg')
55 }
56 })
54 }) 57 })
55
56 return callback(null)
57 })
58} 58}
59 59
60function clientsExist (callback: (err: Error, clientsExist?: boolean) => void) { 60function clientsExist () {
61 db.OAuthClient.countTotal(function (err, totalClients) { 61 return db.OAuthClient.countTotal().then(totalClients => {
62 if (err) return callback(err) 62 return totalClients !== 0
63
64 return callback(null, totalClients !== 0)
65 }) 63 })
66} 64}
67 65
68function usersExist (callback: (err: Error, usersExist?: boolean) => void) { 66function usersExist () {
69 db.User.countTotal(function (err, totalUsers) { 67 return db.User.countTotal().then(totalUsers => {
70 if (err) return callback(err) 68 return totalUsers !== 0
71
72 return callback(null, totalUsers !== 0)
73 }) 69 })
74} 70}
75 71
diff --git a/server/initializers/database.ts b/server/initializers/database.ts
index 705dec6da..6e3a8d009 100644
--- a/server/initializers/database.ts
+++ b/server/initializers/database.ts
@@ -1,12 +1,12 @@
1import * as fs from 'fs'
2import { join } from 'path' 1import { join } from 'path'
2import { flattenDepth } from 'lodash'
3import * as Sequelize from 'sequelize' 3import * as Sequelize from 'sequelize'
4import { each } from 'async' 4import * as Promise from 'bluebird'
5 5
6import { CONFIG } from './constants' 6import { CONFIG } from './constants'
7// Do not use barrel, we need to load database first 7// Do not use barrel, we need to load database first
8import { logger } from '../helpers/logger' 8import { logger } from '../helpers/logger'
9import { isTestInstance } from '../helpers/core-utils' 9import { isTestInstance, readdirPromise } from '../helpers/core-utils'
10import { 10import {
11 ApplicationModel, 11 ApplicationModel,
12 AuthorModel, 12 AuthorModel,
@@ -33,7 +33,7 @@ const password = CONFIG.DATABASE.PASSWORD
33 33
34const database: { 34const database: {
35 sequelize?: Sequelize.Sequelize, 35 sequelize?: Sequelize.Sequelize,
36 init?: (silent: any, callback: any) => void, 36 init?: (silent: boolean) => Promise<void>,
37 37
38 Application?: ApplicationModel, 38 Application?: ApplicationModel,
39 Author?: AuthorModel, 39 Author?: AuthorModel,
@@ -72,19 +72,17 @@ const sequelize = new Sequelize(dbname, username, password, {
72 72
73database.sequelize = sequelize 73database.sequelize = sequelize
74 74
75database.init = function (silent: boolean, callback: (err: Error) => void) { 75database.init = function (silent: boolean) {
76 const modelDirectory = join(__dirname, '..', 'models') 76 const modelDirectory = join(__dirname, '..', 'models')
77 77
78 getModelFiles(modelDirectory, function (err, filePaths) { 78 return getModelFiles(modelDirectory).then(filePaths => {
79 if (err) throw err 79 filePaths.forEach(filePath => {
80
81 filePaths.forEach(function (filePath) {
82 const model = sequelize.import(filePath) 80 const model = sequelize.import(filePath)
83 81
84 database[model['name']] = model 82 database[model['name']] = model
85 }) 83 })
86 84
87 Object.keys(database).forEach(function (modelName) { 85 Object.keys(database).forEach(modelName => {
88 if ('associate' in database[modelName]) { 86 if ('associate' in database[modelName]) {
89 database[modelName].associate(database) 87 database[modelName].associate(database)
90 } 88 }
@@ -92,7 +90,7 @@ database.init = function (silent: boolean, callback: (err: Error) => void) {
92 90
93 if (!silent) logger.info('Database %s is ready.', dbname) 91 if (!silent) logger.info('Database %s is ready.', dbname)
94 92
95 return callback(null) 93 return undefined
96 }) 94 })
97} 95}
98 96
@@ -104,49 +102,50 @@ export {
104 102
105// --------------------------------------------------------------------------- 103// ---------------------------------------------------------------------------
106 104
107function getModelFiles (modelDirectory: string, callback: (err: Error, filePaths: string[]) => void) { 105function getModelFiles (modelDirectory: string) {
108 fs.readdir(modelDirectory, function (err, files) { 106 return readdirPromise(modelDirectory)
109 if (err) throw err 107 .then(files => {
110 108 const directories: string[] = files.filter(function (directory) {
111 const directories = files.filter(function (directory) { 109 // Find directories
112 // Find directories 110 if (
113 if ( 111 directory.endsWith('.js.map') ||
114 directory.endsWith('.js.map') || 112 directory === 'index.js' || directory === 'index.ts' ||
115 directory === 'index.js' || directory === 'index.ts' || 113 directory === 'utils.js' || directory === 'utils.ts'
116 directory === 'utils.js' || directory === 'utils.ts' 114 ) return false
117 ) return false 115
116 return true
117 })
118 118
119 return true 119 return directories
120 }) 120 })
121 121 .then(directories => {
122 let modelFilePaths: string[] = [] 122 const tasks = []
123 123
124 // For each directory we read it and append model in the modelFilePaths array 124 // For each directory we read it and append model in the modelFilePaths array
125 each(directories, function (directory: string, eachCallback: ErrorCallback<Error>) { 125 directories.forEach(directory => {
126 const modelDirectoryPath = join(modelDirectory, directory) 126 const modelDirectoryPath = join(modelDirectory, directory)
127 127
128 fs.readdir(modelDirectoryPath, function (err, files) { 128 const promise = readdirPromise(modelDirectoryPath).then(files => {
129 if (err) return eachCallback(err) 129 const filteredFiles = files.filter(file => {
130 130 if (
131 const filteredFiles = files.filter(file => { 131 file === 'index.js' || file === 'index.ts' ||
132 if ( 132 file === 'utils.js' || file === 'utils.ts' ||
133 file === 'index.js' || file === 'index.ts' || 133 file.endsWith('-interface.js') || file.endsWith('-interface.ts') ||
134 file === 'utils.js' || file === 'utils.ts' || 134 file.endsWith('.js.map')
135 file.endsWith('-interface.js') || file.endsWith('-interface.ts') || 135 ) return false
136 file.endsWith('.js.map') 136
137 ) return false 137 return true
138 138 }).map(file => join(modelDirectoryPath, file))
139 return true 139
140 }).map(file => { 140 return filteredFiles
141 return join(modelDirectoryPath, file)
142 }) 141 })
143 142
144 modelFilePaths = modelFilePaths.concat(filteredFiles) 143 tasks.push(promise)
145
146 return eachCallback(null)
147 }) 144 })
148 }, function (err: Error) { 145
149 return callback(err, modelFilePaths) 146 return Promise.all(tasks)
147 })
148 .then((filteredFiles: string[][]) => {
149 return flattenDepth<string>(filteredFiles, 1)
150 }) 150 })
151 })
152} 151}
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts
index f105c8292..1ec24c4ad 100644
--- a/server/initializers/installer.ts
+++ b/server/initializers/installer.ts
@@ -1,37 +1,19 @@
1import { join } from 'path' 1import { join } from 'path'
2import * as config from 'config' 2import * as config from 'config'
3import { each, series } from 'async'
4import * as mkdirp from 'mkdirp'
5import * as passwordGenerator from 'password-generator' 3import * as passwordGenerator from 'password-generator'
4import * as Promise from 'bluebird'
6 5
7import { database as db } from './database' 6import { database as db } from './database'
8import { USER_ROLES, CONFIG, LAST_MIGRATION_VERSION } from './constants' 7import { USER_ROLES, CONFIG, LAST_MIGRATION_VERSION } from './constants'
9import { clientsExist, usersExist } from './checker' 8import { clientsExist, usersExist } from './checker'
10import { logger, createCertsIfNotExist, root } from '../helpers' 9import { logger, createCertsIfNotExist, root, mkdirpPromise } from '../helpers'
11 10
12function installApplication (callback: (err: Error) => void) { 11function installApplication () {
13 series([ 12 return db.sequelize.sync()
14 function createDatabase (callbackAsync) { 13 .then(() => createDirectoriesIfNotExist())
15 db.sequelize.sync().asCallback(callbackAsync) 14 .then(() => createCertsIfNotExist())
16 // db.sequelize.sync({ force: true }).asCallback(callbackAsync) 15 .then(() => createOAuthClientIfNotExist())
17 }, 16 .then(() => createOAuthAdminIfNotExist())
18
19 function createDirectories (callbackAsync) {
20 createDirectoriesIfNotExist(callbackAsync)
21 },
22
23 function createCertificates (callbackAsync) {
24 createCertsIfNotExist(callbackAsync)
25 },
26
27 function createOAuthClient (callbackAsync) {
28 createOAuthClientIfNotExist(callbackAsync)
29 },
30
31 function createOAuthUser (callbackAsync) {
32 createOAuthAdminIfNotExist(callbackAsync)
33 }
34 ], callback)
35} 17}
36 18
37// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
@@ -42,21 +24,22 @@ export {
42 24
43// --------------------------------------------------------------------------- 25// ---------------------------------------------------------------------------
44 26
45function createDirectoriesIfNotExist (callback: (err: Error) => void) { 27function createDirectoriesIfNotExist () {
46 const storages = config.get('storage') 28 const storages = config.get('storage')
47 29
48 each(Object.keys(storages), function (key, callbackEach) { 30 const tasks = []
31 Object.keys(storages).forEach(key => {
49 const dir = storages[key] 32 const dir = storages[key]
50 mkdirp(join(root(), dir), callbackEach) 33 tasks.push(mkdirpPromise(join(root(), dir)))
51 }, callback) 34 })
52}
53 35
54function createOAuthClientIfNotExist (callback: (err: Error) => void) { 36 return Promise.all(tasks)
55 clientsExist(function (err, exist) { 37}
56 if (err) return callback(err)
57 38
39function createOAuthClientIfNotExist () {
40 return clientsExist().then(exist => {
58 // Nothing to do, clients already exist 41 // Nothing to do, clients already exist
59 if (exist === true) return callback(null) 42 if (exist === true) return undefined
60 43
61 logger.info('Creating a default OAuth Client.') 44 logger.info('Creating a default OAuth Client.')
62 45
@@ -69,23 +52,19 @@ function createOAuthClientIfNotExist (callback: (err: Error) => void) {
69 redirectUris: null 52 redirectUris: null
70 }) 53 })
71 54
72 client.save().asCallback(function (err, createdClient) { 55 return client.save().then(createdClient => {
73 if (err) return callback(err)
74
75 logger.info('Client id: ' + createdClient.clientId) 56 logger.info('Client id: ' + createdClient.clientId)
76 logger.info('Client secret: ' + createdClient.clientSecret) 57 logger.info('Client secret: ' + createdClient.clientSecret)
77 58
78 return callback(null) 59 return undefined
79 }) 60 })
80 }) 61 })
81} 62}
82 63
83function createOAuthAdminIfNotExist (callback: (err: Error) => void) { 64function createOAuthAdminIfNotExist () {
84 usersExist(function (err, exist) { 65 return usersExist().then(exist => {
85 if (err) return callback(err)
86
87 // Nothing to do, users already exist 66 // Nothing to do, users already exist
88 if (exist === true) return callback(null) 67 if (exist === true) return undefined
89 68
90 logger.info('Creating the administrator.') 69 logger.info('Creating the administrator.')
91 70
@@ -116,14 +95,12 @@ function createOAuthAdminIfNotExist (callback: (err: Error) => void) {
116 role 95 role
117 } 96 }
118 97
119 db.User.create(userData, createOptions).asCallback(function (err, createdUser) { 98 return db.User.create(userData, createOptions).then(createdUser => {
120 if (err) return callback(err)
121
122 logger.info('Username: ' + username) 99 logger.info('Username: ' + username)
123 logger.info('User password: ' + password) 100 logger.info('User password: ' + password)
124 101
125 logger.info('Creating Application table.') 102 logger.info('Creating Application table.')
126 db.Application.create({ migrationVersion: LAST_MIGRATION_VERSION }).asCallback(callback) 103 return db.Application.create({ migrationVersion: LAST_MIGRATION_VERSION })
127 }) 104 })
128 }) 105 })
129} 106}
diff --git a/server/initializers/migrations/0005-email-pod.ts b/server/initializers/migrations/0005-email-pod.ts
index a9200c47f..ceefaad4a 100644
--- a/server/initializers/migrations/0005-email-pod.ts
+++ b/server/initializers/migrations/0005-email-pod.ts
@@ -1,9 +1,12 @@
1import { waterfall } from 'async' 1import * as Sequelize from 'sequelize'
2 2import * as Promise from 'bluebird'
3// utils = { transaction, queryInterface, sequelize, Sequelize } 3
4function up (utils, finalCallback) { 4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
5 const q = utils.queryInterface 9 const q = utils.queryInterface
6 const Sequelize = utils.Sequelize
7 10
8 const data = { 11 const data = {
9 type: Sequelize.STRING(400), 12 type: Sequelize.STRING(400),
@@ -11,27 +14,16 @@ function up (utils, finalCallback) {
11 defaultValue: '' 14 defaultValue: ''
12 } 15 }
13 16
14 waterfall([ 17 return q.addColumn('Pods', 'email', data)
15 18 .then(() => {
16 function addEmailColumn (callback) {
17 q.addColumn('Pods', 'email', data, { transaction: utils.transaction }).asCallback(function (err) {
18 return callback(err)
19 })
20 },
21
22 function updateWithFakeEmails (callback) {
23 const query = 'UPDATE "Pods" SET "email" = \'dummy@example.com\'' 19 const query = 'UPDATE "Pods" SET "email" = \'dummy@example.com\''
24 utils.sequelize.query(query, { transaction: utils.transaction }).asCallback(function (err) { 20 return utils.sequelize.query(query, { transaction: utils.transaction })
25 return callback(err) 21 })
26 }) 22 .then(() => {
27 },
28
29 function nullOnDefault (callback) {
30 data.defaultValue = null 23 data.defaultValue = null
31 24
32 q.changeColumn('Pods', 'email', data, { transaction: utils.transaction }).asCallback(callback) 25 return q.changeColumn('Pods', 'email', data)
33 } 26 })
34 ], finalCallback)
35} 27}
36 28
37function down (options, callback) { 29function down (options, callback) {
diff --git a/server/initializers/migrations/0010-email-user.ts b/server/initializers/migrations/0010-email-user.ts
index 4b5d29394..e8865acdb 100644
--- a/server/initializers/migrations/0010-email-user.ts
+++ b/server/initializers/migrations/0010-email-user.ts
@@ -1,37 +1,28 @@
1import { waterfall } from 'async' 1import * as Sequelize from 'sequelize'
2 2import * as Promise from 'bluebird'
3// utils = { transaction, queryInterface, sequelize, Sequelize } 3
4function up (utils, finalCallback) { 4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
5 const q = utils.queryInterface 9 const q = utils.queryInterface
6 const Sequelize = utils.Sequelize
7 10
8 const data = { 11 const data = {
9 type: Sequelize.STRING(400), 12 type: Sequelize.STRING(400),
10 allowNull: false, 13 allowNull: false,
11 defaultValue: '' 14 defaultValue: ''
12 } 15 }
13 16 return q.addColumn('Users', 'email', data)
14 waterfall([ 17 .then(() => {
15
16 function addEmailColumn (callback) {
17 q.addColumn('Users', 'email', data, { transaction: utils.transaction }).asCallback(function (err) {
18 return callback(err)
19 })
20 },
21
22 function updateWithFakeEmails (callback) {
23 const query = 'UPDATE "Users" SET "email" = CONCAT("username", \'@example.com\')' 18 const query = 'UPDATE "Users" SET "email" = CONCAT("username", \'@example.com\')'
24 utils.sequelize.query(query, { transaction: utils.transaction }).asCallback(function (err) { 19 return utils.sequelize.query(query, { transaction: utils.transaction })
25 return callback(err) 20 })
26 }) 21 .then(() => {
27 },
28
29 function nullOnDefault (callback) {
30 data.defaultValue = null 22 data.defaultValue = null
31 23
32 q.changeColumn('Users', 'email', data, { transaction: utils.transaction }).asCallback(callback) 24 return q.changeColumn('Users', 'email', data)
33 } 25 })
34 ], finalCallback)
35} 26}
36 27
37function down (options, callback) { 28function down (options, callback) {
diff --git a/server/initializers/migrations/0015-video-views.ts b/server/initializers/migrations/0015-video-views.ts
index e70869404..df274d817 100644
--- a/server/initializers/migrations/0015-video-views.ts
+++ b/server/initializers/migrations/0015-video-views.ts
@@ -1,7 +1,12 @@
1// utils = { transaction, queryInterface, sequelize, Sequelize } 1import * as Sequelize from 'sequelize'
2function up (utils, finalCallback) { 2import * as Promise from 'bluebird'
3
4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
3 const q = utils.queryInterface 9 const q = utils.queryInterface
4 const Sequelize = utils.Sequelize
5 10
6 const data = { 11 const data = {
7 type: Sequelize.INTEGER, 12 type: Sequelize.INTEGER,
@@ -9,7 +14,7 @@ function up (utils, finalCallback) {
9 defaultValue: 0 14 defaultValue: 0
10 } 15 }
11 16
12 q.addColumn('Videos', 'views', data, { transaction: utils.transaction }).asCallback(finalCallback) 17 return q.addColumn('Videos', 'views', data)
13} 18}
14 19
15function down (options, callback) { 20function down (options, callback) {
diff --git a/server/initializers/migrations/0020-video-likes.ts b/server/initializers/migrations/0020-video-likes.ts
index e435d0657..3d7182d0a 100644
--- a/server/initializers/migrations/0020-video-likes.ts
+++ b/server/initializers/migrations/0020-video-likes.ts
@@ -1,7 +1,12 @@
1// utils = { transaction, queryInterface, sequelize, Sequelize } 1import * as Sequelize from 'sequelize'
2function up (utils, finalCallback) { 2import * as Promise from 'bluebird'
3
4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
3 const q = utils.queryInterface 9 const q = utils.queryInterface
4 const Sequelize = utils.Sequelize
5 10
6 const data = { 11 const data = {
7 type: Sequelize.INTEGER, 12 type: Sequelize.INTEGER,
@@ -9,7 +14,7 @@ function up (utils, finalCallback) {
9 defaultValue: 0 14 defaultValue: 0
10 } 15 }
11 16
12 q.addColumn('Videos', 'likes', data, { transaction: utils.transaction }).asCallback(finalCallback) 17 return q.addColumn('Videos', 'likes', data)
13} 18}
14 19
15function down (options, callback) { 20function down (options, callback) {
diff --git a/server/initializers/migrations/0025-video-dislikes.ts b/server/initializers/migrations/0025-video-dislikes.ts
index 57e54e904..ed41095dc 100644
--- a/server/initializers/migrations/0025-video-dislikes.ts
+++ b/server/initializers/migrations/0025-video-dislikes.ts
@@ -1,7 +1,12 @@
1// utils = { transaction, queryInterface, sequelize, Sequelize } 1import * as Sequelize from 'sequelize'
2function up (utils, finalCallback) { 2import * as Promise from 'bluebird'
3
4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
3 const q = utils.queryInterface 9 const q = utils.queryInterface
4 const Sequelize = utils.Sequelize
5 10
6 const data = { 11 const data = {
7 type: Sequelize.INTEGER, 12 type: Sequelize.INTEGER,
@@ -9,7 +14,7 @@ function up (utils, finalCallback) {
9 defaultValue: 0 14 defaultValue: 0
10 } 15 }
11 16
12 q.addColumn('Videos', 'dislikes', data, { transaction: utils.transaction }).asCallback(finalCallback) 17 return q.addColumn('Videos', 'dislikes', data)
13} 18}
14 19
15function down (options, callback) { 20function down (options, callback) {
diff --git a/server/initializers/migrations/0030-video-category.ts b/server/initializers/migrations/0030-video-category.ts
index 1073f449c..f5adee8f9 100644
--- a/server/initializers/migrations/0030-video-category.ts
+++ b/server/initializers/migrations/0030-video-category.ts
@@ -1,9 +1,12 @@
1import { waterfall } from 'async' 1import * as Sequelize from 'sequelize'
2 2import * as Promise from 'bluebird'
3// utils = { transaction, queryInterface, sequelize, Sequelize } 3
4function up (utils, finalCallback) { 4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
5 const q = utils.queryInterface 9 const q = utils.queryInterface
6 const Sequelize = utils.Sequelize
7 10
8 const data = { 11 const data = {
9 type: Sequelize.INTEGER, 12 type: Sequelize.INTEGER,
@@ -11,20 +14,12 @@ function up (utils, finalCallback) {
11 defaultValue: 0 14 defaultValue: 0
12 } 15 }
13 16
14 waterfall([ 17 return q.addColumn('Videos', 'category', data)
15 18 .then(() => {
16 function addCategoryColumn (callback) {
17 q.addColumn('Videos', 'category', data, { transaction: utils.transaction }).asCallback(function (err) {
18 return callback(err)
19 })
20 },
21
22 function nullOnDefault (callback) {
23 data.defaultValue = null 19 data.defaultValue = null
24 20
25 q.changeColumn('Videos', 'category', data, { transaction: utils.transaction }).asCallback(callback) 21 return q.changeColumn('Videos', 'category', data)
26 } 22 })
27 ], finalCallback)
28} 23}
29 24
30function down (options, callback) { 25function down (options, callback) {
diff --git a/server/initializers/migrations/0035-video-licence.ts b/server/initializers/migrations/0035-video-licence.ts
index 9316b3c37..00c64d8e7 100644
--- a/server/initializers/migrations/0035-video-licence.ts
+++ b/server/initializers/migrations/0035-video-licence.ts
@@ -1,9 +1,12 @@
1import { waterfall } from 'async' 1import * as Sequelize from 'sequelize'
2 2import * as Promise from 'bluebird'
3// utils = { transaction, queryInterface, sequelize, Sequelize } 3
4function up (utils, finalCallback) { 4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
5 const q = utils.queryInterface 9 const q = utils.queryInterface
6 const Sequelize = utils.Sequelize
7 10
8 const data = { 11 const data = {
9 type: Sequelize.INTEGER, 12 type: Sequelize.INTEGER,
@@ -11,20 +14,11 @@ function up (utils, finalCallback) {
11 defaultValue: 0 14 defaultValue: 0
12 } 15 }
13 16
14 waterfall([ 17 return q.addColumn('Videos', 'licence', data)
15 18 .then(() => {
16 function addLicenceColumn (callback) {
17 q.addColumn('Videos', 'licence', data, { transaction: utils.transaction }).asCallback(function (err) {
18 return callback(err)
19 })
20 },
21
22 function nullOnDefault (callback) {
23 data.defaultValue = null 19 data.defaultValue = null
24 20 return q.changeColumn('Videos', 'licence', data)
25 q.changeColumn('Videos', 'licence', data, { transaction: utils.transaction }).asCallback(callback) 21 })
26 }
27 ], finalCallback)
28} 22}
29 23
30function down (options, callback) { 24function down (options, callback) {
diff --git a/server/initializers/migrations/0040-video-nsfw.ts b/server/initializers/migrations/0040-video-nsfw.ts
index c61f496f1..046876b61 100644
--- a/server/initializers/migrations/0040-video-nsfw.ts
+++ b/server/initializers/migrations/0040-video-nsfw.ts
@@ -1,9 +1,12 @@
1import { waterfall } from 'async' 1import * as Sequelize from 'sequelize'
2 2import * as Promise from 'bluebird'
3// utils = { transaction, queryInterface, sequelize, Sequelize } 3
4function up (utils, finalCallback) { 4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
5 const q = utils.queryInterface 9 const q = utils.queryInterface
6 const Sequelize = utils.Sequelize
7 10
8 const data = { 11 const data = {
9 type: Sequelize.BOOLEAN, 12 type: Sequelize.BOOLEAN,
@@ -11,20 +14,12 @@ function up (utils, finalCallback) {
11 defaultValue: false 14 defaultValue: false
12 } 15 }
13 16
14 waterfall([ 17 return q.addColumn('Videos', 'nsfw', data)
15 18 .then(() => {
16 function addNSFWColumn (callback) {
17 q.addColumn('Videos', 'nsfw', data, { transaction: utils.transaction }).asCallback(function (err) {
18 return callback(err)
19 })
20 },
21
22 function nullOnDefault (callback) {
23 data.defaultValue = null 19 data.defaultValue = null
24 20
25 q.changeColumn('Videos', 'nsfw', data, { transaction: utils.transaction }).asCallback(callback) 21 return q.changeColumn('Videos', 'nsfw', data)
26 } 22 })
27 ], finalCallback)
28} 23}
29 24
30function down (options, callback) { 25function down (options, callback) {
diff --git a/server/initializers/migrations/0045-user-display-nsfw.ts b/server/initializers/migrations/0045-user-display-nsfw.ts
index 1ca317795..75bd3bbea 100644
--- a/server/initializers/migrations/0045-user-display-nsfw.ts
+++ b/server/initializers/migrations/0045-user-display-nsfw.ts
@@ -1,7 +1,12 @@
1// utils = { transaction, queryInterface, sequelize, Sequelize } 1import * as Sequelize from 'sequelize'
2function up (utils, finalCallback) { 2import * as Promise from 'bluebird'
3
4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
3 const q = utils.queryInterface 9 const q = utils.queryInterface
4 const Sequelize = utils.Sequelize
5 10
6 const data = { 11 const data = {
7 type: Sequelize.BOOLEAN, 12 type: Sequelize.BOOLEAN,
@@ -9,7 +14,7 @@ function up (utils, finalCallback) {
9 defaultValue: false 14 defaultValue: false
10 } 15 }
11 16
12 q.addColumn('Users', 'displayNSFW', data, { transaction: utils.transaction }).asCallback(finalCallback) 17 return q.addColumn('Users', 'displayNSFW', data)
13} 18}
14 19
15function down (options, callback) { 20function down (options, callback) {
diff --git a/server/initializers/migrations/0050-video-language.ts b/server/initializers/migrations/0050-video-language.ts
index 95d0a473a..ed08f5866 100644
--- a/server/initializers/migrations/0050-video-language.ts
+++ b/server/initializers/migrations/0050-video-language.ts
@@ -1,7 +1,12 @@
1// utils = { transaction, queryInterface, sequelize, Sequelize } 1import * as Sequelize from 'sequelize'
2function up (utils, finalCallback) { 2import * as Promise from 'bluebird'
3
4function up (utils: {
5 transaction: Sequelize.Transaction,
6 queryInterface: Sequelize.QueryInterface,
7 sequelize: Sequelize.Sequelize
8}): Promise<void> {
3 const q = utils.queryInterface 9 const q = utils.queryInterface
4 const Sequelize = utils.Sequelize
5 10
6 const data = { 11 const data = {
7 type: Sequelize.INTEGER, 12 type: Sequelize.INTEGER,
@@ -9,7 +14,7 @@ function up (utils, finalCallback) {
9 defaultValue: null 14 defaultValue: null
10 } 15 }
11 16
12 q.addColumn('Videos', 'language', data, { transaction: utils.transaction }).asCallback(finalCallback) 17 return q.addColumn('Videos', 'language', data)
13} 18}
14 19
15function down (options, callback) { 20function down (options, callback) {
diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts
index d8faaebc6..d381551b5 100644
--- a/server/initializers/migrator.ts
+++ b/server/initializers/migrator.ts
@@ -1,70 +1,54 @@
1import { waterfall, eachSeries } from 'async'
2import * as fs from 'fs'
3import * as path from 'path' 1import * as path from 'path'
4import * as Sequelize from 'sequelize' 2import * as Promise from 'bluebird'
5 3
6import { database as db } from './database' 4import { database as db } from './database'
7import { LAST_MIGRATION_VERSION } from './constants' 5import { LAST_MIGRATION_VERSION } from './constants'
8import { logger } from '../helpers' 6import { logger, readdirPromise } from '../helpers'
9 7
10function migrate (finalCallback: (err: Error) => void) { 8function migrate () {
11 waterfall([ 9 const p = db.sequelize.getQueryInterface().showAllTables()
12 10 .then(tables => {
13 function checkApplicationTableExists (callback) { 11 // No tables, we don't need to migrate anything
14 db.sequelize.getQueryInterface().showAllTables().asCallback(function (err, tables) { 12 // The installer will do that
15 if (err) return callback(err) 13 if (tables.length === 0) throw null
16 14 })
17 // No tables, we don't need to migrate anything 15 .then(() => {
18 // The installer will do that 16 return db.Application.loadMigrationVersion()
19 if (tables.length === 0) return finalCallback(null) 17 })
20 18 .then(actualVersion => {
21 return callback(null)
22 })
23 },
24
25 function loadMigrationVersion (callback) {
26 db.Application.loadMigrationVersion(callback)
27 },
28
29 function createMigrationRowIfNotExists (actualVersion, callback) {
30 if (actualVersion === null) { 19 if (actualVersion === null) {
31 db.Application.create({ 20 return db.Application.create({ migrationVersion: 0 }).then(() => 0)
32 migrationVersion: 0
33 }, function (err) {
34 return callback(err, 0)
35 })
36 } 21 }
37 22
38 return callback(null, actualVersion) 23 return actualVersion
39 }, 24 })
40 25 .then(actualVersion => {
41 function abortMigrationIfNotNeeded (actualVersion, callback) { 26 // No need migrations, abort
42 // No need migrations 27 if (actualVersion >= LAST_MIGRATION_VERSION) throw null
43 if (actualVersion >= LAST_MIGRATION_VERSION) return finalCallback(null)
44
45 return callback(null, actualVersion)
46 },
47 28
48 function getMigrations (actualVersion, callback) { 29 return actualVersion
30 })
31 .then(actualVersion => {
49 // If there are a new migration scripts 32 // If there are a new migration scripts
50 logger.info('Begin migrations.') 33 logger.info('Begin migrations.')
51 34
52 getMigrationScripts(function (err, migrationScripts) { 35 return getMigrationScripts().then(migrationScripts => ({ actualVersion, migrationScripts }))
53 return callback(err, actualVersion, migrationScripts) 36 })
37 .then(({ actualVersion, migrationScripts }) => {
38 return Promise.mapSeries(migrationScripts, entity => {
39 return executeMigration(actualVersion, entity)
54 }) 40 })
55 }, 41 })
42 .then(() => {
43 logger.info('Migrations finished. New migration version schema: %s', LAST_MIGRATION_VERSION)
44 })
45 .catch(err => {
46 if (err === null) return undefined
56 47
57 function doMigrations (actualVersion, migrationScripts, callback) { 48 throw err
58 eachSeries(migrationScripts, function (entity: any, callbackEach) { 49 })
59 executeMigration(actualVersion, entity, callbackEach)
60 }, function (err) {
61 if (err) return callback(err)
62 50
63 logger.info('Migrations finished. New migration version schema: %s', LAST_MIGRATION_VERSION) 51 return p
64 return callback(null)
65 })
66 }
67 ], finalCallback)
68} 52}
69 53
70// --------------------------------------------------------------------------- 54// ---------------------------------------------------------------------------
@@ -75,12 +59,12 @@ export {
75 59
76// --------------------------------------------------------------------------- 60// ---------------------------------------------------------------------------
77 61
78type GetMigrationScriptsCallback = (err: Error, filesToMigrate?: { version: string, script: string }[]) => void 62function getMigrationScripts () {
79function getMigrationScripts (callback: GetMigrationScriptsCallback) { 63 return readdirPromise(path.join(__dirname, 'migrations')).then(files => {
80 fs.readdir(path.join(__dirname, 'migrations'), function (err, files) { 64 const filesToMigrate: {
81 if (err) return callback(err) 65 version: string,
82 66 script: string
83 const filesToMigrate = [] 67 }[] = []
84 68
85 files.forEach(function (file) { 69 files.forEach(function (file) {
86 // Filename is something like 'version-blabla.js' 70 // Filename is something like 'version-blabla.js'
@@ -91,15 +75,15 @@ function getMigrationScripts (callback: GetMigrationScriptsCallback) {
91 }) 75 })
92 }) 76 })
93 77
94 return callback(err, filesToMigrate) 78 return filesToMigrate
95 }) 79 })
96} 80}
97 81
98function executeMigration (actualVersion: number, entity: { version: string, script: string }, callback: (err: Error) => void) { 82function executeMigration (actualVersion: number, entity: { version: string, script: string }) {
99 const versionScript = parseInt(entity.version, 10) 83 const versionScript = parseInt(entity.version, 10)
100 84
101 // Do not execute old migration scripts 85 // Do not execute old migration scripts
102 if (versionScript <= actualVersion) return callback(null) 86 if (versionScript <= actualVersion) return undefined
103 87
104 // Load the migration module and run it 88 // Load the migration module and run it
105 const migrationScriptName = entity.script 89 const migrationScriptName = entity.script
@@ -107,30 +91,17 @@ function executeMigration (actualVersion: number, entity: { version: string, scr
107 91
108 const migrationScript = require(path.join(__dirname, 'migrations', migrationScriptName)) 92 const migrationScript = require(path.join(__dirname, 'migrations', migrationScriptName))
109 93
110 db.sequelize.transaction().asCallback(function (err, t) { 94 return db.sequelize.transaction(t => {
111 if (err) return callback(err)
112
113 const options = { 95 const options = {
114 transaction: t, 96 transaction: t,
115 queryInterface: db.sequelize.getQueryInterface(), 97 queryInterface: db.sequelize.getQueryInterface(),
116 sequelize: db.sequelize, 98 sequelize: db.sequelize
117 Sequelize: Sequelize
118 } 99 }
119 migrationScript.up(options, function (err) {
120 if (err) {
121 t.rollback()
122 return callback(err)
123 }
124
125 // Update the new migration version
126 db.Application.updateMigrationVersion(versionScript, t, function (err) {
127 if (err) {
128 t.rollback()
129 return callback(err)
130 }
131 100
132 t.commit().asCallback(callback) 101 migrationScript.up(options)
102 .then(() => {
103 // Update the new migration version
104 db.Application.updateMigrationVersion(versionScript, t)
133 }) 105 })
134 })
135 }) 106 })
136} 107}