diff options
Diffstat (limited to 'server/initializers')
11 files changed, 386 insertions, 44 deletions
diff --git a/server/initializers/checker-after-init.ts b/server/initializers/checker-after-init.ts index 72d846957..955d55206 100644 --- a/server/initializers/checker-after-init.ts +++ b/server/initializers/checker-after-init.ts | |||
@@ -10,6 +10,7 @@ import { getServerActor } from '../helpers/utils' | |||
10 | import { RecentlyAddedStrategy } from '../../shared/models/redundancy' | 10 | import { RecentlyAddedStrategy } from '../../shared/models/redundancy' |
11 | import { isArray } from '../helpers/custom-validators/misc' | 11 | import { isArray } from '../helpers/custom-validators/misc' |
12 | import { uniq } from 'lodash' | 12 | import { uniq } from 'lodash' |
13 | import { Emailer } from '../lib/emailer' | ||
13 | 14 | ||
14 | async function checkActivityPubUrls () { | 15 | async function checkActivityPubUrls () { |
15 | const actor = await getServerActor() | 16 | const actor = await getServerActor() |
@@ -32,9 +33,19 @@ async function checkActivityPubUrls () { | |||
32 | // Some checks on configuration files | 33 | // Some checks on configuration files |
33 | // Return an error message, or null if everything is okay | 34 | // Return an error message, or null if everything is okay |
34 | function checkConfig () { | 35 | function checkConfig () { |
35 | const defaultNSFWPolicy = CONFIG.INSTANCE.DEFAULT_NSFW_POLICY | 36 | |
37 | if (!Emailer.isEnabled()) { | ||
38 | if (CONFIG.SIGNUP.ENABLED && CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) { | ||
39 | return 'Emailer is disabled but you require signup email verification.' | ||
40 | } | ||
41 | |||
42 | if (CONFIG.CONTACT_FORM.ENABLED) { | ||
43 | logger.warn('Emailer is disabled so the contact form will not work.') | ||
44 | } | ||
45 | } | ||
36 | 46 | ||
37 | // NSFW policy | 47 | // NSFW policy |
48 | const defaultNSFWPolicy = CONFIG.INSTANCE.DEFAULT_NSFW_POLICY | ||
38 | { | 49 | { |
39 | const available = [ 'do_not_list', 'blur', 'display' ] | 50 | const available = [ 'do_not_list', 'blur', 'display' ] |
40 | if (available.indexOf(defaultNSFWPolicy) === -1) { | 51 | if (available.indexOf(defaultNSFWPolicy) === -1) { |
@@ -68,6 +79,7 @@ function checkConfig () { | |||
68 | } | 79 | } |
69 | } | 80 | } |
70 | 81 | ||
82 | // Check storage directory locations | ||
71 | if (isProdInstance()) { | 83 | if (isProdInstance()) { |
72 | const configStorage = config.get('storage') | 84 | const configStorage = config.get('storage') |
73 | for (const key of Object.keys(configStorage)) { | 85 | for (const key of Object.keys(configStorage)) { |
diff --git a/server/initializers/checker-before-init.ts b/server/initializers/checker-before-init.ts index 9dfb5d68c..7905d9ffa 100644 --- a/server/initializers/checker-before-init.ts +++ b/server/initializers/checker-before-init.ts | |||
@@ -12,13 +12,14 @@ function checkMissedConfig () { | |||
12 | 'database.hostname', 'database.port', 'database.suffix', 'database.username', 'database.password', 'database.pool.max', | 12 | 'database.hostname', 'database.port', 'database.suffix', 'database.username', 'database.password', 'database.pool.max', |
13 | 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address', | 13 | 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address', |
14 | 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache', | 14 | 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache', |
15 | 'storage.redundancy', 'storage.tmp', | ||
15 | 'log.level', | 16 | 'log.level', |
16 | 'user.video_quota', 'user.video_quota_daily', | 17 | 'user.video_quota', 'user.video_quota_daily', |
17 | 'cache.previews.size', 'admin.email', | 18 | 'cache.previews.size', 'admin.email', 'contact_form.enabled', |
18 | 'signup.enabled', 'signup.limit', 'signup.requires_email_verification', | 19 | 'signup.enabled', 'signup.limit', 'signup.requires_email_verification', |
19 | 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', | 20 | 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', |
20 | 'redundancy.videos.strategies', 'redundancy.videos.check_interval', | 21 | 'redundancy.videos.strategies', 'redundancy.videos.check_interval', |
21 | 'transcoding.enabled', 'transcoding.threads', | 22 | 'transcoding.enabled', 'transcoding.threads', 'transcoding.allow_additional_extensions', |
22 | 'import.videos.http.enabled', 'import.videos.torrent.enabled', | 23 | 'import.videos.http.enabled', 'import.videos.torrent.enabled', |
23 | 'trending.videos.interval_days', | 24 | 'trending.videos.interval_days', |
24 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', | 25 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index aa243859c..6f3ebb9aa 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -16,7 +16,7 @@ let config: IConfig = require('config') | |||
16 | 16 | ||
17 | // --------------------------------------------------------------------------- | 17 | // --------------------------------------------------------------------------- |
18 | 18 | ||
19 | const LAST_MIGRATION_VERSION = 290 | 19 | const LAST_MIGRATION_VERSION = 325 |
20 | 20 | ||
21 | // --------------------------------------------------------------------------- | 21 | // --------------------------------------------------------------------------- |
22 | 22 | ||
@@ -50,7 +50,9 @@ const SORTABLE_COLUMNS = { | |||
50 | VIDEO_CHANNELS_SEARCH: [ 'match', 'displayName', 'createdAt' ], | 50 | VIDEO_CHANNELS_SEARCH: [ 'match', 'displayName', 'createdAt' ], |
51 | 51 | ||
52 | ACCOUNTS_BLOCKLIST: [ 'createdAt' ], | 52 | ACCOUNTS_BLOCKLIST: [ 'createdAt' ], |
53 | SERVERS_BLOCKLIST: [ 'createdAt' ] | 53 | SERVERS_BLOCKLIST: [ 'createdAt' ], |
54 | |||
55 | USER_NOTIFICATIONS: [ 'createdAt' ] | ||
54 | } | 56 | } |
55 | 57 | ||
56 | const OAUTH_LIFETIME = { | 58 | const OAUTH_LIFETIME = { |
@@ -61,6 +63,7 @@ const OAUTH_LIFETIME = { | |||
61 | const ROUTE_CACHE_LIFETIME = { | 63 | const ROUTE_CACHE_LIFETIME = { |
62 | FEEDS: '15 minutes', | 64 | FEEDS: '15 minutes', |
63 | ROBOTS: '2 hours', | 65 | ROBOTS: '2 hours', |
66 | SITEMAP: '1 day', | ||
64 | SECURITYTXT: '2 hours', | 67 | SECURITYTXT: '2 hours', |
65 | NODEINFO: '10 minutes', | 68 | NODEINFO: '10 minutes', |
66 | DNT_POLICY: '1 week', | 69 | DNT_POLICY: '1 week', |
@@ -143,7 +146,7 @@ const VIDEO_IMPORT_TIMEOUT = 1000 * 3600 // 1 hour | |||
143 | 146 | ||
144 | // 1 hour | 147 | // 1 hour |
145 | let SCHEDULER_INTERVALS_MS = { | 148 | let SCHEDULER_INTERVALS_MS = { |
146 | badActorFollow: 60000 * 60, // 1 hour | 149 | actorFollowScores: 60000 * 60, // 1 hour |
147 | removeOldJobs: 60000 * 60, // 1 hour | 150 | removeOldJobs: 60000 * 60, // 1 hour |
148 | updateVideos: 60000, // 1 minute | 151 | updateVideos: 60000, // 1 minute |
149 | youtubeDLUpdate: 60000 * 60 * 24 // 1 day | 152 | youtubeDLUpdate: 60000 * 60 * 24 // 1 day |
@@ -185,9 +188,11 @@ const CONFIG = { | |||
185 | FROM_ADDRESS: config.get<string>('smtp.from_address') | 188 | FROM_ADDRESS: config.get<string>('smtp.from_address') |
186 | }, | 189 | }, |
187 | STORAGE: { | 190 | STORAGE: { |
191 | TMP_DIR: buildPath(config.get<string>('storage.tmp')), | ||
188 | AVATARS_DIR: buildPath(config.get<string>('storage.avatars')), | 192 | AVATARS_DIR: buildPath(config.get<string>('storage.avatars')), |
189 | LOG_DIR: buildPath(config.get<string>('storage.logs')), | 193 | LOG_DIR: buildPath(config.get<string>('storage.logs')), |
190 | VIDEOS_DIR: buildPath(config.get<string>('storage.videos')), | 194 | VIDEOS_DIR: buildPath(config.get<string>('storage.videos')), |
195 | REDUNDANCY_DIR: buildPath(config.get<string>('storage.redundancy')), | ||
191 | THUMBNAILS_DIR: buildPath(config.get<string>('storage.thumbnails')), | 196 | THUMBNAILS_DIR: buildPath(config.get<string>('storage.thumbnails')), |
192 | PREVIEWS_DIR: buildPath(config.get<string>('storage.previews')), | 197 | PREVIEWS_DIR: buildPath(config.get<string>('storage.previews')), |
193 | CAPTIONS_DIR: buildPath(config.get<string>('storage.captions')), | 198 | CAPTIONS_DIR: buildPath(config.get<string>('storage.captions')), |
@@ -226,6 +231,9 @@ const CONFIG = { | |||
226 | ADMIN: { | 231 | ADMIN: { |
227 | get EMAIL () { return config.get<string>('admin.email') } | 232 | get EMAIL () { return config.get<string>('admin.email') } |
228 | }, | 233 | }, |
234 | CONTACT_FORM: { | ||
235 | get ENABLED () { return config.get<boolean>('contact_form.enabled') } | ||
236 | }, | ||
229 | SIGNUP: { | 237 | SIGNUP: { |
230 | get ENABLED () { return config.get<boolean>('signup.enabled') }, | 238 | get ENABLED () { return config.get<boolean>('signup.enabled') }, |
231 | get LIMIT () { return config.get<number>('signup.limit') }, | 239 | get LIMIT () { return config.get<number>('signup.limit') }, |
@@ -243,6 +251,7 @@ const CONFIG = { | |||
243 | }, | 251 | }, |
244 | TRANSCODING: { | 252 | TRANSCODING: { |
245 | get ENABLED () { return config.get<boolean>('transcoding.enabled') }, | 253 | get ENABLED () { return config.get<boolean>('transcoding.enabled') }, |
254 | get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') }, | ||
246 | get THREADS () { return config.get<number>('transcoding.threads') }, | 255 | get THREADS () { return config.get<number>('transcoding.threads') }, |
247 | RESOLUTIONS: { | 256 | RESOLUTIONS: { |
248 | get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') }, | 257 | get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') }, |
@@ -286,6 +295,7 @@ const CONFIG = { | |||
286 | get SECURITYTXT_CONTACT () { return config.get<string>('admin.email') } | 295 | get SECURITYTXT_CONTACT () { return config.get<string>('admin.email') } |
287 | }, | 296 | }, |
288 | SERVICES: { | 297 | SERVICES: { |
298 | get 'CSP-LOGGER' () { return config.get<string>('services.csp-logger') }, | ||
289 | TWITTER: { | 299 | TWITTER: { |
290 | get USERNAME () { return config.get<string>('services.twitter.username') }, | 300 | get USERNAME () { return config.get<string>('services.twitter.username') }, |
291 | get WHITELISTED () { return config.get<boolean>('services.twitter.whitelisted') } | 301 | get WHITELISTED () { return config.get<boolean>('services.twitter.whitelisted') } |
@@ -295,25 +305,25 @@ const CONFIG = { | |||
295 | 305 | ||
296 | // --------------------------------------------------------------------------- | 306 | // --------------------------------------------------------------------------- |
297 | 307 | ||
298 | const CONSTRAINTS_FIELDS = { | 308 | let CONSTRAINTS_FIELDS = { |
299 | USERS: { | 309 | USERS: { |
300 | NAME: { min: 3, max: 120 }, // Length | 310 | NAME: { min: 1, max: 120 }, // Length |
301 | DESCRIPTION: { min: 3, max: 1000 }, // Length | 311 | DESCRIPTION: { min: 3, max: 1000 }, // Length |
302 | USERNAME: { min: 3, max: 20 }, // Length | 312 | USERNAME: { min: 1, max: 50 }, // Length |
303 | PASSWORD: { min: 6, max: 255 }, // Length | 313 | PASSWORD: { min: 6, max: 255 }, // Length |
304 | VIDEO_QUOTA: { min: -1 }, | 314 | VIDEO_QUOTA: { min: -1 }, |
305 | VIDEO_QUOTA_DAILY: { min: -1 }, | 315 | VIDEO_QUOTA_DAILY: { min: -1 }, |
306 | BLOCKED_REASON: { min: 3, max: 250 } // Length | 316 | BLOCKED_REASON: { min: 3, max: 250 } // Length |
307 | }, | 317 | }, |
308 | VIDEO_ABUSES: { | 318 | VIDEO_ABUSES: { |
309 | REASON: { min: 2, max: 300 }, // Length | 319 | REASON: { min: 2, max: 3000 }, // Length |
310 | MODERATION_COMMENT: { min: 2, max: 300 } // Length | 320 | MODERATION_COMMENT: { min: 2, max: 3000 } // Length |
311 | }, | 321 | }, |
312 | VIDEO_BLACKLIST: { | 322 | VIDEO_BLACKLIST: { |
313 | REASON: { min: 2, max: 300 } // Length | 323 | REASON: { min: 2, max: 300 } // Length |
314 | }, | 324 | }, |
315 | VIDEO_CHANNELS: { | 325 | VIDEO_CHANNELS: { |
316 | NAME: { min: 3, max: 120 }, // Length | 326 | NAME: { min: 1, max: 120 }, // Length |
317 | DESCRIPTION: { min: 3, max: 1000 }, // Length | 327 | DESCRIPTION: { min: 3, max: 1000 }, // Length |
318 | SUPPORT: { min: 3, max: 1000 }, // Length | 328 | SUPPORT: { min: 3, max: 1000 }, // Length |
319 | URL: { min: 3, max: 2000 } // Length | 329 | URL: { min: 3, max: 2000 } // Length |
@@ -354,7 +364,7 @@ const CONSTRAINTS_FIELDS = { | |||
354 | max: 2 * 1024 * 1024 // 2MB | 364 | max: 2 * 1024 * 1024 // 2MB |
355 | } | 365 | } |
356 | }, | 366 | }, |
357 | EXTNAME: [ '.mp4', '.ogv', '.webm' ], | 367 | EXTNAME: buildVideosExtname(), |
358 | INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2 | 368 | INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2 |
359 | DURATION: { min: 0 }, // Number | 369 | DURATION: { min: 0 }, // Number |
360 | TAGS: { min: 0, max: 5 }, // Number of total tags | 370 | TAGS: { min: 0, max: 5 }, // Number of total tags |
@@ -387,6 +397,10 @@ const CONSTRAINTS_FIELDS = { | |||
387 | }, | 397 | }, |
388 | VIDEO_SHARE: { | 398 | VIDEO_SHARE: { |
389 | URL: { min: 3, max: 2000 } // Length | 399 | URL: { min: 3, max: 2000 } // Length |
400 | }, | ||
401 | CONTACT_FORM: { | ||
402 | FROM_NAME: { min: 1, max: 120 }, // Length | ||
403 | BODY: { min: 3, max: 5000 } // Length | ||
390 | } | 404 | } |
391 | } | 405 | } |
392 | 406 | ||
@@ -402,6 +416,8 @@ const RATES_LIMIT = { | |||
402 | } | 416 | } |
403 | 417 | ||
404 | let VIDEO_VIEW_LIFETIME = 60000 * 60 // 1 hour | 418 | let VIDEO_VIEW_LIFETIME = 60000 * 60 // 1 hour |
419 | let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour | ||
420 | |||
405 | const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { | 421 | const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { |
406 | MIN: 10, | 422 | MIN: 10, |
407 | AVERAGE: 30, | 423 | AVERAGE: 30, |
@@ -477,27 +493,31 @@ const VIDEO_ABUSE_STATES = { | |||
477 | [VideoAbuseState.ACCEPTED]: 'Accepted' | 493 | [VideoAbuseState.ACCEPTED]: 'Accepted' |
478 | } | 494 | } |
479 | 495 | ||
480 | const VIDEO_MIMETYPE_EXT = { | 496 | const MIMETYPES = { |
481 | 'video/webm': '.webm', | 497 | VIDEO: { |
482 | 'video/ogg': '.ogv', | 498 | MIMETYPE_EXT: buildVideoMimetypeExt(), |
483 | 'video/mp4': '.mp4' | 499 | EXT_MIMETYPE: null as { [ id: string ]: string } |
484 | } | 500 | }, |
485 | const VIDEO_EXT_MIMETYPE = invert(VIDEO_MIMETYPE_EXT) | 501 | IMAGE: { |
486 | 502 | MIMETYPE_EXT: { | |
487 | const IMAGE_MIMETYPE_EXT = { | 503 | 'image/png': '.png', |
488 | 'image/png': '.png', | 504 | 'image/jpg': '.jpg', |
489 | 'image/jpg': '.jpg', | 505 | 'image/jpeg': '.jpg' |
490 | 'image/jpeg': '.jpg' | 506 | } |
491 | } | 507 | }, |
492 | 508 | VIDEO_CAPTIONS: { | |
493 | const VIDEO_CAPTIONS_MIMETYPE_EXT = { | 509 | MIMETYPE_EXT: { |
494 | 'text/vtt': '.vtt', | 510 | 'text/vtt': '.vtt', |
495 | 'application/x-subrip': '.srt' | 511 | 'application/x-subrip': '.srt' |
496 | } | 512 | } |
497 | 513 | }, | |
498 | const TORRENT_MIMETYPE_EXT = { | 514 | TORRENT: { |
499 | 'application/x-bittorrent': '.torrent' | 515 | MIMETYPE_EXT: { |
516 | 'application/x-bittorrent': '.torrent' | ||
517 | } | ||
518 | } | ||
500 | } | 519 | } |
520 | MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT) | ||
501 | 521 | ||
502 | // --------------------------------------------------------------------------- | 522 | // --------------------------------------------------------------------------- |
503 | 523 | ||
@@ -523,7 +543,7 @@ const ACTIVITY_PUB = { | |||
523 | COLLECTION_ITEMS_PER_PAGE: 10, | 543 | COLLECTION_ITEMS_PER_PAGE: 10, |
524 | FETCH_PAGE_LIMIT: 100, | 544 | FETCH_PAGE_LIMIT: 100, |
525 | URL_MIME_TYPES: { | 545 | URL_MIME_TYPES: { |
526 | VIDEO: Object.keys(VIDEO_MIMETYPE_EXT), | 546 | VIDEO: Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT), |
527 | TORRENT: [ 'application/x-bittorrent' ], | 547 | TORRENT: [ 'application/x-bittorrent' ], |
528 | MAGNET: [ 'application/x-bittorrent;x-scheme-handler/magnet' ] | 548 | MAGNET: [ 'application/x-bittorrent;x-scheme-handler/magnet' ] |
529 | }, | 549 | }, |
@@ -569,6 +589,7 @@ const STATIC_PATHS = { | |||
569 | THUMBNAILS: '/static/thumbnails/', | 589 | THUMBNAILS: '/static/thumbnails/', |
570 | TORRENTS: '/static/torrents/', | 590 | TORRENTS: '/static/torrents/', |
571 | WEBSEED: '/static/webseed/', | 591 | WEBSEED: '/static/webseed/', |
592 | REDUNDANCY: '/static/redundancy/', | ||
572 | AVATARS: '/static/avatars/', | 593 | AVATARS: '/static/avatars/', |
573 | VIDEO_CAPTIONS: '/static/video-captions/' | 594 | VIDEO_CAPTIONS: '/static/video-captions/' |
574 | } | 595 | } |
@@ -665,7 +686,7 @@ if (isTestInstance() === true) { | |||
665 | 686 | ||
666 | CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max = 100 * 1024 // 100KB | 687 | CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max = 100 * 1024 // 100KB |
667 | 688 | ||
668 | SCHEDULER_INTERVALS_MS.badActorFollow = 10000 | 689 | SCHEDULER_INTERVALS_MS.actorFollowScores = 1000 |
669 | SCHEDULER_INTERVALS_MS.removeOldJobs = 10000 | 690 | SCHEDULER_INTERVALS_MS.removeOldJobs = 10000 |
670 | SCHEDULER_INTERVALS_MS.updateVideos = 5000 | 691 | SCHEDULER_INTERVALS_MS.updateVideos = 5000 |
671 | REPEAT_JOBS['videos-views'] = { every: 5000 } | 692 | REPEAT_JOBS['videos-views'] = { every: 5000 } |
@@ -673,6 +694,7 @@ if (isTestInstance() === true) { | |||
673 | REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 | 694 | REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 |
674 | 695 | ||
675 | VIDEO_VIEW_LIFETIME = 1000 // 1 second | 696 | VIDEO_VIEW_LIFETIME = 1000 // 1 second |
697 | CONTACT_FORM_LIFETIME = 1000 // 1 second | ||
676 | 698 | ||
677 | JOB_ATTEMPTS['email'] = 1 | 699 | JOB_ATTEMPTS['email'] = 1 |
678 | 700 | ||
@@ -681,13 +703,12 @@ if (isTestInstance() === true) { | |||
681 | ROUTE_CACHE_LIFETIME.OVERVIEWS.VIDEOS = '0ms' | 703 | ROUTE_CACHE_LIFETIME.OVERVIEWS.VIDEOS = '0ms' |
682 | } | 704 | } |
683 | 705 | ||
684 | updateWebserverConfig() | 706 | updateWebserverUrls() |
685 | 707 | ||
686 | // --------------------------------------------------------------------------- | 708 | // --------------------------------------------------------------------------- |
687 | 709 | ||
688 | export { | 710 | export { |
689 | API_VERSION, | 711 | API_VERSION, |
690 | VIDEO_CAPTIONS_MIMETYPE_EXT, | ||
691 | AVATARS_SIZE, | 712 | AVATARS_SIZE, |
692 | ACCEPT_HEADERS, | 713 | ACCEPT_HEADERS, |
693 | BCRYPT_SALT_SIZE, | 714 | BCRYPT_SALT_SIZE, |
@@ -715,7 +736,6 @@ export { | |||
715 | FEEDS, | 736 | FEEDS, |
716 | JOB_TTL, | 737 | JOB_TTL, |
717 | NSFW_POLICY_TYPES, | 738 | NSFW_POLICY_TYPES, |
718 | TORRENT_MIMETYPE_EXT, | ||
719 | STATIC_MAX_AGE, | 739 | STATIC_MAX_AGE, |
720 | STATIC_PATHS, | 740 | STATIC_PATHS, |
721 | VIDEO_IMPORT_TIMEOUT, | 741 | VIDEO_IMPORT_TIMEOUT, |
@@ -728,7 +748,6 @@ export { | |||
728 | VIDEO_LICENCES, | 748 | VIDEO_LICENCES, |
729 | VIDEO_STATES, | 749 | VIDEO_STATES, |
730 | VIDEO_RATE_TYPES, | 750 | VIDEO_RATE_TYPES, |
731 | VIDEO_MIMETYPE_EXT, | ||
732 | VIDEO_TRANSCODING_FPS, | 751 | VIDEO_TRANSCODING_FPS, |
733 | FFMPEG_NICE, | 752 | FFMPEG_NICE, |
734 | VIDEO_ABUSE_STATES, | 753 | VIDEO_ABUSE_STATES, |
@@ -736,18 +755,18 @@ export { | |||
736 | USER_PASSWORD_RESET_LIFETIME, | 755 | USER_PASSWORD_RESET_LIFETIME, |
737 | MEMOIZE_TTL, | 756 | MEMOIZE_TTL, |
738 | USER_EMAIL_VERIFY_LIFETIME, | 757 | USER_EMAIL_VERIFY_LIFETIME, |
739 | IMAGE_MIMETYPE_EXT, | ||
740 | OVERVIEWS, | 758 | OVERVIEWS, |
741 | SCHEDULER_INTERVALS_MS, | 759 | SCHEDULER_INTERVALS_MS, |
742 | REPEAT_JOBS, | 760 | REPEAT_JOBS, |
743 | STATIC_DOWNLOAD_PATHS, | 761 | STATIC_DOWNLOAD_PATHS, |
744 | RATES_LIMIT, | 762 | RATES_LIMIT, |
745 | VIDEO_EXT_MIMETYPE, | 763 | MIMETYPES, |
746 | CRAWL_REQUEST_CONCURRENCY, | 764 | CRAWL_REQUEST_CONCURRENCY, |
747 | JOB_COMPLETED_LIFETIME, | 765 | JOB_COMPLETED_LIFETIME, |
748 | HTTP_SIGNATURE, | 766 | HTTP_SIGNATURE, |
749 | VIDEO_IMPORT_STATES, | 767 | VIDEO_IMPORT_STATES, |
750 | VIDEO_VIEW_LIFETIME, | 768 | VIDEO_VIEW_LIFETIME, |
769 | CONTACT_FORM_LIFETIME, | ||
751 | buildLanguages | 770 | buildLanguages |
752 | } | 771 | } |
753 | 772 | ||
@@ -764,16 +783,50 @@ function getLocalConfigFilePath () { | |||
764 | return join(dirname(configSources[ 0 ].name), filename + '.json') | 783 | return join(dirname(configSources[ 0 ].name), filename + '.json') |
765 | } | 784 | } |
766 | 785 | ||
767 | function updateWebserverConfig () { | 786 | function buildVideoMimetypeExt () { |
787 | const data = { | ||
788 | 'video/webm': '.webm', | ||
789 | 'video/ogg': '.ogv', | ||
790 | 'video/mp4': '.mp4' | ||
791 | } | ||
792 | |||
793 | if (CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS) { | ||
794 | Object.assign(data, { | ||
795 | 'video/quicktime': '.mov', | ||
796 | 'video/x-msvideo': '.avi', | ||
797 | 'video/x-flv': '.flv', | ||
798 | 'video/x-matroska': '.mkv', | ||
799 | 'application/octet-stream': '.mkv', | ||
800 | 'video/avi': '.avi' | ||
801 | }) | ||
802 | } | ||
803 | |||
804 | return data | ||
805 | } | ||
806 | |||
807 | function updateWebserverUrls () { | ||
768 | CONFIG.WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT) | 808 | CONFIG.WEBSERVER.URL = sanitizeUrl(CONFIG.WEBSERVER.SCHEME + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT) |
769 | CONFIG.WEBSERVER.HOST = sanitizeHost(CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT, REMOTE_SCHEME.HTTP) | 809 | CONFIG.WEBSERVER.HOST = sanitizeHost(CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT, REMOTE_SCHEME.HTTP) |
770 | } | 810 | } |
771 | 811 | ||
812 | function updateWebserverConfig () { | ||
813 | CONSTRAINTS_FIELDS.VIDEOS.EXTNAME = buildVideosExtname() | ||
814 | |||
815 | MIMETYPES.VIDEO.MIMETYPE_EXT = buildVideoMimetypeExt() | ||
816 | MIMETYPES.VIDEO.EXT_MIMETYPE = invert(MIMETYPES.VIDEO.MIMETYPE_EXT) | ||
817 | } | ||
818 | |||
819 | function buildVideosExtname () { | ||
820 | return CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.ALLOW_ADDITIONAL_EXTENSIONS | ||
821 | ? [ '.mp4', '.ogv', '.webm', '.mkv', '.mov', '.avi', '.flv' ] | ||
822 | : [ '.mp4', '.ogv', '.webm' ] | ||
823 | } | ||
824 | |||
772 | function buildVideosRedundancy (objs: any[]): VideosRedundancy[] { | 825 | function buildVideosRedundancy (objs: any[]): VideosRedundancy[] { |
773 | if (!objs) return [] | 826 | if (!objs) return [] |
774 | 827 | ||
775 | return objs.map(obj => { | 828 | return objs.map(obj => { |
776 | return Object.assign(obj, { | 829 | return Object.assign({}, obj, { |
777 | minLifetime: parseDuration(obj.min_lifetime), | 830 | minLifetime: parseDuration(obj.min_lifetime), |
778 | size: bytes.parse(obj.size), | 831 | size: bytes.parse(obj.size), |
779 | minViews: obj.min_views | 832 | minViews: obj.min_views |
@@ -850,4 +903,5 @@ export function reloadConfig () { | |||
850 | config = require('config') | 903 | config = require('config') |
851 | 904 | ||
852 | updateWebserverConfig() | 905 | updateWebserverConfig() |
906 | updateWebserverUrls() | ||
853 | } | 907 | } |
diff --git a/server/initializers/database.ts b/server/initializers/database.ts index 40cd659ab..84ad2079b 100644 --- a/server/initializers/database.ts +++ b/server/initializers/database.ts | |||
@@ -31,6 +31,8 @@ import { VideoRedundancyModel } from '../models/redundancy/video-redundancy' | |||
31 | import { UserVideoHistoryModel } from '../models/account/user-video-history' | 31 | import { UserVideoHistoryModel } from '../models/account/user-video-history' |
32 | import { AccountBlocklistModel } from '../models/account/account-blocklist' | 32 | import { AccountBlocklistModel } from '../models/account/account-blocklist' |
33 | import { ServerBlocklistModel } from '../models/server/server-blocklist' | 33 | import { ServerBlocklistModel } from '../models/server/server-blocklist' |
34 | import { UserNotificationModel } from '../models/account/user-notification' | ||
35 | import { UserNotificationSettingModel } from '../models/account/user-notification-setting' | ||
34 | 36 | ||
35 | require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string | 37 | require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string |
36 | 38 | ||
@@ -95,7 +97,9 @@ async function initDatabaseModels (silent: boolean) { | |||
95 | VideoRedundancyModel, | 97 | VideoRedundancyModel, |
96 | UserVideoHistoryModel, | 98 | UserVideoHistoryModel, |
97 | AccountBlocklistModel, | 99 | AccountBlocklistModel, |
98 | ServerBlocklistModel | 100 | ServerBlocklistModel, |
101 | UserNotificationModel, | ||
102 | UserNotificationSettingModel | ||
99 | ]) | 103 | ]) |
100 | 104 | ||
101 | // Check extensions exist in the database | 105 | // Check extensions exist in the database |
diff --git a/server/initializers/migrations/0295-video-file-extname.ts b/server/initializers/migrations/0295-video-file-extname.ts new file mode 100644 index 000000000..dbf249f66 --- /dev/null +++ b/server/initializers/migrations/0295-video-file-extname.ts | |||
@@ -0,0 +1,49 @@ | |||
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 | { | ||
10 | await utils.queryInterface.renameColumn('videoFile', 'extname', 'extname_old') | ||
11 | } | ||
12 | |||
13 | { | ||
14 | const data = { | ||
15 | type: Sequelize.STRING, | ||
16 | defaultValue: null, | ||
17 | allowNull: true | ||
18 | } | ||
19 | |||
20 | await utils.queryInterface.addColumn('videoFile', 'extname', data) | ||
21 | } | ||
22 | |||
23 | { | ||
24 | const query = 'UPDATE "videoFile" SET "extname" = "extname_old"::text' | ||
25 | await utils.sequelize.query(query) | ||
26 | } | ||
27 | |||
28 | { | ||
29 | const data = { | ||
30 | type: Sequelize.STRING, | ||
31 | defaultValue: null, | ||
32 | allowNull: false | ||
33 | } | ||
34 | await utils.queryInterface.changeColumn('videoFile', 'extname', data) | ||
35 | } | ||
36 | |||
37 | { | ||
38 | await utils.queryInterface.removeColumn('videoFile', 'extname_old') | ||
39 | } | ||
40 | } | ||
41 | |||
42 | function down (options) { | ||
43 | throw new Error('Not implemented.') | ||
44 | } | ||
45 | |||
46 | export { | ||
47 | up, | ||
48 | down | ||
49 | } | ||
diff --git a/server/initializers/migrations/0300-user-videos-history-enabled.ts b/server/initializers/migrations/0300-user-videos-history-enabled.ts new file mode 100644 index 000000000..aa5fc21fb --- /dev/null +++ b/server/initializers/migrations/0300-user-videos-history-enabled.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 | { | ||
10 | const data = { | ||
11 | type: Sequelize.BOOLEAN, | ||
12 | allowNull: false, | ||
13 | defaultValue: true | ||
14 | } | ||
15 | |||
16 | await utils.queryInterface.addColumn('user', 'videosHistoryEnabled', data) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | function down (options) { | ||
21 | throw new Error('Not implemented.') | ||
22 | } | ||
23 | |||
24 | export { | ||
25 | up, | ||
26 | down | ||
27 | } | ||
diff --git a/server/initializers/migrations/0305-fix-unfederated-videos.ts b/server/initializers/migrations/0305-fix-unfederated-videos.ts new file mode 100644 index 000000000..be206601f --- /dev/null +++ b/server/initializers/migrations/0305-fix-unfederated-videos.ts | |||
@@ -0,0 +1,52 @@ | |||
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 | { | ||
10 | const query = `INSERT INTO "videoShare" (url, "actorId", "videoId", "createdAt", "updatedAt") ` + | ||
11 | `(` + | ||
12 | `SELECT ` + | ||
13 | `video.url || '/announces/' || "videoChannel"."actorId" as url, ` + | ||
14 | `"videoChannel"."actorId" AS "actorId", ` + | ||
15 | `"video"."id" AS "videoId", ` + | ||
16 | `NOW() AS "createdAt", ` + | ||
17 | `NOW() AS "updatedAt" ` + | ||
18 | `FROM video ` + | ||
19 | `INNER JOIN "videoChannel" ON "video"."channelId" = "videoChannel"."id" ` + | ||
20 | `WHERE "video"."remote" = false AND "video"."privacy" != 3 AND "video"."state" = 1` + | ||
21 | `) ` + | ||
22 | `ON CONFLICT DO NOTHING` | ||
23 | |||
24 | await utils.sequelize.query(query) | ||
25 | } | ||
26 | |||
27 | { | ||
28 | const query = `INSERT INTO "videoShare" (url, "actorId", "videoId", "createdAt", "updatedAt") ` + | ||
29 | `(` + | ||
30 | `SELECT ` + | ||
31 | `video.url || '/announces/' || (SELECT id FROM actor WHERE "preferredUsername" = 'peertube' ORDER BY id ASC LIMIT 1) as url, ` + | ||
32 | `(SELECT id FROM actor WHERE "preferredUsername" = 'peertube' ORDER BY id ASC LIMIT 1) AS "actorId", ` + | ||
33 | `"video"."id" AS "videoId", ` + | ||
34 | `NOW() AS "createdAt", ` + | ||
35 | `NOW() AS "updatedAt" ` + | ||
36 | `FROM video ` + | ||
37 | `WHERE "video"."remote" = false AND "video"."privacy" != 3 AND "video"."state" = 1` + | ||
38 | `) ` + | ||
39 | `ON CONFLICT DO NOTHING` | ||
40 | |||
41 | await utils.sequelize.query(query) | ||
42 | } | ||
43 | } | ||
44 | |||
45 | function down (options) { | ||
46 | throw new Error('Not implemented.') | ||
47 | } | ||
48 | |||
49 | export { | ||
50 | up, | ||
51 | down | ||
52 | } | ||
diff --git a/server/initializers/migrations/0310-drop-unused-video-indexes.ts b/server/initializers/migrations/0310-drop-unused-video-indexes.ts new file mode 100644 index 000000000..d51f430c0 --- /dev/null +++ b/server/initializers/migrations/0310-drop-unused-video-indexes.ts | |||
@@ -0,0 +1,32 @@ | |||
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 indexNames = [ | ||
10 | 'video_category', | ||
11 | 'video_licence', | ||
12 | 'video_nsfw', | ||
13 | 'video_language', | ||
14 | 'video_wait_transcoding', | ||
15 | 'video_state', | ||
16 | 'video_remote', | ||
17 | 'video_likes' | ||
18 | ] | ||
19 | |||
20 | for (const indexName of indexNames) { | ||
21 | await utils.sequelize.query('DROP INDEX IF EXISTS "' + indexName + '";') | ||
22 | } | ||
23 | } | ||
24 | |||
25 | function down (options) { | ||
26 | throw new Error('Not implemented.') | ||
27 | } | ||
28 | |||
29 | export { | ||
30 | up, | ||
31 | down | ||
32 | } | ||
diff --git a/server/initializers/migrations/0315-user-notifications.ts b/server/initializers/migrations/0315-user-notifications.ts new file mode 100644 index 000000000..8284c58a0 --- /dev/null +++ b/server/initializers/migrations/0315-user-notifications.ts | |||
@@ -0,0 +1,47 @@ | |||
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 | }): Promise<void> { | ||
8 | |||
9 | { | ||
10 | const query = ` | ||
11 | CREATE TABLE IF NOT EXISTS "userNotificationSetting" ("id" SERIAL, | ||
12 | "newVideoFromSubscription" INTEGER NOT NULL DEFAULT NULL, | ||
13 | "newCommentOnMyVideo" INTEGER NOT NULL DEFAULT NULL, | ||
14 | "videoAbuseAsModerator" INTEGER NOT NULL DEFAULT NULL, | ||
15 | "blacklistOnMyVideo" INTEGER NOT NULL DEFAULT NULL, | ||
16 | "myVideoPublished" INTEGER NOT NULL DEFAULT NULL, | ||
17 | "myVideoImportFinished" INTEGER NOT NULL DEFAULT NULL, | ||
18 | "newUserRegistration" INTEGER NOT NULL DEFAULT NULL, | ||
19 | "newFollow" INTEGER NOT NULL DEFAULT NULL, | ||
20 | "commentMention" INTEGER NOT NULL DEFAULT NULL, | ||
21 | "userId" INTEGER REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE, | ||
22 | "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, | ||
23 | "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, | ||
24 | PRIMARY KEY ("id")) | ||
25 | ` | ||
26 | await utils.sequelize.query(query) | ||
27 | } | ||
28 | |||
29 | { | ||
30 | const query = 'INSERT INTO "userNotificationSetting" ' + | ||
31 | '("newVideoFromSubscription", "newCommentOnMyVideo", "videoAbuseAsModerator", "blacklistOnMyVideo", ' + | ||
32 | '"myVideoPublished", "myVideoImportFinished", "newUserRegistration", "newFollow", "commentMention", ' + | ||
33 | '"userId", "createdAt", "updatedAt") ' + | ||
34 | '(SELECT 1, 1, 3, 3, 1, 1, 1, 1, 1, id, NOW(), NOW() FROM "user")' | ||
35 | |||
36 | await utils.sequelize.query(query) | ||
37 | } | ||
38 | } | ||
39 | |||
40 | function down (options) { | ||
41 | throw new Error('Not implemented.') | ||
42 | } | ||
43 | |||
44 | export { | ||
45 | up, | ||
46 | down | ||
47 | } | ||
diff --git a/server/initializers/migrations/0320-blacklist-unfederate.ts b/server/initializers/migrations/0320-blacklist-unfederate.ts new file mode 100644 index 000000000..6fb7bbb90 --- /dev/null +++ b/server/initializers/migrations/0320-blacklist-unfederate.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 | }): Promise<void> { | ||
8 | |||
9 | { | ||
10 | const data = { | ||
11 | type: Sequelize.BOOLEAN, | ||
12 | allowNull: false, | ||
13 | defaultValue: false | ||
14 | } | ||
15 | |||
16 | await utils.queryInterface.addColumn('videoBlacklist', 'unfederated', data) | ||
17 | } | ||
18 | } | ||
19 | |||
20 | function down (options) { | ||
21 | throw new Error('Not implemented.') | ||
22 | } | ||
23 | |||
24 | export { | ||
25 | up, | ||
26 | down | ||
27 | } | ||
diff --git a/server/initializers/migrations/0325-video-abuse-fields.ts b/server/initializers/migrations/0325-video-abuse-fields.ts new file mode 100644 index 000000000..fca6d666f --- /dev/null +++ b/server/initializers/migrations/0325-video-abuse-fields.ts | |||
@@ -0,0 +1,37 @@ | |||
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 | }): Promise<void> { | ||
8 | |||
9 | { | ||
10 | const data = { | ||
11 | type: Sequelize.STRING(3000), | ||
12 | allowNull: false, | ||
13 | defaultValue: null | ||
14 | } | ||
15 | |||
16 | await utils.queryInterface.changeColumn('videoAbuse', 'reason', data) | ||
17 | } | ||
18 | |||
19 | { | ||
20 | const data = { | ||
21 | type: Sequelize.STRING(3000), | ||
22 | allowNull: true, | ||
23 | defaultValue: null | ||
24 | } | ||
25 | |||
26 | await utils.queryInterface.changeColumn('videoAbuse', 'moderationComment', data) | ||
27 | } | ||
28 | } | ||
29 | |||
30 | function down (options) { | ||
31 | throw new Error('Not implemented.') | ||
32 | } | ||
33 | |||
34 | export { | ||
35 | up, | ||
36 | down | ||
37 | } | ||