diff options
26 files changed, 385 insertions, 12 deletions
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html index 6e3f83ccf..13b43306b 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html | |||
@@ -101,6 +101,13 @@ | |||
101 | </div> | 101 | </div> |
102 | </div> | 102 | </div> |
103 | 103 | ||
104 | <div i18n class="inner-form-title">Import</div> | ||
105 | |||
106 | <my-peertube-checkbox | ||
107 | inputName="importVideosHttpEnabled" formControlName="importVideosHttpEnabled" | ||
108 | i18n-labelText labelText="Video import with HTTP enabled" | ||
109 | ></my-peertube-checkbox> | ||
110 | |||
104 | <div i18n class="inner-form-title">Administrator</div> | 111 | <div i18n class="inner-form-title">Administrator</div> |
105 | 112 | ||
106 | <div class="form-group"> | 113 | <div class="form-group"> |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts index e614c1892..bc5ce6e5d 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts | |||
@@ -71,6 +71,7 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
71 | cacheCaptionsSize: this.customConfigValidatorsService.CACHE_CAPTIONS_SIZE, | 71 | cacheCaptionsSize: this.customConfigValidatorsService.CACHE_CAPTIONS_SIZE, |
72 | signupEnabled: null, | 72 | signupEnabled: null, |
73 | signupLimit: this.customConfigValidatorsService.SIGNUP_LIMIT, | 73 | signupLimit: this.customConfigValidatorsService.SIGNUP_LIMIT, |
74 | importVideosHttpEnabled: null, | ||
74 | adminEmail: this.customConfigValidatorsService.ADMIN_EMAIL, | 75 | adminEmail: this.customConfigValidatorsService.ADMIN_EMAIL, |
75 | userVideoQuota: this.userValidatorsService.USER_VIDEO_QUOTA, | 76 | userVideoQuota: this.userValidatorsService.USER_VIDEO_QUOTA, |
76 | transcodingThreads: this.customConfigValidatorsService.TRANSCODING_THREADS, | 77 | transcodingThreads: this.customConfigValidatorsService.TRANSCODING_THREADS, |
@@ -183,6 +184,13 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
183 | '720p': this.form.value[this.getResolutionKey('720p')], | 184 | '720p': this.form.value[this.getResolutionKey('720p')], |
184 | '1080p': this.form.value[this.getResolutionKey('1080p')] | 185 | '1080p': this.form.value[this.getResolutionKey('1080p')] |
185 | } | 186 | } |
187 | }, | ||
188 | import: { | ||
189 | videos: { | ||
190 | http: { | ||
191 | enabled: this.form.value['importVideosHttpEnabled'] | ||
192 | } | ||
193 | } | ||
186 | } | 194 | } |
187 | } | 195 | } |
188 | 196 | ||
@@ -222,7 +230,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
222 | transcodingThreads: this.customConfig.transcoding.threads, | 230 | transcodingThreads: this.customConfig.transcoding.threads, |
223 | transcodingEnabled: this.customConfig.transcoding.enabled, | 231 | transcodingEnabled: this.customConfig.transcoding.enabled, |
224 | customizationJavascript: this.customConfig.instance.customizations.javascript, | 232 | customizationJavascript: this.customConfig.instance.customizations.javascript, |
225 | customizationCSS: this.customConfig.instance.customizations.css | 233 | customizationCSS: this.customConfig.instance.customizations.css, |
234 | importVideosHttpEnabled: this.customConfig.import.videos.http.enabled | ||
226 | } | 235 | } |
227 | 236 | ||
228 | for (const resolution of this.resolutions) { | 237 | for (const resolution of this.resolutions) { |
diff --git a/client/src/app/+my-account/my-account.component.html b/client/src/app/+my-account/my-account.component.html index f67245d85..ddb0570db 100644 --- a/client/src/app/+my-account/my-account.component.html +++ b/client/src/app/+my-account/my-account.component.html | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | <a i18n routerLink="/my-account/videos" routerLinkActive="active" class="title-page">My videos</a> | 7 | <a i18n routerLink="/my-account/videos" routerLinkActive="active" class="title-page">My videos</a> |
8 | 8 | ||
9 | <a i18n routerLink="/my-account/video-imports" routerLinkActive="active" class="title-page">My video imports</a> | 9 | <a *ngIf="isVideoImportEnabled()" i18n routerLink="/my-account/video-imports" routerLinkActive="active" class="title-page">My video imports</a> |
10 | </div> | 10 | </div> |
11 | 11 | ||
12 | <div class="margin-content"> | 12 | <div class="margin-content"> |
diff --git a/client/src/app/+my-account/my-account.component.ts b/client/src/app/+my-account/my-account.component.ts index 7bb461d3c..a8f5f8f31 100644 --- a/client/src/app/+my-account/my-account.component.ts +++ b/client/src/app/+my-account/my-account.component.ts | |||
@@ -1,7 +1,17 @@ | |||
1 | import { Component } from '@angular/core' | 1 | import { Component } from '@angular/core' |
2 | import { ServerService } from '@app/core' | ||
2 | 3 | ||
3 | @Component({ | 4 | @Component({ |
4 | selector: 'my-my-account', | 5 | selector: 'my-my-account', |
5 | templateUrl: './my-account.component.html' | 6 | templateUrl: './my-account.component.html' |
6 | }) | 7 | }) |
7 | export class MyAccountComponent {} | 8 | export class MyAccountComponent { |
9 | |||
10 | constructor ( | ||
11 | private serverService: ServerService | ||
12 | ) {} | ||
13 | |||
14 | isVideoImportEnabled () { | ||
15 | return this.serverService.getConfig().import.video.http.enabled | ||
16 | } | ||
17 | } | ||
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts index 7b11c068e..e2254b7b5 100644 --- a/client/src/app/core/server/server.service.ts +++ b/client/src/app/core/server/server.service.ts | |||
@@ -68,6 +68,13 @@ export class ServerService { | |||
68 | }, | 68 | }, |
69 | user: { | 69 | user: { |
70 | videoQuota: -1 | 70 | videoQuota: -1 |
71 | }, | ||
72 | import: { | ||
73 | video: { | ||
74 | http: { | ||
75 | enabled: false | ||
76 | } | ||
77 | } | ||
71 | } | 78 | } |
72 | } | 79 | } |
73 | private videoCategories: Array<VideoConstant<string>> = [] | 80 | private videoCategories: Array<VideoConstant<string>> = [] |
diff --git a/client/src/app/videos/+video-edit/video-add.component.html b/client/src/app/videos/+video-edit/video-add.component.html index ed8d91c11..1575007d2 100644 --- a/client/src/app/videos/+video-edit/video-add.component.html +++ b/client/src/app/videos/+video-edit/video-add.component.html | |||
@@ -10,7 +10,7 @@ | |||
10 | <my-video-upload #videoUpload (firstStepDone)="onFirstStepDone('upload', $event)"></my-video-upload> | 10 | <my-video-upload #videoUpload (firstStepDone)="onFirstStepDone('upload', $event)"></my-video-upload> |
11 | </tab> | 11 | </tab> |
12 | 12 | ||
13 | <tab i18n-heading heading="Import your video"> | 13 | <tab *ngIf="isVideoImportEnabled()" i18n-heading heading="Import your video"> |
14 | <my-video-import #videoImport (firstStepDone)="onFirstStepDone('import', $event)"></my-video-import> | 14 | <my-video-import #videoImport (firstStepDone)="onFirstStepDone('import', $event)"></my-video-import> |
15 | </tab> | 15 | </tab> |
16 | </tabset> | 16 | </tabset> |
diff --git a/client/src/app/videos/+video-edit/video-add.component.ts b/client/src/app/videos/+video-edit/video-add.component.ts index 64071b40c..d38a53db9 100644 --- a/client/src/app/videos/+video-edit/video-add.component.ts +++ b/client/src/app/videos/+video-edit/video-add.component.ts | |||
@@ -2,6 +2,7 @@ import { Component, ViewChild } from '@angular/core' | |||
2 | import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service' | 2 | import { CanComponentDeactivate } from '@app/shared/guards/can-deactivate-guard.service' |
3 | import { VideoImportComponent } from '@app/videos/+video-edit/video-import.component' | 3 | import { VideoImportComponent } from '@app/videos/+video-edit/video-import.component' |
4 | import { VideoUploadComponent } from '@app/videos/+video-edit/video-upload.component' | 4 | import { VideoUploadComponent } from '@app/videos/+video-edit/video-upload.component' |
5 | import { ServerService } from '@app/core' | ||
5 | 6 | ||
6 | @Component({ | 7 | @Component({ |
7 | selector: 'my-videos-add', | 8 | selector: 'my-videos-add', |
@@ -15,6 +16,10 @@ export class VideoAddComponent implements CanComponentDeactivate { | |||
15 | secondStepType: 'upload' | 'import' | 16 | secondStepType: 'upload' | 'import' |
16 | videoName: string | 17 | videoName: string |
17 | 18 | ||
19 | constructor ( | ||
20 | private serverService: ServerService | ||
21 | ) {} | ||
22 | |||
18 | onFirstStepDone (type: 'upload' | 'import', videoName: string) { | 23 | onFirstStepDone (type: 'upload' | 'import', videoName: string) { |
19 | this.secondStepType = type | 24 | this.secondStepType = type |
20 | this.videoName = videoName | 25 | this.videoName = videoName |
@@ -26,4 +31,8 @@ export class VideoAddComponent implements CanComponentDeactivate { | |||
26 | 31 | ||
27 | return { canDeactivate: true } | 32 | return { canDeactivate: true } |
28 | } | 33 | } |
34 | |||
35 | isVideoImportEnabled () { | ||
36 | return this.serverService.getConfig().import.video.http.enabled | ||
37 | } | ||
29 | } | 38 | } |
diff --git a/client/src/app/videos/+video-edit/video-import.component.ts b/client/src/app/videos/+video-edit/video-import.component.ts index bd4482e17..b1e8e0205 100644 --- a/client/src/app/videos/+video-edit/video-import.component.ts +++ b/client/src/app/videos/+video-edit/video-import.component.ts | |||
@@ -97,8 +97,11 @@ export class VideoImportComponent extends FormReactive implements OnInit, CanCom | |||
97 | channelId: this.firstStepChannelId | 97 | channelId: this.firstStepChannelId |
98 | } | 98 | } |
99 | 99 | ||
100 | this.loadingBar.start() | ||
101 | |||
100 | this.videoImportService.importVideo(this.targetUrl, videoUpdate).subscribe( | 102 | this.videoImportService.importVideo(this.targetUrl, videoUpdate).subscribe( |
101 | res => { | 103 | res => { |
104 | this.loadingBar.complete() | ||
102 | this.firstStepDone.emit(res.video.name) | 105 | this.firstStepDone.emit(res.video.name) |
103 | this.isImportingVideo = false | 106 | this.isImportingVideo = false |
104 | this.hasImportedVideo = true | 107 | this.hasImportedVideo = true |
@@ -113,6 +116,7 @@ export class VideoImportComponent extends FormReactive implements OnInit, CanCom | |||
113 | }, | 116 | }, |
114 | 117 | ||
115 | err => { | 118 | err => { |
119 | this.loadingBar.complete() | ||
116 | this.isImportingVideo = false | 120 | this.isImportingVideo = false |
117 | this.notificationsService.error(this.i18n('Error'), err.message) | 121 | this.notificationsService.error(this.i18n('Error'), err.message) |
118 | } | 122 | } |
diff --git a/config/default.yaml b/config/default.yaml index 722b33db3..5fa7e5945 100644 --- a/config/default.yaml +++ b/config/default.yaml | |||
@@ -96,7 +96,7 @@ import: | |||
96 | # Add ability for your users to import remote videos (from YouTube, torrent...) | 96 | # Add ability for your users to import remote videos (from YouTube, torrent...) |
97 | videos: | 97 | videos: |
98 | http: # Classic HTTP or all sites supported by youtube-dl https://rg3.github.io/youtube-dl/supportedsites.html | 98 | http: # Classic HTTP or all sites supported by youtube-dl https://rg3.github.io/youtube-dl/supportedsites.html |
99 | enabled: true | 99 | enabled: false |
100 | 100 | ||
101 | instance: | 101 | instance: |
102 | name: 'PeerTube' | 102 | name: 'PeerTube' |
diff --git a/config/production.yaml.example b/config/production.yaml.example index 6087e78be..635a41e9e 100644 --- a/config/production.yaml.example +++ b/config/production.yaml.example | |||
@@ -106,6 +106,12 @@ transcoding: | |||
106 | 720p: false | 106 | 720p: false |
107 | 1080p: false | 107 | 1080p: false |
108 | 108 | ||
109 | import: | ||
110 | # Add ability for your users to import remote videos (from YouTube, torrent...) | ||
111 | videos: | ||
112 | http: # Classic HTTP or all sites supported by youtube-dl https://rg3.github.io/youtube-dl/supportedsites.html | ||
113 | enabled: false | ||
114 | |||
109 | # Instance settings | 115 | # Instance settings |
110 | instance: | 116 | instance: |
111 | name: 'PeerTube' | 117 | name: 'PeerTube' |
diff --git a/config/test.yaml b/config/test.yaml index ffe736b24..3c51785f2 100644 --- a/config/test.yaml +++ b/config/test.yaml | |||
@@ -40,5 +40,10 @@ transcoding: | |||
40 | 720p: true | 40 | 720p: true |
41 | 1080p: true | 41 | 1080p: true |
42 | 42 | ||
43 | import: | ||
44 | videos: | ||
45 | http: | ||
46 | enabled: true | ||
47 | |||
43 | instance: | 48 | instance: |
44 | default_nsfw_policy: 'display' \ No newline at end of file | 49 | default_nsfw_policy: 'display' \ No newline at end of file |
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index 411b13539..acbeab70b 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -65,6 +65,13 @@ async function getConfig (req: express.Request, res: express.Response, next: exp | |||
65 | transcoding: { | 65 | transcoding: { |
66 | enabledResolutions | 66 | enabledResolutions |
67 | }, | 67 | }, |
68 | import: { | ||
69 | video: { | ||
70 | http: { | ||
71 | enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED | ||
72 | } | ||
73 | } | ||
74 | }, | ||
68 | avatar: { | 75 | avatar: { |
69 | file: { | 76 | file: { |
70 | size: { | 77 | size: { |
@@ -225,6 +232,13 @@ function customConfig (): CustomConfig { | |||
225 | '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], | 232 | '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], |
226 | '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ] | 233 | '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ] |
227 | } | 234 | } |
235 | }, | ||
236 | import: { | ||
237 | videos: { | ||
238 | http: { | ||
239 | enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED | ||
240 | } | ||
241 | } | ||
228 | } | 242 | } |
229 | } | 243 | } |
230 | } | 244 | } |
diff --git a/server/controllers/api/users.ts b/server/controllers/api/users.ts index 6e5f9913e..879ba3f91 100644 --- a/server/controllers/api/users.ts +++ b/server/controllers/api/users.ts | |||
@@ -68,7 +68,6 @@ usersRouter.get('/me/video-quota-used', | |||
68 | asyncMiddleware(getUserVideoQuotaUsed) | 68 | asyncMiddleware(getUserVideoQuotaUsed) |
69 | ) | 69 | ) |
70 | 70 | ||
71 | |||
72 | usersRouter.get('/me/videos/imports', | 71 | usersRouter.get('/me/videos/imports', |
73 | authenticate, | 72 | authenticate, |
74 | paginationValidator, | 73 | paginationValidator, |
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index 33ac83cb9..ee11b0741 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts | |||
@@ -77,7 +77,7 @@ async function addVideoImport (req: express.Request, res: express.Response) { | |||
77 | video.url = getVideoActivityPubUrl(video) | 77 | video.url = getVideoActivityPubUrl(video) |
78 | 78 | ||
79 | // Process thumbnail file? | 79 | // Process thumbnail file? |
80 | const thumbnailField = req.files['thumbnailfile'] | 80 | const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined |
81 | let downloadThumbnail = true | 81 | let downloadThumbnail = true |
82 | if (thumbnailField) { | 82 | if (thumbnailField) { |
83 | const thumbnailPhysicalFile = thumbnailField[ 0 ] | 83 | const thumbnailPhysicalFile = thumbnailField[ 0 ] |
@@ -86,7 +86,7 @@ async function addVideoImport (req: express.Request, res: express.Response) { | |||
86 | } | 86 | } |
87 | 87 | ||
88 | // Process preview file? | 88 | // Process preview file? |
89 | const previewField = req.files['previewfile'] | 89 | const previewField = req.files ? req.files['previewfile'] : undefined |
90 | let downloadPreview = true | 90 | let downloadPreview = true |
91 | if (previewField) { | 91 | if (previewField) { |
92 | const previewPhysicalFile = previewField[0] | 92 | const previewPhysicalFile = previewField[0] |
diff --git a/server/helpers/audit-logger.ts b/server/helpers/audit-logger.ts index 031b1bfbd..db20df20f 100644 --- a/server/helpers/audit-logger.ts +++ b/server/helpers/audit-logger.ts | |||
@@ -246,11 +246,9 @@ class CustomConfigAuditView extends EntityAuditView { | |||
246 | const resolutionsDict = infos.transcoding.resolutions | 246 | const resolutionsDict = infos.transcoding.resolutions |
247 | const resolutionsArray = [] | 247 | const resolutionsArray = [] |
248 | Object.entries(resolutionsDict).forEach(([resolution, isEnabled]) => { | 248 | Object.entries(resolutionsDict).forEach(([resolution, isEnabled]) => { |
249 | if (isEnabled) { | 249 | if (isEnabled) resolutionsArray.push(resolution) |
250 | resolutionsArray.push(resolution) | ||
251 | } | ||
252 | }) | 250 | }) |
253 | infos.transcoding.resolutions = resolutionsArray | 251 | Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } }) |
254 | super(customConfigKeysToKeep, 'config', infos) | 252 | super(customConfigKeysToKeep, 'config', infos) |
255 | } | 253 | } |
256 | } | 254 | } |
diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts index f1c2e80a9..608123607 100644 --- a/server/initializers/checker.ts +++ b/server/initializers/checker.ts | |||
@@ -51,6 +51,7 @@ function checkMissedConfig () { | |||
51 | 'cache.previews.size', 'admin.email', | 51 | 'cache.previews.size', 'admin.email', |
52 | 'signup.enabled', 'signup.limit', 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', | 52 | 'signup.enabled', 'signup.limit', 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', |
53 | 'transcoding.enabled', 'transcoding.threads', | 53 | 'transcoding.enabled', 'transcoding.threads', |
54 | 'import.videos.http.enabled', | ||
54 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', | 55 | 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', |
55 | 'instance.default_nsfw_policy', 'instance.robots', | 56 | 'instance.default_nsfw_policy', 'instance.robots', |
56 | 'services.twitter.username', 'services.twitter.whitelisted' | 57 | 'services.twitter.username', 'services.twitter.whitelisted' |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 5bfeb3746..069d9b2e8 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -206,6 +206,13 @@ const CONFIG = { | |||
206 | get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') } | 206 | get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') } |
207 | } | 207 | } |
208 | }, | 208 | }, |
209 | IMPORT: { | ||
210 | VIDEOS: { | ||
211 | HTTP: { | ||
212 | get ENABLED () { return config.get<boolean>('import.videos.http.enabled') } | ||
213 | } | ||
214 | } | ||
215 | }, | ||
209 | CACHE: { | 216 | CACHE: { |
210 | PREVIEWS: { | 217 | PREVIEWS: { |
211 | get SIZE () { return config.get<number>('cache.previews.size') } | 218 | get SIZE () { return config.get<number>('cache.previews.size') } |
diff --git a/server/middlewares/validators/config.ts b/server/middlewares/validators/config.ts index f58c0676c..9d303eee2 100644 --- a/server/middlewares/validators/config.ts +++ b/server/middlewares/validators/config.ts | |||
@@ -24,6 +24,7 @@ const customConfigUpdateValidator = [ | |||
24 | body('transcoding.resolutions.480p').isBoolean().withMessage('Should have a valid transcoding 480p resolution enabled boolean'), | 24 | body('transcoding.resolutions.480p').isBoolean().withMessage('Should have a valid transcoding 480p resolution enabled boolean'), |
25 | body('transcoding.resolutions.720p').isBoolean().withMessage('Should have a valid transcoding 720p resolution enabled boolean'), | 25 | body('transcoding.resolutions.720p').isBoolean().withMessage('Should have a valid transcoding 720p resolution enabled boolean'), |
26 | body('transcoding.resolutions.1080p').isBoolean().withMessage('Should have a valid transcoding 1080p resolution enabled boolean'), | 26 | body('transcoding.resolutions.1080p').isBoolean().withMessage('Should have a valid transcoding 1080p resolution enabled boolean'), |
27 | body('import.videos.http.enabled').isBoolean().withMessage('Should have a valid import video http enabled boolean'), | ||
27 | 28 | ||
28 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 29 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
29 | logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) | 30 | logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body }) |
diff --git a/server/middlewares/validators/video-imports.ts b/server/middlewares/validators/video-imports.ts index e0a552976..d806edfa3 100644 --- a/server/middlewares/validators/video-imports.ts +++ b/server/middlewares/validators/video-imports.ts | |||
@@ -7,6 +7,7 @@ import { getCommonVideoAttributes } from './videos' | |||
7 | import { isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports' | 7 | import { isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports' |
8 | import { cleanUpReqFiles } from '../../helpers/utils' | 8 | import { cleanUpReqFiles } from '../../helpers/utils' |
9 | import { isVideoChannelOfAccountExist, isVideoNameValid } from '../../helpers/custom-validators/videos' | 9 | import { isVideoChannelOfAccountExist, isVideoNameValid } from '../../helpers/custom-validators/videos' |
10 | import { CONFIG } from '../../initializers/constants' | ||
10 | 11 | ||
11 | const videoImportAddValidator = getCommonVideoAttributes().concat([ | 12 | const videoImportAddValidator = getCommonVideoAttributes().concat([ |
12 | body('targetUrl').custom(isVideoImportTargetUrlValid).withMessage('Should have a valid video import target URL'), | 13 | body('targetUrl').custom(isVideoImportTargetUrlValid).withMessage('Should have a valid video import target URL'), |
@@ -23,6 +24,14 @@ const videoImportAddValidator = getCommonVideoAttributes().concat([ | |||
23 | const user = res.locals.oauth.token.User | 24 | const user = res.locals.oauth.token.User |
24 | 25 | ||
25 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) | 26 | if (areValidationErrors(req, res)) return cleanUpReqFiles(req) |
27 | |||
28 | if (CONFIG.IMPORT.VIDEOS.HTTP.ENABLED !== true) { | ||
29 | cleanUpReqFiles(req) | ||
30 | return res.status(409) | ||
31 | .json({ error: 'Import is not enabled on this instance.' }) | ||
32 | .end() | ||
33 | } | ||
34 | |||
26 | if (!await isVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) | 35 | if (!await isVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) |
27 | 36 | ||
28 | return next() | 37 | return next() |
diff --git a/server/tests/api/check-params/config.ts b/server/tests/api/check-params/config.ts index 03855237f..2742e26de 100644 --- a/server/tests/api/check-params/config.ts +++ b/server/tests/api/check-params/config.ts | |||
@@ -60,6 +60,13 @@ describe('Test config API validators', function () { | |||
60 | '720p': false, | 60 | '720p': false, |
61 | '1080p': false | 61 | '1080p': false |
62 | } | 62 | } |
63 | }, | ||
64 | import: { | ||
65 | videos: { | ||
66 | http: { | ||
67 | enabled: false | ||
68 | } | ||
69 | } | ||
63 | } | 70 | } |
64 | } | 71 | } |
65 | 72 | ||
diff --git a/server/tests/api/check-params/index.ts b/server/tests/api/check-params/index.ts index 820dde889..03fdd5c4e 100644 --- a/server/tests/api/check-params/index.ts +++ b/server/tests/api/check-params/index.ts | |||
@@ -10,4 +10,5 @@ import './video-captions' | |||
10 | import './video-channels' | 10 | import './video-channels' |
11 | import './video-comments' | 11 | import './video-comments' |
12 | import './videos' | 12 | import './videos' |
13 | import './video-imports' | ||
13 | import './search' | 14 | import './search' |
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts new file mode 100644 index 000000000..7f58efb74 --- /dev/null +++ b/server/tests/api/check-params/video-imports.ts | |||
@@ -0,0 +1,246 @@ | |||
1 | /* tslint:disable:no-unused-expression */ | ||
2 | |||
3 | import { omit } from 'lodash' | ||
4 | import 'mocha' | ||
5 | import { join } from 'path' | ||
6 | import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' | ||
7 | import { | ||
8 | createUser, | ||
9 | flushTests, | ||
10 | getMyUserInformation, | ||
11 | immutableAssign, | ||
12 | killallServers, | ||
13 | makeGetRequest, | ||
14 | makePostBodyRequest, | ||
15 | makeUploadRequest, | ||
16 | runServer, | ||
17 | ServerInfo, | ||
18 | setAccessTokensToServers, | ||
19 | userLogin | ||
20 | } from '../../utils' | ||
21 | import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params' | ||
22 | |||
23 | describe('Test video imports API validator', function () { | ||
24 | const path = '/api/v1/videos/imports' | ||
25 | let server: ServerInfo | ||
26 | let userAccessToken = '' | ||
27 | let accountName: string | ||
28 | let channelId: number | ||
29 | let channelUUID: string | ||
30 | |||
31 | // --------------------------------------------------------------- | ||
32 | |||
33 | before(async function () { | ||
34 | this.timeout(30000) | ||
35 | |||
36 | await flushTests() | ||
37 | |||
38 | server = await runServer(1) | ||
39 | |||
40 | await setAccessTokensToServers([ server ]) | ||
41 | |||
42 | const username = 'user1' | ||
43 | const password = 'my super password' | ||
44 | await createUser(server.url, server.accessToken, username, password) | ||
45 | userAccessToken = await userLogin(server, { username, password }) | ||
46 | |||
47 | { | ||
48 | const res = await getMyUserInformation(server.url, server.accessToken) | ||
49 | channelId = res.body.videoChannels[ 0 ].id | ||
50 | channelUUID = res.body.videoChannels[ 0 ].uuid | ||
51 | accountName = res.body.account.name + '@' + res.body.account.host | ||
52 | } | ||
53 | }) | ||
54 | |||
55 | describe('When listing my video imports', function () { | ||
56 | const myPath = '/api/v1/users/me/videos/imports' | ||
57 | |||
58 | it('Should fail with a bad start pagination', async function () { | ||
59 | await checkBadStartPagination(server.url, myPath, server.accessToken) | ||
60 | }) | ||
61 | |||
62 | it('Should fail with a bad count pagination', async function () { | ||
63 | await checkBadCountPagination(server.url, myPath, server.accessToken) | ||
64 | }) | ||
65 | |||
66 | it('Should fail with an incorrect sort', async function () { | ||
67 | await checkBadSortPagination(server.url, myPath, server.accessToken) | ||
68 | }) | ||
69 | |||
70 | it('Should success with the correct parameters', async function () { | ||
71 | await makeGetRequest({ url: server.url, path: myPath, statusCodeExpected: 200, token: server.accessToken }) | ||
72 | }) | ||
73 | }) | ||
74 | |||
75 | describe('When adding a video import', function () { | ||
76 | let baseCorrectParams | ||
77 | |||
78 | before(function () { | ||
79 | baseCorrectParams = { | ||
80 | targetUrl: 'https://youtu.be/msX3jv1XdvM', | ||
81 | name: 'my super name', | ||
82 | category: 5, | ||
83 | licence: 1, | ||
84 | language: 'pt', | ||
85 | nsfw: false, | ||
86 | commentsEnabled: true, | ||
87 | waitTranscoding: true, | ||
88 | description: 'my super description', | ||
89 | support: 'my super support text', | ||
90 | tags: [ 'tag1', 'tag2' ], | ||
91 | privacy: VideoPrivacy.PUBLIC, | ||
92 | channelId: channelId | ||
93 | } | ||
94 | }) | ||
95 | |||
96 | it('Should fail with nothing', async function () { | ||
97 | const fields = {} | ||
98 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
99 | }) | ||
100 | |||
101 | it('Should fail with a long name', async function () { | ||
102 | const fields = immutableAssign(baseCorrectParams, { name: 'super'.repeat(65) }) | ||
103 | |||
104 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
105 | }) | ||
106 | |||
107 | it('Should fail with a bad category', async function () { | ||
108 | const fields = immutableAssign(baseCorrectParams, { category: 125 }) | ||
109 | |||
110 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
111 | }) | ||
112 | |||
113 | it('Should fail with a bad licence', async function () { | ||
114 | const fields = immutableAssign(baseCorrectParams, { licence: 125 }) | ||
115 | |||
116 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
117 | }) | ||
118 | |||
119 | it('Should fail with a bad language', async function () { | ||
120 | const fields = immutableAssign(baseCorrectParams, { language: 'a'.repeat(15) }) | ||
121 | |||
122 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
123 | }) | ||
124 | |||
125 | it('Should fail with a long description', async function () { | ||
126 | const fields = immutableAssign(baseCorrectParams, { description: 'super'.repeat(2500) }) | ||
127 | |||
128 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
129 | }) | ||
130 | |||
131 | it('Should fail with a long support text', async function () { | ||
132 | const fields = immutableAssign(baseCorrectParams, { support: 'super'.repeat(150) }) | ||
133 | |||
134 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
135 | }) | ||
136 | |||
137 | it('Should fail without a channel', async function () { | ||
138 | const fields = omit(baseCorrectParams, 'channelId') | ||
139 | |||
140 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
141 | }) | ||
142 | |||
143 | it('Should fail with a bad channel', async function () { | ||
144 | const fields = immutableAssign(baseCorrectParams, { channelId: 545454 }) | ||
145 | |||
146 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
147 | }) | ||
148 | |||
149 | it('Should fail with another user channel', async function () { | ||
150 | const user = { | ||
151 | username: 'fake', | ||
152 | password: 'fake_password' | ||
153 | } | ||
154 | await createUser(server.url, server.accessToken, user.username, user.password) | ||
155 | |||
156 | const accessTokenUser = await userLogin(server, user) | ||
157 | const res = await getMyUserInformation(server.url, accessTokenUser) | ||
158 | const customChannelId = res.body.videoChannels[0].id | ||
159 | |||
160 | const fields = immutableAssign(baseCorrectParams, { channelId: customChannelId }) | ||
161 | |||
162 | await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields }) | ||
163 | }) | ||
164 | |||
165 | it('Should fail with too many tags', async function () { | ||
166 | const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6' ] }) | ||
167 | |||
168 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
169 | }) | ||
170 | |||
171 | it('Should fail with a tag length too low', async function () { | ||
172 | const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 't' ] }) | ||
173 | |||
174 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
175 | }) | ||
176 | |||
177 | it('Should fail with a tag length too big', async function () { | ||
178 | const fields = immutableAssign(baseCorrectParams, { tags: [ 'tag1', 'my_super_tag_too_long_long_long_long_long_long' ] }) | ||
179 | |||
180 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
181 | }) | ||
182 | |||
183 | it('Should fail with an incorrect thumbnail file', async function () { | ||
184 | const fields = baseCorrectParams | ||
185 | const attaches = { | ||
186 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | ||
187 | } | ||
188 | |||
189 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | ||
190 | }) | ||
191 | |||
192 | it('Should fail with a big thumbnail file', async function () { | ||
193 | const fields = baseCorrectParams | ||
194 | const attaches = { | ||
195 | 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | ||
196 | } | ||
197 | |||
198 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | ||
199 | }) | ||
200 | |||
201 | it('Should fail with an incorrect preview file', async function () { | ||
202 | const fields = baseCorrectParams | ||
203 | const attaches = { | ||
204 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png') | ||
205 | } | ||
206 | |||
207 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | ||
208 | }) | ||
209 | |||
210 | it('Should fail with a big preview file', async function () { | ||
211 | const fields = baseCorrectParams | ||
212 | const attaches = { | ||
213 | 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png') | ||
214 | } | ||
215 | |||
216 | await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches }) | ||
217 | }) | ||
218 | |||
219 | it('Should succeed with the correct parameters', async function () { | ||
220 | this.timeout(10000) | ||
221 | |||
222 | const fields = baseCorrectParams | ||
223 | |||
224 | { | ||
225 | await makePostBodyRequest({ | ||
226 | url: server.url, | ||
227 | path, | ||
228 | token: server.accessToken, | ||
229 | fields, | ||
230 | statusCodeExpected: 200 | ||
231 | }) | ||
232 | } | ||
233 | }) | ||
234 | |||
235 | it('Should forbid importing') | ||
236 | }) | ||
237 | |||
238 | after(async function () { | ||
239 | killallServers([ server ]) | ||
240 | |||
241 | // Keep the logs if the test failed | ||
242 | if (this['ok']) { | ||
243 | await flushTests() | ||
244 | } | ||
245 | }) | ||
246 | }) | ||
diff --git a/server/tests/api/server/config.ts b/server/tests/api/server/config.ts index 1782a8623..b65061a5d 100644 --- a/server/tests/api/server/config.ts +++ b/server/tests/api/server/config.ts | |||
@@ -44,6 +44,7 @@ function checkInitialConfig (data: CustomConfig) { | |||
44 | expect(data.transcoding.resolutions['480p']).to.be.true | 44 | expect(data.transcoding.resolutions['480p']).to.be.true |
45 | expect(data.transcoding.resolutions['720p']).to.be.true | 45 | expect(data.transcoding.resolutions['720p']).to.be.true |
46 | expect(data.transcoding.resolutions['1080p']).to.be.true | 46 | expect(data.transcoding.resolutions['1080p']).to.be.true |
47 | expect(data.import.videos.http.enabled).to.be.true | ||
47 | } | 48 | } |
48 | 49 | ||
49 | function checkUpdatedConfig (data: CustomConfig) { | 50 | function checkUpdatedConfig (data: CustomConfig) { |
@@ -70,6 +71,7 @@ function checkUpdatedConfig (data: CustomConfig) { | |||
70 | expect(data.transcoding.resolutions['480p']).to.be.true | 71 | expect(data.transcoding.resolutions['480p']).to.be.true |
71 | expect(data.transcoding.resolutions['720p']).to.be.false | 72 | expect(data.transcoding.resolutions['720p']).to.be.false |
72 | expect(data.transcoding.resolutions['1080p']).to.be.false | 73 | expect(data.transcoding.resolutions['1080p']).to.be.false |
74 | expect(data.import.videos.http.enabled).to.be.false | ||
73 | } | 75 | } |
74 | 76 | ||
75 | describe('Test config', function () { | 77 | describe('Test config', function () { |
@@ -160,6 +162,13 @@ describe('Test config', function () { | |||
160 | '720p': false, | 162 | '720p': false, |
161 | '1080p': false | 163 | '1080p': false |
162 | } | 164 | } |
165 | }, | ||
166 | import: { | ||
167 | videos: { | ||
168 | http: { | ||
169 | enabled: false | ||
170 | } | ||
171 | } | ||
163 | } | 172 | } |
164 | } | 173 | } |
165 | await updateCustomConfig(server.url, server.accessToken, newCustomConfig) | 174 | await updateCustomConfig(server.url, server.accessToken, newCustomConfig) |
diff --git a/server/tests/client.ts b/server/tests/client.ts index bcbac86e9..129b40cdf 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -164,6 +164,13 @@ describe('Test a client controllers', function () { | |||
164 | '720p': false, | 164 | '720p': false, |
165 | '1080p': false | 165 | '1080p': false |
166 | } | 166 | } |
167 | }, | ||
168 | import: { | ||
169 | videos: { | ||
170 | http: { | ||
171 | enabled: false | ||
172 | } | ||
173 | } | ||
167 | } | 174 | } |
168 | } | 175 | } |
169 | await updateCustomConfig(server.url, server.accessToken, newCustomConfig) | 176 | await updateCustomConfig(server.url, server.accessToken, newCustomConfig) |
diff --git a/shared/models/server/custom-config.model.ts b/shared/models/server/custom-config.model.ts index 9c4718e43..46320435d 100644 --- a/shared/models/server/custom-config.model.ts +++ b/shared/models/server/custom-config.model.ts | |||
@@ -55,4 +55,12 @@ export interface CustomConfig { | |||
55 | '1080p': boolean | 55 | '1080p': boolean |
56 | } | 56 | } |
57 | } | 57 | } |
58 | |||
59 | import: { | ||
60 | videos: { | ||
61 | http: { | ||
62 | enabled: boolean | ||
63 | } | ||
64 | } | ||
65 | } | ||
58 | } | 66 | } |
diff --git a/shared/models/server/server-config.model.ts b/shared/models/server/server-config.model.ts index 217d142cd..38e1941d8 100644 --- a/shared/models/server/server-config.model.ts +++ b/shared/models/server/server-config.model.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { NSFWPolicyType } from '../videos/nsfw-policy.type' | 1 | import { NSFWPolicyType } from '../videos/nsfw-policy.type' |
2 | import { CONFIG } from '../../../server/initializers' | ||
2 | 3 | ||
3 | export interface ServerConfig { | 4 | export interface ServerConfig { |
4 | serverVersion: string | 5 | serverVersion: string |
@@ -23,6 +24,14 @@ export interface ServerConfig { | |||
23 | enabledResolutions: number[] | 24 | enabledResolutions: number[] |
24 | } | 25 | } |
25 | 26 | ||
27 | import: { | ||
28 | video: { | ||
29 | http: { | ||
30 | enabled: boolean | ||
31 | } | ||
32 | } | ||
33 | } | ||
34 | |||
26 | avatar: { | 35 | avatar: { |
27 | file: { | 36 | file: { |
28 | size: { | 37 | size: { |