diff options
Diffstat (limited to 'server/initializers')
-rw-r--r-- | server/initializers/checker-after-init.ts | 15 | ||||
-rw-r--r-- | server/initializers/checker-before-init.ts | 3 | ||||
-rw-r--r-- | server/initializers/config.ts | 7 | ||||
-rw-r--r-- | server/initializers/constants.ts | 31 | ||||
-rw-r--r-- | server/initializers/database.ts | 6 | ||||
-rw-r--r-- | server/initializers/installer.ts | 6 | ||||
-rw-r--r-- | server/initializers/migrations/0750-user-registration.ts | 58 | ||||
-rw-r--r-- | server/initializers/migrations/0755-unique-viewer-url.ts | 27 |
8 files changed, 134 insertions, 19 deletions
diff --git a/server/initializers/checker-after-init.ts b/server/initializers/checker-after-init.ts index c83fef425..0df7414be 100644 --- a/server/initializers/checker-after-init.ts +++ b/server/initializers/checker-after-init.ts | |||
@@ -4,7 +4,7 @@ import { getFFmpegVersion } from '@server/helpers/ffmpeg' | |||
4 | import { uniqify } from '@shared/core-utils' | 4 | import { uniqify } from '@shared/core-utils' |
5 | import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type' | 5 | import { VideoRedundancyConfigFilter } from '@shared/models/redundancy/video-redundancy-config-filter.type' |
6 | import { RecentlyAddedStrategy } from '../../shared/models/redundancy' | 6 | import { RecentlyAddedStrategy } from '../../shared/models/redundancy' |
7 | import { isProdInstance, parseSemVersion } from '../helpers/core-utils' | 7 | import { isProdInstance, parseBytes, parseSemVersion } from '../helpers/core-utils' |
8 | import { isArray } from '../helpers/custom-validators/misc' | 8 | import { isArray } from '../helpers/custom-validators/misc' |
9 | import { logger } from '../helpers/logger' | 9 | import { logger } from '../helpers/logger' |
10 | import { ApplicationModel, getServerActor } from '../models/application/application' | 10 | import { ApplicationModel, getServerActor } from '../models/application/application' |
@@ -116,6 +116,11 @@ function checkEmailConfig () { | |||
116 | throw new Error('Emailer is disabled but you require signup email verification.') | 116 | throw new Error('Emailer is disabled but you require signup email verification.') |
117 | } | 117 | } |
118 | 118 | ||
119 | if (CONFIG.SIGNUP.ENABLED && CONFIG.SIGNUP.REQUIRES_APPROVAL) { | ||
120 | // eslint-disable-next-line max-len | ||
121 | logger.warn('Emailer is disabled but signup approval is enabled: PeerTube will not be able to send an email to the user upon acceptance/rejection of the registration request') | ||
122 | } | ||
123 | |||
119 | if (CONFIG.CONTACT_FORM.ENABLED) { | 124 | if (CONFIG.CONTACT_FORM.ENABLED) { |
120 | logger.warn('Emailer is disabled so the contact form will not work.') | 125 | logger.warn('Emailer is disabled so the contact form will not work.') |
121 | } | 126 | } |
@@ -174,7 +179,8 @@ function checkRemoteRedundancyConfig () { | |||
174 | function checkStorageConfig () { | 179 | function checkStorageConfig () { |
175 | // Check storage directory locations | 180 | // Check storage directory locations |
176 | if (isProdInstance()) { | 181 | if (isProdInstance()) { |
177 | const configStorage = config.get('storage') | 182 | const configStorage = config.get<{ [ name: string ]: string }>('storage') |
183 | |||
178 | for (const key of Object.keys(configStorage)) { | 184 | for (const key of Object.keys(configStorage)) { |
179 | if (configStorage[key].startsWith('storage/')) { | 185 | if (configStorage[key].startsWith('storage/')) { |
180 | logger.warn( | 186 | logger.warn( |
@@ -278,6 +284,11 @@ function checkObjectStorageConfig () { | |||
278 | 'Object storage bucket prefixes should be set to different values when the same bucket is used for both types of video.' | 284 | 'Object storage bucket prefixes should be set to different values when the same bucket is used for both types of video.' |
279 | ) | 285 | ) |
280 | } | 286 | } |
287 | |||
288 | if (CONFIG.OBJECT_STORAGE.MAX_UPLOAD_PART > parseBytes('250MB')) { | ||
289 | // eslint-disable-next-line max-len | ||
290 | logger.warn(`Object storage max upload part seems to have a big value (${CONFIG.OBJECT_STORAGE.MAX_UPLOAD_PART} bytes). Consider using a lower one (like 100MB).`) | ||
291 | } | ||
281 | } | 292 | } |
282 | } | 293 | } |
283 | 294 | ||
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts index 39713a266..8b4d49180 100644 --- a/server/initializers/checker-before-init.ts +++ b/server/initializers/checker-before-init.ts | |||
@@ -13,6 +13,7 @@ function checkMissedConfig () { | |||
13 | 'webserver.https', 'webserver.hostname', 'webserver.port', | 13 | 'webserver.https', 'webserver.hostname', 'webserver.port', |
14 | 'secrets.peertube', | 14 | 'secrets.peertube', |
15 | 'trust_proxy', | 15 | 'trust_proxy', |
16 | 'oauth2.token_lifetime.access_token', 'oauth2.token_lifetime.refresh_token', | ||
16 | 'database.hostname', 'database.port', 'database.username', 'database.password', 'database.pool.max', | 17 | 'database.hostname', 'database.port', 'database.username', 'database.password', 'database.pool.max', |
17 | 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address', | 18 | 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address', |
18 | 'email.body.signature', 'email.subject.prefix', | 19 | 'email.body.signature', 'email.subject.prefix', |
@@ -27,7 +28,7 @@ function checkMissedConfig () { | |||
27 | 'csp.enabled', 'csp.report_only', 'csp.report_uri', | 28 | 'csp.enabled', 'csp.report_only', 'csp.report_uri', |
28 | 'security.frameguard.enabled', | 29 | 'security.frameguard.enabled', |
29 | 'cache.previews.size', 'cache.captions.size', 'cache.torrents.size', 'admin.email', 'contact_form.enabled', | 30 | 'cache.previews.size', 'cache.captions.size', 'cache.torrents.size', 'admin.email', 'contact_form.enabled', |
30 | 'signup.enabled', 'signup.limit', 'signup.requires_email_verification', 'signup.minimum_age', | 31 | 'signup.enabled', 'signup.limit', 'signup.requires_approval', 'signup.requires_email_verification', 'signup.minimum_age', |
31 | 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', | 32 | 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', |
32 | 'redundancy.videos.strategies', 'redundancy.videos.check_interval', | 33 | 'redundancy.videos.strategies', 'redundancy.videos.check_interval', |
33 | 'transcoding.enabled', 'transcoding.threads', 'transcoding.allow_additional_extensions', 'transcoding.hls.enabled', | 34 | 'transcoding.enabled', 'transcoding.threads', 'transcoding.allow_additional_extensions', 'transcoding.hls.enabled', |
diff --git a/server/initializers/config.ts b/server/initializers/config.ts index c2f8b19fd..9685e7bfc 100644 --- a/server/initializers/config.ts +++ b/server/initializers/config.ts | |||
@@ -149,6 +149,12 @@ const CONFIG = { | |||
149 | HOSTNAME: config.get<string>('webserver.hostname'), | 149 | HOSTNAME: config.get<string>('webserver.hostname'), |
150 | PORT: config.get<number>('webserver.port') | 150 | PORT: config.get<number>('webserver.port') |
151 | }, | 151 | }, |
152 | OAUTH2: { | ||
153 | TOKEN_LIFETIME: { | ||
154 | ACCESS_TOKEN: parseDurationToMs(config.get<string>('oauth2.token_lifetime.access_token')), | ||
155 | REFRESH_TOKEN: parseDurationToMs(config.get<string>('oauth2.token_lifetime.refresh_token')) | ||
156 | } | ||
157 | }, | ||
152 | RATES_LIMIT: { | 158 | RATES_LIMIT: { |
153 | API: { | 159 | API: { |
154 | WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.api.window')), | 160 | WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.api.window')), |
@@ -299,6 +305,7 @@ const CONFIG = { | |||
299 | }, | 305 | }, |
300 | SIGNUP: { | 306 | SIGNUP: { |
301 | get ENABLED () { return config.get<boolean>('signup.enabled') }, | 307 | get ENABLED () { return config.get<boolean>('signup.enabled') }, |
308 | get REQUIRES_APPROVAL () { return config.get<boolean>('signup.requires_approval') }, | ||
302 | get LIMIT () { return config.get<number>('signup.limit') }, | 309 | get LIMIT () { return config.get<number>('signup.limit') }, |
303 | get REQUIRES_EMAIL_VERIFICATION () { return config.get<boolean>('signup.requires_email_verification') }, | 310 | get REQUIRES_EMAIL_VERIFICATION () { return config.get<boolean>('signup.requires_email_verification') }, |
304 | get MINIMUM_AGE () { return config.get<number>('signup.minimum_age') }, | 311 | get MINIMUM_AGE () { return config.get<number>('signup.minimum_age') }, |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 0e56f0c9f..992c86ed2 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -6,6 +6,7 @@ import { randomInt, root } from '@shared/core-utils' | |||
6 | import { | 6 | import { |
7 | AbuseState, | 7 | AbuseState, |
8 | JobType, | 8 | JobType, |
9 | UserRegistrationState, | ||
9 | VideoChannelSyncState, | 10 | VideoChannelSyncState, |
10 | VideoImportState, | 11 | VideoImportState, |
11 | VideoPrivacy, | 12 | VideoPrivacy, |
@@ -25,7 +26,7 @@ import { CONFIG, registerConfigChangedHandler } from './config' | |||
25 | 26 | ||
26 | // --------------------------------------------------------------------------- | 27 | // --------------------------------------------------------------------------- |
27 | 28 | ||
28 | const LAST_MIGRATION_VERSION = 745 | 29 | const LAST_MIGRATION_VERSION = 755 |
29 | 30 | ||
30 | // --------------------------------------------------------------------------- | 31 | // --------------------------------------------------------------------------- |
31 | 32 | ||
@@ -78,6 +79,8 @@ const SORTABLE_COLUMNS = { | |||
78 | ACCOUNT_FOLLOWERS: [ 'createdAt' ], | 79 | ACCOUNT_FOLLOWERS: [ 'createdAt' ], |
79 | CHANNEL_FOLLOWERS: [ 'createdAt' ], | 80 | CHANNEL_FOLLOWERS: [ 'createdAt' ], |
80 | 81 | ||
82 | USER_REGISTRATIONS: [ 'createdAt', 'state' ], | ||
83 | |||
81 | VIDEOS: [ 'name', 'duration', 'createdAt', 'publishedAt', 'originallyPublishedAt', 'views', 'likes', 'trending', 'hot', 'best' ], | 84 | VIDEOS: [ 'name', 'duration', 'createdAt', 'publishedAt', 'originallyPublishedAt', 'views', 'likes', 'trending', 'hot', 'best' ], |
82 | 85 | ||
83 | // Don't forget to update peertube-search-index with the same values | 86 | // Don't forget to update peertube-search-index with the same values |
@@ -101,11 +104,6 @@ const SORTABLE_COLUMNS = { | |||
101 | VIDEO_REDUNDANCIES: [ 'name' ] | 104 | VIDEO_REDUNDANCIES: [ 'name' ] |
102 | } | 105 | } |
103 | 106 | ||
104 | const OAUTH_LIFETIME = { | ||
105 | ACCESS_TOKEN: 3600 * 24, // 1 day, for upload | ||
106 | REFRESH_TOKEN: 1209600 // 2 weeks | ||
107 | } | ||
108 | |||
109 | const ROUTE_CACHE_LIFETIME = { | 107 | const ROUTE_CACHE_LIFETIME = { |
110 | FEEDS: '15 minutes', | 108 | FEEDS: '15 minutes', |
111 | ROBOTS: '2 hours', | 109 | ROBOTS: '2 hours', |
@@ -295,6 +293,10 @@ const CONSTRAINTS_FIELDS = { | |||
295 | ABUSE_MESSAGES: { | 293 | ABUSE_MESSAGES: { |
296 | MESSAGE: { min: 2, max: 3000 } // Length | 294 | MESSAGE: { min: 2, max: 3000 } // Length |
297 | }, | 295 | }, |
296 | USER_REGISTRATIONS: { | ||
297 | REASON_MESSAGE: { min: 2, max: 3000 }, // Length | ||
298 | MODERATOR_MESSAGE: { min: 2, max: 3000 } // Length | ||
299 | }, | ||
298 | VIDEO_BLACKLIST: { | 300 | VIDEO_BLACKLIST: { |
299 | REASON: { min: 2, max: 300 } // Length | 301 | REASON: { min: 2, max: 300 } // Length |
300 | }, | 302 | }, |
@@ -521,6 +523,12 @@ const ABUSE_STATES: { [ id in AbuseState ]: string } = { | |||
521 | [AbuseState.ACCEPTED]: 'Accepted' | 523 | [AbuseState.ACCEPTED]: 'Accepted' |
522 | } | 524 | } |
523 | 525 | ||
526 | const USER_REGISTRATION_STATES: { [ id in UserRegistrationState ]: string } = { | ||
527 | [UserRegistrationState.PENDING]: 'Pending', | ||
528 | [UserRegistrationState.REJECTED]: 'Rejected', | ||
529 | [UserRegistrationState.ACCEPTED]: 'Accepted' | ||
530 | } | ||
531 | |||
524 | const VIDEO_PLAYLIST_PRIVACIES: { [ id in VideoPlaylistPrivacy ]: string } = { | 532 | const VIDEO_PLAYLIST_PRIVACIES: { [ id in VideoPlaylistPrivacy ]: string } = { |
525 | [VideoPlaylistPrivacy.PUBLIC]: 'Public', | 533 | [VideoPlaylistPrivacy.PUBLIC]: 'Public', |
526 | [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted', | 534 | [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted', |
@@ -665,7 +673,7 @@ const USER_PASSWORD_CREATE_LIFETIME = 60000 * 60 * 24 * 7 // 7 days | |||
665 | 673 | ||
666 | const TWO_FACTOR_AUTH_REQUEST_TOKEN_LIFETIME = 60000 * 10 // 10 minutes | 674 | const TWO_FACTOR_AUTH_REQUEST_TOKEN_LIFETIME = 60000 * 10 // 10 minutes |
667 | 675 | ||
668 | const USER_EMAIL_VERIFY_LIFETIME = 60000 * 60 // 60 minutes | 676 | const EMAIL_VERIFY_LIFETIME = 60000 * 60 // 60 minutes |
669 | 677 | ||
670 | const NSFW_POLICY_TYPES: { [ id: string ]: NSFWPolicyType } = { | 678 | const NSFW_POLICY_TYPES: { [ id: string ]: NSFWPolicyType } = { |
671 | DO_NOT_LIST: 'do_not_list', | 679 | DO_NOT_LIST: 'do_not_list', |
@@ -781,6 +789,9 @@ const LRU_CACHE = { | |||
781 | VIDEO_TOKENS: { | 789 | VIDEO_TOKENS: { |
782 | MAX_SIZE: 100_000, | 790 | MAX_SIZE: 100_000, |
783 | TTL: parseDurationToMs('8 hours') | 791 | TTL: parseDurationToMs('8 hours') |
792 | }, | ||
793 | TRACKER_IPS: { | ||
794 | MAX_SIZE: 100_000 | ||
784 | } | 795 | } |
785 | } | 796 | } |
786 | 797 | ||
@@ -884,7 +895,7 @@ const TRACKER_RATE_LIMITS = { | |||
884 | INTERVAL: 60000 * 5, // 5 minutes | 895 | INTERVAL: 60000 * 5, // 5 minutes |
885 | ANNOUNCES_PER_IP_PER_INFOHASH: 15, // maximum announces per torrent in the interval | 896 | ANNOUNCES_PER_IP_PER_INFOHASH: 15, // maximum announces per torrent in the interval |
886 | ANNOUNCES_PER_IP: 30, // maximum announces for all our torrents in the interval | 897 | ANNOUNCES_PER_IP: 30, // maximum announces for all our torrents in the interval |
887 | BLOCK_IP_LIFETIME: 60000 * 3 // 3 minutes | 898 | BLOCK_IP_LIFETIME: parseDurationToMs('3 minutes') |
888 | } | 899 | } |
889 | 900 | ||
890 | const P2P_MEDIA_LOADER_PEER_VERSION = 2 | 901 | const P2P_MEDIA_LOADER_PEER_VERSION = 2 |
@@ -1030,7 +1041,6 @@ export { | |||
1030 | JOB_ATTEMPTS, | 1041 | JOB_ATTEMPTS, |
1031 | AP_CLEANER, | 1042 | AP_CLEANER, |
1032 | LAST_MIGRATION_VERSION, | 1043 | LAST_MIGRATION_VERSION, |
1033 | OAUTH_LIFETIME, | ||
1034 | CUSTOM_HTML_TAG_COMMENTS, | 1044 | CUSTOM_HTML_TAG_COMMENTS, |
1035 | STATS_TIMESERIE, | 1045 | STATS_TIMESERIE, |
1036 | BROADCAST_CONCURRENCY, | 1046 | BROADCAST_CONCURRENCY, |
@@ -1072,13 +1082,14 @@ export { | |||
1072 | VIDEO_TRANSCODING_FPS, | 1082 | VIDEO_TRANSCODING_FPS, |
1073 | FFMPEG_NICE, | 1083 | FFMPEG_NICE, |
1074 | ABUSE_STATES, | 1084 | ABUSE_STATES, |
1085 | USER_REGISTRATION_STATES, | ||
1075 | LRU_CACHE, | 1086 | LRU_CACHE, |
1076 | REQUEST_TIMEOUTS, | 1087 | REQUEST_TIMEOUTS, |
1077 | MAX_LOCAL_VIEWER_WATCH_SECTIONS, | 1088 | MAX_LOCAL_VIEWER_WATCH_SECTIONS, |
1078 | USER_PASSWORD_RESET_LIFETIME, | 1089 | USER_PASSWORD_RESET_LIFETIME, |
1079 | USER_PASSWORD_CREATE_LIFETIME, | 1090 | USER_PASSWORD_CREATE_LIFETIME, |
1080 | MEMOIZE_TTL, | 1091 | MEMOIZE_TTL, |
1081 | USER_EMAIL_VERIFY_LIFETIME, | 1092 | EMAIL_VERIFY_LIFETIME, |
1082 | OVERVIEWS, | 1093 | OVERVIEWS, |
1083 | SCHEDULER_INTERVALS_MS, | 1094 | SCHEDULER_INTERVALS_MS, |
1084 | REPEAT_JOBS, | 1095 | REPEAT_JOBS, |
diff --git a/server/initializers/database.ts b/server/initializers/database.ts index f55f40df0..96145f489 100644 --- a/server/initializers/database.ts +++ b/server/initializers/database.ts | |||
@@ -5,7 +5,9 @@ import { TrackerModel } from '@server/models/server/tracker' | |||
5 | import { VideoTrackerModel } from '@server/models/server/video-tracker' | 5 | import { VideoTrackerModel } from '@server/models/server/video-tracker' |
6 | import { UserModel } from '@server/models/user/user' | 6 | import { UserModel } from '@server/models/user/user' |
7 | import { UserNotificationModel } from '@server/models/user/user-notification' | 7 | import { UserNotificationModel } from '@server/models/user/user-notification' |
8 | import { UserRegistrationModel } from '@server/models/user/user-registration' | ||
8 | import { UserVideoHistoryModel } from '@server/models/user/user-video-history' | 9 | import { UserVideoHistoryModel } from '@server/models/user/user-video-history' |
10 | import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync' | ||
9 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' | 11 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' |
10 | import { VideoLiveSessionModel } from '@server/models/video/video-live-session' | 12 | import { VideoLiveSessionModel } from '@server/models/video/video-live-session' |
11 | import { VideoSourceModel } from '@server/models/video/video-source' | 13 | import { VideoSourceModel } from '@server/models/video/video-source' |
@@ -50,7 +52,6 @@ import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-pla | |||
50 | import { VideoTagModel } from '../models/video/video-tag' | 52 | import { VideoTagModel } from '../models/video/video-tag' |
51 | import { VideoViewModel } from '../models/view/video-view' | 53 | import { VideoViewModel } from '../models/view/video-view' |
52 | import { CONFIG } from './config' | 54 | import { CONFIG } from './config' |
53 | import { VideoChannelSyncModel } from '@server/models/video/video-channel-sync' | ||
54 | 55 | ||
55 | require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string | 56 | require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string |
56 | 57 | ||
@@ -155,7 +156,8 @@ async function initDatabaseModels (silent: boolean) { | |||
155 | PluginModel, | 156 | PluginModel, |
156 | ActorCustomPageModel, | 157 | ActorCustomPageModel, |
157 | VideoJobInfoModel, | 158 | VideoJobInfoModel, |
158 | VideoChannelSyncModel | 159 | VideoChannelSyncModel, |
160 | UserRegistrationModel | ||
159 | ]) | 161 | ]) |
160 | 162 | ||
161 | // Check extensions exist in the database | 163 | // Check extensions exist in the database |
diff --git a/server/initializers/installer.ts b/server/initializers/installer.ts index f5d8eedf1..f48f348a7 100644 --- a/server/initializers/installer.ts +++ b/server/initializers/installer.ts | |||
@@ -51,8 +51,7 @@ function removeCacheAndTmpDirectories () { | |||
51 | const tasks: Promise<any>[] = [] | 51 | const tasks: Promise<any>[] = [] |
52 | 52 | ||
53 | // Cache directories | 53 | // Cache directories |
54 | for (const key of Object.keys(cacheDirectories)) { | 54 | for (const dir of cacheDirectories) { |
55 | const dir = cacheDirectories[key] | ||
56 | tasks.push(removeDirectoryOrContent(dir)) | 55 | tasks.push(removeDirectoryOrContent(dir)) |
57 | } | 56 | } |
58 | 57 | ||
@@ -87,8 +86,7 @@ function createDirectoriesIfNotExist () { | |||
87 | } | 86 | } |
88 | 87 | ||
89 | // Cache directories | 88 | // Cache directories |
90 | for (const key of Object.keys(cacheDirectories)) { | 89 | for (const dir of cacheDirectories) { |
91 | const dir = cacheDirectories[key] | ||
92 | tasks.push(ensureDir(dir)) | 90 | tasks.push(ensureDir(dir)) |
93 | } | 91 | } |
94 | 92 | ||
diff --git a/server/initializers/migrations/0750-user-registration.ts b/server/initializers/migrations/0750-user-registration.ts new file mode 100644 index 000000000..15bbfd3fd --- /dev/null +++ b/server/initializers/migrations/0750-user-registration.ts | |||
@@ -0,0 +1,58 @@ | |||
1 | |||
2 | import * as Sequelize from 'sequelize' | ||
3 | |||
4 | async function up (utils: { | ||
5 | transaction: Sequelize.Transaction | ||
6 | queryInterface: Sequelize.QueryInterface | ||
7 | sequelize: Sequelize.Sequelize | ||
8 | db: any | ||
9 | }): Promise<void> { | ||
10 | { | ||
11 | const query = ` | ||
12 | CREATE TABLE IF NOT EXISTS "userRegistration" ( | ||
13 | "id" serial, | ||
14 | "state" integer NOT NULL, | ||
15 | "registrationReason" text NOT NULL, | ||
16 | "moderationResponse" text, | ||
17 | "password" varchar(255), | ||
18 | "username" varchar(255) NOT NULL, | ||
19 | "email" varchar(400) NOT NULL, | ||
20 | "emailVerified" boolean, | ||
21 | "accountDisplayName" varchar(255), | ||
22 | "channelHandle" varchar(255), | ||
23 | "channelDisplayName" varchar(255), | ||
24 | "userId" integer REFERENCES "user" ("id") ON DELETE SET NULL ON UPDATE CASCADE, | ||
25 | "createdAt" timestamp with time zone NOT NULL, | ||
26 | "updatedAt" timestamp with time zone NOT NULL, | ||
27 | PRIMARY KEY ("id") | ||
28 | ); | ||
29 | ` | ||
30 | await utils.sequelize.query(query, { transaction: utils.transaction }) | ||
31 | } | ||
32 | |||
33 | { | ||
34 | await utils.queryInterface.addColumn('userNotification', 'userRegistrationId', { | ||
35 | type: Sequelize.INTEGER, | ||
36 | defaultValue: null, | ||
37 | allowNull: true, | ||
38 | references: { | ||
39 | model: 'userRegistration', | ||
40 | key: 'id' | ||
41 | }, | ||
42 | onUpdate: 'CASCADE', | ||
43 | onDelete: 'SET NULL' | ||
44 | }, { transaction: utils.transaction }) | ||
45 | } | ||
46 | } | ||
47 | |||
48 | async function down (utils: { | ||
49 | queryInterface: Sequelize.QueryInterface | ||
50 | transaction: Sequelize.Transaction | ||
51 | }) { | ||
52 | await utils.queryInterface.dropTable('videoChannelSync', { transaction: utils.transaction }) | ||
53 | } | ||
54 | |||
55 | export { | ||
56 | up, | ||
57 | down | ||
58 | } | ||
diff --git a/server/initializers/migrations/0755-unique-viewer-url.ts b/server/initializers/migrations/0755-unique-viewer-url.ts new file mode 100644 index 000000000..b3dff9258 --- /dev/null +++ b/server/initializers/migrations/0755-unique-viewer-url.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import * as Sequelize from 'sequelize' | ||
2 | |||
3 | async function up (utils: { | ||
4 | transaction: Sequelize.Transaction | ||
5 | queryInterface: Sequelize.QueryInterface | ||
6 | sequelize: Sequelize.Sequelize | ||
7 | db: any | ||
8 | }): Promise<void> { | ||
9 | const { transaction } = utils | ||
10 | |||
11 | const query = 'DELETE FROM "localVideoViewer" t1 ' + | ||
12 | 'USING (SELECT MIN(id) as id, "url" FROM "localVideoViewer" GROUP BY "url" HAVING COUNT(*) > 1) t2 ' + | ||
13 | 'WHERE t1."url" = t2."url" AND t1.id <> t2.id' | ||
14 | |||
15 | await utils.sequelize.query(query, { transaction }) | ||
16 | } | ||
17 | |||
18 | async function down (utils: { | ||
19 | queryInterface: Sequelize.QueryInterface | ||
20 | transaction: Sequelize.Transaction | ||
21 | }) { | ||
22 | } | ||
23 | |||
24 | export { | ||
25 | up, | ||
26 | down | ||
27 | } | ||