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