aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/initializers
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-02-06 12:26:58 +0100
committerChocobozzz <me@florianbigard.com>2019-02-06 12:26:58 +0100
commit73471b1a52f242e86364ffb077ea6cadb3b07ae2 (patch)
tree43dbb7748e281f8d80f15326f489cdea10ec857d /server/initializers
parentc22419dd265c0c7185bf4197a1cb286eb3d8ebc0 (diff)
parentf5305c04aae14467d6f957b713c5a902275cbb89 (diff)
downloadPeerTube-73471b1a52f242e86364ffb077ea6cadb3b07ae2.tar.gz
PeerTube-73471b1a52f242e86364ffb077ea6cadb3b07ae2.tar.zst
PeerTube-73471b1a52f242e86364ffb077ea6cadb3b07ae2.zip
Merge branch 'release/v1.2.0'
Diffstat (limited to 'server/initializers')
-rw-r--r--server/initializers/checker-after-init.ts14
-rw-r--r--server/initializers/checker-before-init.ts5
-rw-r--r--server/initializers/constants.ts134
-rw-r--r--server/initializers/database.ts6
-rw-r--r--server/initializers/migrations/0295-video-file-extname.ts49
-rw-r--r--server/initializers/migrations/0300-user-videos-history-enabled.ts27
-rw-r--r--server/initializers/migrations/0305-fix-unfederated-videos.ts52
-rw-r--r--server/initializers/migrations/0310-drop-unused-video-indexes.ts32
-rw-r--r--server/initializers/migrations/0315-user-notifications.ts47
-rw-r--r--server/initializers/migrations/0320-blacklist-unfederate.ts27
-rw-r--r--server/initializers/migrations/0325-video-abuse-fields.ts37
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'
10import { RecentlyAddedStrategy } from '../../shared/models/redundancy' 10import { RecentlyAddedStrategy } from '../../shared/models/redundancy'
11import { isArray } from '../helpers/custom-validators/misc' 11import { isArray } from '../helpers/custom-validators/misc'
12import { uniq } from 'lodash' 12import { uniq } from 'lodash'
13import { Emailer } from '../lib/emailer'
13 14
14async function checkActivityPubUrls () { 15async 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
34function checkConfig () { 35function 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
19const LAST_MIGRATION_VERSION = 290 19const 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
56const OAUTH_LIFETIME = { 58const OAUTH_LIFETIME = {
@@ -61,6 +63,7 @@ const OAUTH_LIFETIME = {
61const ROUTE_CACHE_LIFETIME = { 63const 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
145let SCHEDULER_INTERVALS_MS = { 148let 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
298const CONSTRAINTS_FIELDS = { 308let 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
404let VIDEO_VIEW_LIFETIME = 60000 * 60 // 1 hour 418let VIDEO_VIEW_LIFETIME = 60000 * 60 // 1 hour
419let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour
420
405const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { 421const 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
480const VIDEO_MIMETYPE_EXT = { 496const 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 },
485const VIDEO_EXT_MIMETYPE = invert(VIDEO_MIMETYPE_EXT) 501 IMAGE: {
486 502 MIMETYPE_EXT: {
487const 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: {
493const 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 },
498const TORRENT_MIMETYPE_EXT = { 514 TORRENT: {
499 'application/x-bittorrent': '.torrent' 515 MIMETYPE_EXT: {
516 'application/x-bittorrent': '.torrent'
517 }
518 }
500} 519}
520MIMETYPES.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
684updateWebserverConfig() 706updateWebserverUrls()
685 707
686// --------------------------------------------------------------------------- 708// ---------------------------------------------------------------------------
687 709
688export { 710export {
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
767function updateWebserverConfig () { 786function 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
807function 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
812function 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
819function 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
772function buildVideosRedundancy (objs: any[]): VideosRedundancy[] { 825function 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'
31import { UserVideoHistoryModel } from '../models/account/user-video-history' 31import { UserVideoHistoryModel } from '../models/account/user-video-history'
32import { AccountBlocklistModel } from '../models/account/account-blocklist' 32import { AccountBlocklistModel } from '../models/account/account-blocklist'
33import { ServerBlocklistModel } from '../models/server/server-blocklist' 33import { ServerBlocklistModel } from '../models/server/server-blocklist'
34import { UserNotificationModel } from '../models/account/user-notification'
35import { UserNotificationSettingModel } from '../models/account/user-notification-setting'
34 36
35require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string 37require('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 @@
1import * as Sequelize from 'sequelize'
2
3async 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
42function down (options) {
43 throw new Error('Not implemented.')
44}
45
46export {
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 @@
1import * as Sequelize from 'sequelize'
2
3async 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
20function down (options) {
21 throw new Error('Not implemented.')
22}
23
24export {
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 @@
1import * as Sequelize from 'sequelize'
2
3async 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
45function down (options) {
46 throw new Error('Not implemented.')
47}
48
49export {
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 @@
1import * as Sequelize from 'sequelize'
2
3async 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
25function down (options) {
26 throw new Error('Not implemented.')
27}
28
29export {
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 @@
1import * as Sequelize from 'sequelize'
2
3async function up (utils: {
4 transaction: Sequelize.Transaction,
5 queryInterface: Sequelize.QueryInterface,
6 sequelize: Sequelize.Sequelize
7}): Promise<void> {
8
9 {
10 const query = `
11CREATE 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,
24PRIMARY 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
40function down (options) {
41 throw new Error('Not implemented.')
42}
43
44export {
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 @@
1import * as Sequelize from 'sequelize'
2
3async 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
20function down (options) {
21 throw new Error('Not implemented.')
22}
23
24export {
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 @@
1import * as Sequelize from 'sequelize'
2
3async 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
30function down (options) {
31 throw new Error('Not implemented.')
32}
33
34export {
35 up,
36 down
37}