aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/initializers
diff options
context:
space:
mode:
Diffstat (limited to 'server/initializers')
-rw-r--r--server/initializers/checker.ts46
-rw-r--r--server/initializers/database.ts90
-rw-r--r--server/initializers/index.ts2
-rw-r--r--server/initializers/installer.ts141
-rw-r--r--server/initializers/migrator.ts107
5 files changed, 178 insertions, 208 deletions
diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts
index eb9e9e280..9eaef1695 100644
--- a/server/initializers/checker.ts
+++ b/server/initializers/checker.ts
@@ -37,39 +37,37 @@ function checkMissedConfig () {
37 37
38// Check the available codecs 38// Check the available codecs
39// We get CONFIG by param to not import it in this file (import orders) 39// We get CONFIG by param to not import it in this file (import orders)
40function checkFFmpeg (CONFIG: { TRANSCODING: { ENABLED: boolean } }) { 40async function checkFFmpeg (CONFIG: { TRANSCODING: { ENABLED: boolean } }) {
41 const Ffmpeg = require('fluent-ffmpeg') 41 const Ffmpeg = require('fluent-ffmpeg')
42 const getAvailableCodecsPromise = promisify0(Ffmpeg.getAvailableCodecs) 42 const getAvailableCodecsPromise = promisify0(Ffmpeg.getAvailableCodecs)
43 43
44 getAvailableCodecsPromise() 44 const codecs = await getAvailableCodecsPromise()
45 .then(codecs => { 45 if (CONFIG.TRANSCODING.ENABLED === false) return undefined
46 if (CONFIG.TRANSCODING.ENABLED === false) return undefined 46
47 47 const canEncode = [ 'libx264' ]
48 const canEncode = [ 'libx264' ] 48 for (const codec of canEncode) {
49 canEncode.forEach(codec => { 49 if (codecs[codec] === undefined) {
50 if (codecs[codec] === undefined) { 50 throw new Error('Unknown codec ' + codec + ' in FFmpeg.')
51 throw new Error('Unknown codec ' + codec + ' in FFmpeg.') 51 }
52 } 52
53 53 if (codecs[codec].canEncode !== true) {
54 if (codecs[codec].canEncode !== true) { 54 throw new Error('Unavailable encode codec ' + codec + ' in FFmpeg')
55 throw new Error('Unavailable encode codec ' + codec + ' in FFmpeg') 55 }
56 } 56 }
57 })
58 })
59} 57}
60 58
61// We get db by param to not import it in this file (import orders) 59// We get db by param to not import it in this file (import orders)
62function clientsExist (OAuthClient: OAuthClientModel) { 60async function clientsExist (OAuthClient: OAuthClientModel) {
63 return OAuthClient.countTotal().then(totalClients => { 61 const totalClients = await OAuthClient.countTotal()
64 return totalClients !== 0 62
65 }) 63 return totalClients !== 0
66} 64}
67 65
68// We get db by param to not import it in this file (import orders) 66// We get db by param to not import it in this file (import orders)
69function usersExist (User: UserModel) { 67async function usersExist (User: UserModel) {
70 return User.countTotal().then(totalUsers => { 68 const totalUsers = await User.countTotal()
71 return totalUsers !== 0 69
72 }) 70 return totalUsers !== 0
73} 71}
74 72
75// --------------------------------------------------------------------------- 73// ---------------------------------------------------------------------------
diff --git a/server/initializers/database.ts b/server/initializers/database.ts
index ea2b68f59..ade72b62f 100644
--- a/server/initializers/database.ts
+++ b/server/initializers/database.ts
@@ -2,7 +2,7 @@ import { join } from 'path'
2import { flattenDepth } from 'lodash' 2import { flattenDepth } from 'lodash'
3require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string 3require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string
4import * as Sequelize from 'sequelize' 4import * as Sequelize from 'sequelize'
5import * as Promise from 'bluebird' 5import * as Bluebird from 'bluebird'
6 6
7import { CONFIG } from './constants' 7import { CONFIG } from './constants'
8// Do not use barrel, we need to load database first 8// Do not use barrel, we need to load database first
@@ -77,26 +77,26 @@ const sequelize = new Sequelize(dbname, username, password, {
77 77
78database.sequelize = sequelize 78database.sequelize = sequelize
79 79
80database.init = (silent: boolean) => { 80database.init = async (silent: boolean) => {
81 const modelDirectory = join(__dirname, '..', 'models') 81 const modelDirectory = join(__dirname, '..', 'models')
82 82
83 return getModelFiles(modelDirectory).then(filePaths => { 83 const filePaths = await getModelFiles(modelDirectory)
84 filePaths.forEach(filePath => {
85 const model = sequelize.import(filePath)
86 84
87 database[model['name']] = model 85 for (const filePath of filePaths) {
88 }) 86 const model = sequelize.import(filePath)
89 87
90 Object.keys(database).forEach(modelName => { 88 database[model['name']] = model
91 if ('associate' in database[modelName]) { 89 }
92 database[modelName].associate(database)
93 }
94 })
95 90
96 if (!silent) logger.info('Database %s is ready.', dbname) 91 for (const modelName of Object.keys(database)) {
92 if ('associate' in database[modelName]) {
93 database[modelName].associate(database)
94 }
95 }
97 96
98 return undefined 97 if (!silent) logger.info('Database %s is ready.', dbname)
99 }) 98
99 return undefined
100} 100}
101 101
102// --------------------------------------------------------------------------- 102// ---------------------------------------------------------------------------
@@ -107,31 +107,29 @@ export {
107 107
108// --------------------------------------------------------------------------- 108// ---------------------------------------------------------------------------
109 109
110function getModelFiles (modelDirectory: string) { 110async function getModelFiles (modelDirectory: string) {
111 return readdirPromise(modelDirectory) 111 const files = await readdirPromise(modelDirectory)
112 .then(files => { 112 const directories = files.filter(directory => {
113 const directories: string[] = files.filter(directory => { 113 // Find directories
114 // Find directories 114 if (
115 if ( 115 directory.endsWith('.js.map') ||
116 directory.endsWith('.js.map') || 116 directory === 'index.js' || directory === 'index.ts' ||
117 directory === 'index.js' || directory === 'index.ts' || 117 directory === 'utils.js' || directory === 'utils.ts'
118 directory === 'utils.js' || directory === 'utils.ts' 118 ) return false
119 ) return false 119
120 120 return true
121 return true 121 })
122 })
123 122
124 return directories 123 const tasks: Bluebird<any>[] = []
125 })
126 .then(directories => {
127 const tasks = []
128 124
129 // For each directory we read it and append model in the modelFilePaths array 125 // For each directory we read it and append model in the modelFilePaths array
130 directories.forEach(directory => { 126 for (const directory of directories) {
131 const modelDirectoryPath = join(modelDirectory, directory) 127 const modelDirectoryPath = join(modelDirectory, directory)
132 128
133 const promise = readdirPromise(modelDirectoryPath).then(files => { 129 const promise = readdirPromise(modelDirectoryPath)
134 const filteredFiles = files.filter(file => { 130 .then(files => {
131 const filteredFiles = files
132 .filter(file => {
135 if ( 133 if (
136 file === 'index.js' || file === 'index.ts' || 134 file === 'index.js' || file === 'index.ts' ||
137 file === 'utils.js' || file === 'utils.ts' || 135 file === 'utils.js' || file === 'utils.ts' ||
@@ -140,17 +138,15 @@ function getModelFiles (modelDirectory: string) {
140 ) return false 138 ) return false
141 139
142 return true 140 return true
143 }).map(file => join(modelDirectoryPath, file)) 141 })
144 142 .map(file => join(modelDirectoryPath, file))
145 return filteredFiles
146 })
147 143
148 tasks.push(promise) 144 return filteredFiles
149 }) 145 })
150 146
151 return Promise.all(tasks) 147 tasks.push(promise)
152 }) 148 }
153 .then((filteredFiles: string[][]) => { 149
154 return flattenDepth<string>(filteredFiles, 1) 150 const filteredFilesArray: string[][] = await Promise.all(tasks)
155 }) 151 return flattenDepth<string>(filteredFilesArray, 1)
156} 152}
diff --git a/server/initializers/index.ts b/server/initializers/index.ts
index b8400ff84..332702774 100644
--- a/server/initializers/index.ts
+++ b/server/initializers/index.ts
@@ -1,4 +1,4 @@
1// Constants first, databse in second! 1// Constants first, database in second!
2export * from './constants' 2export * from './constants'
3export * from './database' 3export * from './database'
4export * from './checker' 4export * from './checker'
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts
index b997de07f..4c04290fc 100644
--- a/server/initializers/installer.ts
+++ b/server/initializers/installer.ts
@@ -1,5 +1,5 @@
1import * as passwordGenerator from 'password-generator' 1import * as passwordGenerator from 'password-generator'
2import * as Promise from 'bluebird' 2import * as Bluebird from 'bluebird'
3 3
4import { database as db } from './database' 4import { database as db } from './database'
5import { USER_ROLES, CONFIG, LAST_MIGRATION_VERSION, CACHE } from './constants' 5import { USER_ROLES, CONFIG, LAST_MIGRATION_VERSION, CACHE } from './constants'
@@ -7,13 +7,13 @@ import { clientsExist, usersExist } from './checker'
7import { logger, createCertsIfNotExist, mkdirpPromise, rimrafPromise } from '../helpers' 7import { logger, createCertsIfNotExist, mkdirpPromise, rimrafPromise } from '../helpers'
8import { createUserAuthorAndChannel } from '../lib' 8import { createUserAuthorAndChannel } from '../lib'
9 9
10function installApplication () { 10async function installApplication () {
11 return db.sequelize.sync() 11 await db.sequelize.sync()
12 .then(() => removeCacheDirectories()) 12 await removeCacheDirectories()
13 .then(() => createDirectoriesIfNotExist()) 13 await createDirectoriesIfNotExist()
14 .then(() => createCertsIfNotExist()) 14 await createCertsIfNotExist()
15 .then(() => createOAuthClientIfNotExist()) 15 await createOAuthClientIfNotExist()
16 .then(() => createOAuthAdminIfNotExist()) 16 await createOAuthAdminIfNotExist()
17} 17}
18 18
19// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
@@ -27,13 +27,13 @@ export {
27function removeCacheDirectories () { 27function removeCacheDirectories () {
28 const cacheDirectories = CACHE.DIRECTORIES 28 const cacheDirectories = CACHE.DIRECTORIES
29 29
30 const tasks = [] 30 const tasks: Bluebird<any>[] = []
31 31
32 // Cache directories 32 // Cache directories
33 Object.keys(cacheDirectories).forEach(key => { 33 for (const key of Object.keys(cacheDirectories)) {
34 const dir = cacheDirectories[key] 34 const dir = cacheDirectories[key]
35 tasks.push(rimrafPromise(dir)) 35 tasks.push(rimrafPromise(dir))
36 }) 36 }
37 37
38 return Promise.all(tasks) 38 return Promise.all(tasks)
39} 39}
@@ -43,88 +43,83 @@ function createDirectoriesIfNotExist () {
43 const cacheDirectories = CACHE.DIRECTORIES 43 const cacheDirectories = CACHE.DIRECTORIES
44 44
45 const tasks = [] 45 const tasks = []
46 Object.keys(storage).forEach(key => { 46 for (const key of Object.keys(storage)) {
47 const dir = storage[key] 47 const dir = storage[key]
48 tasks.push(mkdirpPromise(dir)) 48 tasks.push(mkdirpPromise(dir))
49 }) 49 }
50 50
51 // Cache directories 51 // Cache directories
52 Object.keys(cacheDirectories).forEach(key => { 52 for (const key of Object.keys(cacheDirectories)) {
53 const dir = cacheDirectories[key] 53 const dir = cacheDirectories[key]
54 tasks.push(mkdirpPromise(dir)) 54 tasks.push(mkdirpPromise(dir))
55 }) 55 }
56 56
57 return Promise.all(tasks) 57 return Promise.all(tasks)
58} 58}
59 59
60function createOAuthClientIfNotExist () { 60async function createOAuthClientIfNotExist () {
61 return clientsExist(db.OAuthClient).then(exist => { 61 const exist = await clientsExist(db.OAuthClient)
62 // Nothing to do, clients already exist 62 // Nothing to do, clients already exist
63 if (exist === true) return undefined 63 if (exist === true) return undefined
64
65 logger.info('Creating a default OAuth Client.')
66
67 const id = passwordGenerator(32, false, /[a-z0-9]/)
68 const secret = passwordGenerator(32, false, /[a-zA-Z0-9]/)
69 const client = db.OAuthClient.build({
70 clientId: id,
71 clientSecret: secret,
72 grants: [ 'password', 'refresh_token' ],
73 redirectUris: null
74 })
75 64
76 return client.save().then(createdClient => { 65 logger.info('Creating a default OAuth Client.')
77 logger.info('Client id: ' + createdClient.clientId)
78 logger.info('Client secret: ' + createdClient.clientSecret)
79 66
80 return undefined 67 const id = passwordGenerator(32, false, /[a-z0-9]/)
81 }) 68 const secret = passwordGenerator(32, false, /[a-zA-Z0-9]/)
69 const client = db.OAuthClient.build({
70 clientId: id,
71 clientSecret: secret,
72 grants: [ 'password', 'refresh_token' ],
73 redirectUris: null
82 }) 74 })
83}
84 75
85function createOAuthAdminIfNotExist () { 76 const createdClient = await client.save()
86 return usersExist(db.User).then(exist => { 77 logger.info('Client id: ' + createdClient.clientId)
87 // Nothing to do, users already exist 78 logger.info('Client secret: ' + createdClient.clientSecret)
88 if (exist === true) return undefined
89 79
90 logger.info('Creating the administrator.') 80 return undefined
81}
91 82
92 const username = 'root' 83async function createOAuthAdminIfNotExist () {
93 const role = USER_ROLES.ADMIN 84 const exist = await usersExist(db.User)
94 const email = CONFIG.ADMIN.EMAIL 85 // Nothing to do, users already exist
95 let validatePassword = true 86 if (exist === true) return undefined
96 let password = ''
97 87
98 // Do not generate a random password for tests 88 logger.info('Creating the administrator.')
99 if (process.env.NODE_ENV === 'test') {
100 password = 'test'
101 89
102 if (process.env.NODE_APP_INSTANCE) { 90 const username = 'root'
103 password += process.env.NODE_APP_INSTANCE 91 const role = USER_ROLES.ADMIN
104 } 92 const email = CONFIG.ADMIN.EMAIL
93 let validatePassword = true
94 let password = ''
105 95
106 // Our password is weak so do not validate it 96 // Do not generate a random password for tests
107 validatePassword = false 97 if (process.env.NODE_ENV === 'test') {
108 } else { 98 password = 'test'
109 password = passwordGenerator(8, true)
110 }
111 99
112 const userData = { 100 if (process.env.NODE_APP_INSTANCE) {
113 username, 101 password += process.env.NODE_APP_INSTANCE
114 email,
115 password,
116 role,
117 videoQuota: -1
118 } 102 }
119 const user = db.User.build(userData)
120 103
121 return createUserAuthorAndChannel(user, validatePassword) 104 // Our password is weak so do not validate it
122 .then(({ user }) => { 105 validatePassword = false
123 logger.info('Username: ' + username) 106 } else {
124 logger.info('User password: ' + password) 107 password = passwordGenerator(8, true)
125 108 }
126 logger.info('Creating Application table.') 109
127 return db.Application.create({ migrationVersion: LAST_MIGRATION_VERSION }) 110 const userData = {
128 }) 111 username,
129 }) 112 email,
113 password,
114 role,
115 videoQuota: -1
116 }
117 const user = db.User.build(userData)
118
119 await createUserAuthorAndChannel(user, validatePassword)
120 logger.info('Username: ' + username)
121 logger.info('User password: ' + password)
122
123 logger.info('Creating Application table.')
124 await db.Application.create({ migrationVersion: LAST_MIGRATION_VERSION })
130} 125}
diff --git a/server/initializers/migrator.ts b/server/initializers/migrator.ts
index 7b535aea9..4fbe1cf5b 100644
--- a/server/initializers/migrator.ts
+++ b/server/initializers/migrator.ts
@@ -1,52 +1,35 @@
1import * as path from 'path' 1import * as path from 'path'
2import * as Promise from 'bluebird'
3 2
4import { database as db } from './database' 3import { database as db } from './database'
5import { LAST_MIGRATION_VERSION } from './constants' 4import { LAST_MIGRATION_VERSION } from './constants'
6import { logger, readdirPromise } from '../helpers' 5import { logger, readdirPromise } from '../helpers'
7 6
8function migrate () { 7async function migrate () {
9 const p = db.sequelize.getQueryInterface().showAllTables() 8 const tables = await db.sequelize.getQueryInterface().showAllTables()
10 .then(tables => {
11 // No tables, we don't need to migrate anything
12 // The installer will do that
13 if (tables.length === 0) throw null
14 })
15 .then(() => {
16 return db.Application.loadMigrationVersion()
17 })
18 .then(actualVersion => {
19 if (actualVersion === null) {
20 return db.Application.create({ migrationVersion: 0 }).then(() => 0)
21 }
22 9
23 return actualVersion 10 // No tables, we don't need to migrate anything
24 }) 11 // The installer will do that
25 .then(actualVersion => { 12 if (tables.length === 0) return
26 // No need migrations, abort
27 if (actualVersion >= LAST_MIGRATION_VERSION) throw null
28 13
29 return actualVersion 14 let actualVersion = await db.Application.loadMigrationVersion()
30 }) 15 if (actualVersion === null) {
31 .then(actualVersion => { 16 await db.Application.create({ migrationVersion: 0 })
32 // If there are a new migration scripts 17 actualVersion = 0
33 logger.info('Begin migrations.') 18 }
34 19
35 return getMigrationScripts().then(migrationScripts => ({ actualVersion, migrationScripts })) 20 // No need migrations, abort
36 }) 21 if (actualVersion >= LAST_MIGRATION_VERSION) return
37 .then(({ actualVersion, migrationScripts }) => {
38 return Promise.each(migrationScripts, entity => executeMigration(actualVersion, entity))
39 })
40 .then(() => {
41 logger.info('Migrations finished. New migration version schema: %s', LAST_MIGRATION_VERSION)
42 })
43 .catch(err => {
44 if (err === null) return undefined
45 22
46 throw err 23 // If there are a new migration scripts
47 }) 24 logger.info('Begin migrations.')
25
26 const migrationScripts = await getMigrationScripts()
48 27
49 return p 28 for (const migrationScript of migrationScripts) {
29 await executeMigration(actualVersion, migrationScript)
30 }
31
32 logger.info('Migrations finished. New migration version schema: %s', LAST_MIGRATION_VERSION)
50} 33}
51 34
52// --------------------------------------------------------------------------- 35// ---------------------------------------------------------------------------
@@ -57,29 +40,28 @@ export {
57 40
58// --------------------------------------------------------------------------- 41// ---------------------------------------------------------------------------
59 42
60function getMigrationScripts () { 43async function getMigrationScripts () {
61 return readdirPromise(path.join(__dirname, 'migrations')).then(files => { 44 const files = await readdirPromise(path.join(__dirname, 'migrations'))
62 const filesToMigrate: { 45 const filesToMigrate: {
63 version: string, 46 version: string,
64 script: string 47 script: string
65 }[] = [] 48 }[] = []
66 49
67 files 50 files
68 .filter(file => file.endsWith('.js.map') === false) 51 .filter(file => file.endsWith('.js.map') === false)
69 .forEach(file => { 52 .forEach(file => {
70 // Filename is something like 'version-blabla.js' 53 // Filename is something like 'version-blabla.js'
71 const version = file.split('-')[0] 54 const version = file.split('-')[0]
72 filesToMigrate.push({ 55 filesToMigrate.push({
73 version, 56 version,
74 script: file 57 script: file
75 })
76 }) 58 })
59 })
77 60
78 return filesToMigrate 61 return filesToMigrate
79 })
80} 62}
81 63
82function executeMigration (actualVersion: number, entity: { version: string, script: string }) { 64async function executeMigration (actualVersion: number, entity: { version: string, script: string }) {
83 const versionScript = parseInt(entity.version, 10) 65 const versionScript = parseInt(entity.version, 10)
84 66
85 // Do not execute old migration scripts 67 // Do not execute old migration scripts
@@ -91,7 +73,7 @@ function executeMigration (actualVersion: number, entity: { version: string, scr
91 73
92 const migrationScript = require(path.join(__dirname, 'migrations', migrationScriptName)) 74 const migrationScript = require(path.join(__dirname, 'migrations', migrationScriptName))
93 75
94 return db.sequelize.transaction(t => { 76 await db.sequelize.transaction(async t => {
95 const options = { 77 const options = {
96 transaction: t, 78 transaction: t,
97 queryInterface: db.sequelize.getQueryInterface(), 79 queryInterface: db.sequelize.getQueryInterface(),
@@ -99,10 +81,9 @@ function executeMigration (actualVersion: number, entity: { version: string, scr
99 db 81 db
100 } 82 }
101 83
102 return migrationScript.up(options) 84 await migrationScript.up(options)
103 .then(() => { 85
104 // Update the new migration version 86 // Update the new migration version
105 return db.Application.updateMigrationVersion(versionScript, t) 87 await db.Application.updateMigrationVersion(versionScript, t)
106 })
107 }) 88 })
108} 89}