]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/initializers/database.ts
Add server API to abuse messages
[github/Chocobozzz/PeerTube.git] / server / initializers / database.ts
1 import { QueryTypes, Transaction } from 'sequelize'
2 import { Sequelize as SequelizeTypescript } from 'sequelize-typescript'
3 import { AbuseModel } from '@server/models/abuse/abuse'
4 import { AbuseMessageModel } from '@server/models/abuse/abuse-message'
5 import { VideoAbuseModel } from '@server/models/abuse/video-abuse'
6 import { VideoCommentAbuseModel } from '@server/models/abuse/video-comment-abuse'
7 import { isTestInstance } from '../helpers/core-utils'
8 import { logger } from '../helpers/logger'
9 import { AccountModel } from '../models/account/account'
10 import { AccountBlocklistModel } from '../models/account/account-blocklist'
11 import { AccountVideoRateModel } from '../models/account/account-video-rate'
12 import { UserModel } from '../models/account/user'
13 import { UserNotificationModel } from '../models/account/user-notification'
14 import { UserNotificationSettingModel } from '../models/account/user-notification-setting'
15 import { UserVideoHistoryModel } from '../models/account/user-video-history'
16 import { ActorModel } from '../models/activitypub/actor'
17 import { ActorFollowModel } from '../models/activitypub/actor-follow'
18 import { ApplicationModel } from '../models/application/application'
19 import { AvatarModel } from '../models/avatar/avatar'
20 import { OAuthClientModel } from '../models/oauth/oauth-client'
21 import { OAuthTokenModel } from '../models/oauth/oauth-token'
22 import { VideoRedundancyModel } from '../models/redundancy/video-redundancy'
23 import { PluginModel } from '../models/server/plugin'
24 import { ServerModel } from '../models/server/server'
25 import { ServerBlocklistModel } from '../models/server/server-blocklist'
26 import { ScheduleVideoUpdateModel } from '../models/video/schedule-video-update'
27 import { TagModel } from '../models/video/tag'
28 import { ThumbnailModel } from '../models/video/thumbnail'
29 import { VideoModel } from '../models/video/video'
30 import { VideoBlacklistModel } from '../models/video/video-blacklist'
31 import { VideoCaptionModel } from '../models/video/video-caption'
32 import { VideoChangeOwnershipModel } from '../models/video/video-change-ownership'
33 import { VideoChannelModel } from '../models/video/video-channel'
34 import { VideoCommentModel } from '../models/video/video-comment'
35 import { VideoFileModel } from '../models/video/video-file'
36 import { VideoImportModel } from '../models/video/video-import'
37 import { VideoPlaylistModel } from '../models/video/video-playlist'
38 import { VideoPlaylistElementModel } from '../models/video/video-playlist-element'
39 import { VideoShareModel } from '../models/video/video-share'
40 import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
41 import { VideoTagModel } from '../models/video/video-tag'
42 import { VideoViewModel } from '../models/video/video-view'
43 import { CONFIG } from './config'
44
45 require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string
46
47 const dbname = CONFIG.DATABASE.DBNAME
48 const username = CONFIG.DATABASE.USERNAME
49 const password = CONFIG.DATABASE.PASSWORD
50 const host = CONFIG.DATABASE.HOSTNAME
51 const port = CONFIG.DATABASE.PORT
52 const poolMax = CONFIG.DATABASE.POOL.MAX
53
54 const sequelizeTypescript = new SequelizeTypescript({
55 database: dbname,
56 dialect: 'postgres',
57 host,
58 port,
59 username,
60 password,
61 pool: {
62 max: poolMax
63 },
64 benchmark: isTestInstance(),
65 isolationLevel: Transaction.ISOLATION_LEVELS.SERIALIZABLE,
66 logging: (message: string, benchmark: number) => {
67 if (process.env.NODE_DB_LOG === 'false') return
68
69 let newMessage = message
70 if (isTestInstance() === true && benchmark !== undefined) {
71 newMessage += ' | ' + benchmark + 'ms'
72 }
73
74 logger.debug(newMessage)
75 }
76 })
77
78 async function initDatabaseModels (silent: boolean) {
79 sequelizeTypescript.addModels([
80 ApplicationModel,
81 ActorModel,
82 ActorFollowModel,
83 AvatarModel,
84 AccountModel,
85 OAuthClientModel,
86 OAuthTokenModel,
87 ServerModel,
88 TagModel,
89 AccountVideoRateModel,
90 UserModel,
91 AbuseMessageModel,
92 AbuseModel,
93 VideoCommentAbuseModel,
94 VideoAbuseModel,
95 VideoModel,
96 VideoChangeOwnershipModel,
97 VideoChannelModel,
98 VideoShareModel,
99 VideoFileModel,
100 VideoCaptionModel,
101 VideoBlacklistModel,
102 VideoTagModel,
103 VideoCommentModel,
104 ScheduleVideoUpdateModel,
105 VideoImportModel,
106 VideoViewModel,
107 VideoRedundancyModel,
108 UserVideoHistoryModel,
109 AccountBlocklistModel,
110 ServerBlocklistModel,
111 UserNotificationModel,
112 UserNotificationSettingModel,
113 VideoStreamingPlaylistModel,
114 VideoPlaylistModel,
115 VideoPlaylistElementModel,
116 ThumbnailModel,
117 PluginModel
118 ])
119
120 // Check extensions exist in the database
121 await checkPostgresExtensions()
122
123 // Create custom PostgreSQL functions
124 await createFunctions()
125
126 if (!silent) logger.info('Database %s is ready.', dbname)
127 }
128
129 // ---------------------------------------------------------------------------
130
131 export {
132 initDatabaseModels,
133 sequelizeTypescript
134 }
135
136 // ---------------------------------------------------------------------------
137
138 async function checkPostgresExtensions () {
139 const promises = [
140 checkPostgresExtension('pg_trgm'),
141 checkPostgresExtension('unaccent')
142 ]
143
144 return Promise.all(promises)
145 }
146
147 async function checkPostgresExtension (extension: string) {
148 const query = `SELECT 1 FROM pg_available_extensions WHERE name = '${extension}' AND installed_version IS NOT NULL;`
149 const options = {
150 type: QueryTypes.SELECT as QueryTypes.SELECT,
151 raw: true
152 }
153
154 const res = await sequelizeTypescript.query<object>(query, options)
155
156 if (!res || res.length === 0) {
157 // Try to create the extension ourselves
158 try {
159 await sequelizeTypescript.query(`CREATE EXTENSION ${extension};`, { raw: true })
160
161 } catch {
162 const errorMessage = `You need to enable ${extension} extension in PostgreSQL. ` +
163 `You can do so by running 'CREATE EXTENSION ${extension};' as a PostgreSQL super user in ${CONFIG.DATABASE.DBNAME} database.`
164 throw new Error(errorMessage)
165 }
166 }
167 }
168
169 function createFunctions () {
170 const query = `CREATE OR REPLACE FUNCTION immutable_unaccent(text)
171 RETURNS text AS
172 $func$
173 SELECT public.unaccent('public.unaccent', $1::text)
174 $func$ LANGUAGE sql IMMUTABLE;`
175
176 return sequelizeTypescript.query(query, { raw: true })
177 }