]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/initializers/database.ts
Implement signup approval in server
[github/Chocobozzz/PeerTube.git] / server / initializers / database.ts
CommitLineData
d95d1559 1import { QueryTypes, Transaction } from 'sequelize'
3fd3ab2d 2import { Sequelize as SequelizeTypescript } from 'sequelize-typescript'
b2111066 3import { ActorCustomPageModel } from '@server/models/account/actor-custom-page'
f4796856
C
4import { TrackerModel } from '@server/models/server/tracker'
5import { VideoTrackerModel } from '@server/models/server/video-tracker'
7d9ba5c0
C
6import { UserModel } from '@server/models/user/user'
7import { UserNotificationModel } from '@server/models/user/user-notification'
e364e31e 8import { UserRegistrationModel } from '@server/models/user/user-registration'
7d9ba5c0 9import { UserVideoHistoryModel } from '@server/models/user/user-video-history'
e364e31e 10import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync'
b2111066 11import { VideoJobInfoModel } from '@server/models/video/video-job-info'
26e3e98f 12import { VideoLiveSessionModel } from '@server/models/video/video-live-session'
9452d4fd 13import { VideoSourceModel } from '@server/models/video/video-source'
b2111066
C
14import { LocalVideoViewerModel } from '@server/models/view/local-video-viewer'
15import { LocalVideoViewerWatchSectionModel } from '@server/models/view/local-video-viewer-watch-section'
9452d4fd 16import { isTestOrDevInstance } from '../helpers/core-utils'
3fd3ab2d 17import { logger } from '../helpers/logger'
c6c0fa6c
C
18import { AbuseModel } from '../models/abuse/abuse'
19import { AbuseMessageModel } from '../models/abuse/abuse-message'
20import { VideoAbuseModel } from '../models/abuse/video-abuse'
21import { VideoCommentAbuseModel } from '../models/abuse/video-comment-abuse'
3fd3ab2d 22import { AccountModel } from '../models/account/account'
d95d1559 23import { AccountBlocklistModel } from '../models/account/account-blocklist'
3fd3ab2d 24import { AccountVideoRateModel } from '../models/account/account-video-rate'
7d9ba5c0
C
25import { ActorModel } from '../models/actor/actor'
26import { ActorFollowModel } from '../models/actor/actor-follow'
27import { ActorImageModel } from '../models/actor/actor-image'
3fd3ab2d 28import { ApplicationModel } from '../models/application/application'
3fd3ab2d
C
29import { OAuthClientModel } from '../models/oauth/oauth-client'
30import { OAuthTokenModel } from '../models/oauth/oauth-token'
d95d1559
C
31import { VideoRedundancyModel } from '../models/redundancy/video-redundancy'
32import { PluginModel } from '../models/server/plugin'
3fd3ab2d 33import { ServerModel } from '../models/server/server'
d95d1559 34import { ServerBlocklistModel } from '../models/server/server-blocklist'
7d9ba5c0 35import { UserNotificationSettingModel } from '../models/user/user-notification-setting'
d95d1559 36import { ScheduleVideoUpdateModel } from '../models/video/schedule-video-update'
3fd3ab2d 37import { TagModel } from '../models/video/tag'
d95d1559 38import { ThumbnailModel } from '../models/video/thumbnail'
3fd3ab2d 39import { VideoModel } from '../models/video/video'
3fd3ab2d 40import { VideoBlacklistModel } from '../models/video/video-blacklist'
d95d1559
C
41import { VideoCaptionModel } from '../models/video/video-caption'
42import { VideoChangeOwnershipModel } from '../models/video/video-change-ownership'
3fd3ab2d 43import { VideoChannelModel } from '../models/video/video-channel'
6d852470 44import { VideoCommentModel } from '../models/video/video-comment'
3fd3ab2d 45import { VideoFileModel } from '../models/video/video-file'
fbad87b0 46import { VideoImportModel } from '../models/video/video-import'
c6c0fa6c 47import { VideoLiveModel } from '../models/video/video-live'
418d092a
C
48import { VideoPlaylistModel } from '../models/video/video-playlist'
49import { VideoPlaylistElementModel } from '../models/video/video-playlist-element'
d95d1559
C
50import { VideoShareModel } from '../models/video/video-share'
51import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
52import { VideoTagModel } from '../models/video/video-tag'
b2111066 53import { VideoViewModel } from '../models/view/video-view'
d95d1559 54import { CONFIG } from './config'
fdbda9e3 55
3fd3ab2d 56require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string
8c308c2b 57
65fcc311
C
58const dbname = CONFIG.DATABASE.DBNAME
59const username = CONFIG.DATABASE.USERNAME
60const password = CONFIG.DATABASE.PASSWORD
228077ef
C
61const host = CONFIG.DATABASE.HOSTNAME
62const port = CONFIG.DATABASE.PORT
1c3386e8 63const poolMax = CONFIG.DATABASE.POOL.MAX
8c308c2b 64
6bc672da
C
65let dialectOptions: any = {}
66
67if (CONFIG.DATABASE.SSL) {
68 dialectOptions = {
69 ssl: {
70 rejectUnauthorized: false
71 }
72 }
73}
74
3fd3ab2d
C
75const sequelizeTypescript = new SequelizeTypescript({
76 database: dbname,
feb4bdfd 77 dialect: 'postgres',
6bc672da 78 dialectOptions,
228077ef
C
79 host,
80 port,
3fd3ab2d
C
81 username,
82 password,
1c3386e8
RK
83 pool: {
84 max: poolMax
85 },
9452d4fd 86 benchmark: isTestOrDevInstance(),
1735c825 87 isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
075f16ca 88 logging: (message: string, benchmark: number) => {
165cdc75
C
89 if (process.env.NODE_DB_LOG === 'false') return
90
2a6cf69c 91 let newMessage = 'Executed SQL request'
9452d4fd 92 if (isTestOrDevInstance() === true && benchmark !== undefined) {
2a6cf69c 93 newMessage += ' in ' + benchmark + 'ms'
7920c273
C
94 }
95
452b3bea 96 logger.debug(newMessage, { sql: message, tags: [ 'sql' ] })
7920c273 97 }
feb4bdfd
C
98})
99
74055dc8
C
100function checkDatabaseConnectionOrDie () {
101 sequelizeTypescript.authenticate()
102 .then(() => logger.debug('Connection to PostgreSQL has been established successfully.'))
103 .catch(err => {
104
105 logger.error('Unable to connect to PostgreSQL database.', { err })
106 process.exit(-1)
107 })
108}
4f24f16e 109
91fea9fc 110async function initDatabaseModels (silent: boolean) {
3fd3ab2d
C
111 sequelizeTypescript.addModels([
112 ApplicationModel,
50d6de9c
C
113 ActorModel,
114 ActorFollowModel,
f4796856 115 ActorImageModel,
3fd3ab2d 116 AccountModel,
3fd3ab2d
C
117 OAuthClientModel,
118 OAuthTokenModel,
119 ServerModel,
120 TagModel,
121 AccountVideoRateModel,
3fd3ab2d 122 UserModel,
edbc9325 123 AbuseMessageModel,
d95d1559
C
124 AbuseModel,
125 VideoCommentAbuseModel,
3fd3ab2d 126 VideoAbuseModel,
b876eaf1 127 VideoModel,
74d63469 128 VideoChangeOwnershipModel,
3fd3ab2d 129 VideoChannelModel,
3fd3ab2d
C
130 VideoShareModel,
131 VideoFileModel,
2e401e85 132 VideoSourceModel,
40e87e9e 133 VideoCaptionModel,
3fd3ab2d
C
134 VideoBlacklistModel,
135 VideoTagModel,
2baea0c7 136 VideoCommentModel,
fbad87b0 137 ScheduleVideoUpdateModel,
6b616860 138 VideoImportModel,
c48e82b5 139 VideoViewModel,
6e46de09 140 VideoRedundancyModel,
7ad9b984 141 UserVideoHistoryModel,
c6c0fa6c 142 VideoLiveModel,
26e3e98f 143 VideoLiveSessionModel,
7ad9b984 144 AccountBlocklistModel,
cef534ed
C
145 ServerBlocklistModel,
146 UserNotificationModel,
09209296 147 UserNotificationSettingModel,
418d092a
C
148 VideoStreamingPlaylistModel,
149 VideoPlaylistModel,
e8bafea3 150 VideoPlaylistElementModel,
b2111066
C
151 LocalVideoViewerModel,
152 LocalVideoViewerWatchSectionModel,
f023a19c 153 ThumbnailModel,
d9a2a031
C
154 TrackerModel,
155 VideoTrackerModel,
2539932e 156 PluginModel,
0305db28 157 ActorCustomPageModel,
2a491182 158 VideoJobInfoModel,
e364e31e
C
159 VideoChannelSyncModel,
160 UserRegistrationModel
3fd3ab2d 161 ])
b769007f 162
57c36b27
C
163 // Check extensions exist in the database
164 await checkPostgresExtensions()
165
166 // Create custom PostgreSQL functions
167 await createFunctions()
168
f5028693 169 if (!silent) logger.info('Database %s is ready.', dbname)
b769007f 170}
65fcc311
C
171
172// ---------------------------------------------------------------------------
173
e02643f3 174export {
91fea9fc 175 initDatabaseModels,
74055dc8 176 checkDatabaseConnectionOrDie,
3fd3ab2d 177 sequelizeTypescript
74889a71 178}
57c36b27
C
179
180// ---------------------------------------------------------------------------
181
182async function checkPostgresExtensions () {
0b2f03d3
C
183 const promises = [
184 checkPostgresExtension('pg_trgm'),
185 checkPostgresExtension('unaccent')
57c36b27
C
186 ]
187
0b2f03d3
C
188 return Promise.all(promises)
189}
190
191async function checkPostgresExtension (extension: string) {
3acc5084 192 const query = `SELECT 1 FROM pg_available_extensions WHERE name = '${extension}' AND installed_version IS NOT NULL;`
1735c825
C
193 const options = {
194 type: QueryTypes.SELECT as QueryTypes.SELECT,
195 raw: true
196 }
197
3acc5084 198 const res = await sequelizeTypescript.query<object>(query, options)
57c36b27 199
3acc5084 200 if (!res || res.length === 0) {
1735c825 201 // Try to create the extension ourselves
0b2f03d3
C
202 try {
203 await sequelizeTypescript.query(`CREATE EXTENSION ${extension};`, { raw: true })
57c36b27 204
0b2f03d3
C
205 } catch {
206 const errorMessage = `You need to enable ${extension} extension in PostgreSQL. ` +
207 `You can do so by running 'CREATE EXTENSION ${extension};' as a PostgreSQL super user in ${CONFIG.DATABASE.DBNAME} database.`
208 throw new Error(errorMessage)
57c36b27
C
209 }
210 }
211}
212
f0ad4710 213function createFunctions () {
2cebd797
C
214 const query = `CREATE OR REPLACE FUNCTION immutable_unaccent(text)
215 RETURNS text AS
216$func$
217SELECT public.unaccent('public.unaccent', $1::text)
218$func$ LANGUAGE sql IMMUTABLE;`
57c36b27
C
219
220 return sequelizeTypescript.query(query, { raw: true })
221}