]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
We don't need services anymore for validators
[github/Chocobozzz/PeerTube.git] / client / src / app / +admin / config / edit-custom-config / edit-custom-config.component.ts
1 import { forkJoin } from 'rxjs'
2 import { ViewportScroller } from '@angular/common'
3 import { AfterViewChecked, Component, OnInit, ViewChild } from '@angular/core'
4 import { ConfigService } from '@app/+admin/config/shared/config.service'
5 import { Notifier } from '@app/core'
6 import { ServerService } from '@app/core/server/server.service'
7 import {
8 ADMIN_EMAIL_VALIDATOR,
9 CACHE_CAPTIONS_SIZE_VALIDATOR,
10 CACHE_PREVIEWS_SIZE_VALIDATOR,
11 INDEX_URL_VALIDATOR,
12 INSTANCE_NAME_VALIDATOR,
13 INSTANCE_SHORT_DESCRIPTION_VALIDATOR,
14 SEARCH_INDEX_URL_VALIDATOR,
15 SERVICES_TWITTER_USERNAME_VALIDATOR,
16 SIGNUP_LIMIT_VALIDATOR,
17 TRANSCODING_THREADS_VALIDATOR
18 } from '@app/shared/form-validators/custom-config-validators'
19 import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators'
20 import { FormReactive, FormValidatorService, SelectOptionsItem } from '@app/shared/shared-forms'
21 import { NgbNav } from '@ng-bootstrap/ng-bootstrap'
22 import { CustomConfig, ServerConfig } from '@shared/models'
23
24 @Component({
25 selector: 'my-edit-custom-config',
26 templateUrl: './edit-custom-config.component.html',
27 styleUrls: [ './edit-custom-config.component.scss' ]
28 })
29 export class EditCustomConfigComponent extends FormReactive implements OnInit, AfterViewChecked {
30 // FIXME: use built-in router
31 @ViewChild('nav') nav: NgbNav
32
33 initDone = false
34 customConfig: CustomConfig
35
36 resolutions: { id: string, label: string, description?: string }[] = []
37 transcodingThreadOptions: { label: string, value: number }[] = []
38
39 languageItems: SelectOptionsItem[] = []
40 categoryItems: SelectOptionsItem[] = []
41
42 private serverConfig: ServerConfig
43
44 constructor (
45 private viewportScroller: ViewportScroller,
46 protected formValidatorService: FormValidatorService,
47 private notifier: Notifier,
48 private configService: ConfigService,
49 private serverService: ServerService
50 ) {
51 super()
52
53 this.resolutions = [
54 {
55 id: '0p',
56 label: $localize`Audio-only`,
57 description: $localize`A <code>.mp4</code> that keeps the original audio track, with no video`
58 },
59 {
60 id: '240p',
61 label: $localize`240p`
62 },
63 {
64 id: '360p',
65 label: $localize`360p`
66 },
67 {
68 id: '480p',
69 label: $localize`480p`
70 },
71 {
72 id: '720p',
73 label: $localize`720p`
74 },
75 {
76 id: '1080p',
77 label: $localize`1080p`
78 },
79 {
80 id: '2160p',
81 label: $localize`2160p`
82 }
83 ]
84
85 this.transcodingThreadOptions = [
86 { value: 0, label: $localize`Auto (via ffmpeg)` },
87 { value: 1, label: '1' },
88 { value: 2, label: '2' },
89 { value: 4, label: '4' },
90 { value: 8, label: '8' }
91 ]
92 }
93
94 get videoQuotaOptions () {
95 return this.configService.videoQuotaOptions
96 }
97
98 get videoQuotaDailyOptions () {
99 return this.configService.videoQuotaDailyOptions
100 }
101
102 get availableThemes () {
103 return this.serverConfig.theme.registered
104 .map(t => t.name)
105 }
106
107 getResolutionKey (resolution: string) {
108 return 'transcoding.resolutions.' + resolution
109 }
110
111 ngOnInit () {
112 this.serverConfig = this.serverService.getTmpConfig()
113 this.serverService.getConfig()
114 .subscribe(config => this.serverConfig = config)
115
116 const formGroupData: { [key in keyof CustomConfig ]: any } = {
117 instance: {
118 name: INSTANCE_NAME_VALIDATOR,
119 shortDescription: INSTANCE_SHORT_DESCRIPTION_VALIDATOR,
120 description: null,
121
122 isNSFW: false,
123 defaultNSFWPolicy: null,
124
125 terms: null,
126 codeOfConduct: null,
127
128 creationReason: null,
129 moderationInformation: null,
130 administrator: null,
131 maintenanceLifetime: null,
132 businessModel: null,
133
134 hardwareInformation: null,
135
136 categories: null,
137 languages: null,
138
139 defaultClientRoute: null,
140
141 customizations: {
142 javascript: null,
143 css: null
144 }
145 },
146 theme: {
147 default: null
148 },
149 services: {
150 twitter: {
151 username: SERVICES_TWITTER_USERNAME_VALIDATOR,
152 whitelisted: null
153 }
154 },
155 cache: {
156 previews: {
157 size: CACHE_PREVIEWS_SIZE_VALIDATOR
158 },
159 captions: {
160 size: CACHE_CAPTIONS_SIZE_VALIDATOR
161 }
162 },
163 signup: {
164 enabled: null,
165 limit: SIGNUP_LIMIT_VALIDATOR,
166 requiresEmailVerification: null
167 },
168 import: {
169 videos: {
170 http: {
171 enabled: null
172 },
173 torrent: {
174 enabled: null
175 }
176 }
177 },
178 admin: {
179 email: ADMIN_EMAIL_VALIDATOR
180 },
181 contactForm: {
182 enabled: null
183 },
184 user: {
185 videoQuota: USER_VIDEO_QUOTA_VALIDATOR,
186 videoQuotaDaily: USER_VIDEO_QUOTA_DAILY_VALIDATOR
187 },
188 transcoding: {
189 enabled: null,
190 threads: TRANSCODING_THREADS_VALIDATOR,
191 allowAdditionalExtensions: null,
192 allowAudioFiles: null,
193 resolutions: {},
194 hls: {
195 enabled: null
196 },
197 webtorrent: {
198 enabled: null
199 }
200 },
201 autoBlacklist: {
202 videos: {
203 ofUsers: {
204 enabled: null
205 }
206 }
207 },
208 followers: {
209 instance: {
210 enabled: null,
211 manualApproval: null
212 }
213 },
214 followings: {
215 instance: {
216 autoFollowBack: {
217 enabled: null
218 },
219 autoFollowIndex: {
220 enabled: null,
221 indexUrl: INDEX_URL_VALIDATOR
222 }
223 }
224 },
225 broadcastMessage: {
226 enabled: null,
227 level: null,
228 dismissable: null,
229 message: null
230 },
231 search: {
232 remoteUri: {
233 users: null,
234 anonymous: null
235 },
236 searchIndex: {
237 enabled: null,
238 url: SEARCH_INDEX_URL_VALIDATOR,
239 disableLocalSearch: null,
240 isDefaultSearch: null
241 }
242 }
243 }
244
245 const defaultValues = {
246 transcoding: {
247 resolutions: {}
248 }
249 }
250 for (const resolution of this.resolutions) {
251 defaultValues.transcoding.resolutions[resolution.id] = 'false'
252 formGroupData.transcoding.resolutions[resolution.id] = null
253 }
254
255 this.buildForm(formGroupData)
256 this.loadForm()
257 this.checkTranscodingFields()
258 }
259
260 ngAfterViewChecked () {
261 if (!this.initDone) {
262 this.initDone = true
263 this.gotoAnchor()
264 }
265 }
266
267 isTranscodingEnabled () {
268 return this.form.value['transcoding']['enabled'] === true
269 }
270
271 isSignupEnabled () {
272 return this.form.value['signup']['enabled'] === true
273 }
274
275 isSearchIndexEnabled () {
276 return this.form.value['search']['searchIndex']['enabled'] === true
277 }
278
279 isAutoFollowIndexEnabled () {
280 return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true
281 }
282
283 async formValidated () {
284 this.configService.updateCustomConfig(this.form.getRawValue())
285 .subscribe(
286 res => {
287 this.customConfig = res
288
289 // Reload general configuration
290 this.serverService.resetConfig()
291
292 this.updateForm()
293
294 this.notifier.success($localize`Configuration updated.`)
295 },
296
297 err => this.notifier.error(err.message)
298 )
299 }
300
301 gotoAnchor () {
302 const hashToNav = {
303 'customizations': 'advanced-configuration'
304 }
305 const hash = window.location.hash.replace('#', '')
306
307 if (hash && Object.keys(hashToNav).includes(hash)) {
308 this.nav.select(hashToNav[hash])
309 setTimeout(() => this.viewportScroller.scrollToAnchor(hash), 100)
310 }
311 }
312
313 private updateForm () {
314 this.form.patchValue(this.customConfig)
315 }
316
317 private loadForm () {
318 forkJoin([
319 this.configService.getCustomConfig(),
320 this.serverService.getVideoLanguages(),
321 this.serverService.getVideoCategories()
322 ]).subscribe(
323 ([ config, languages, categories ]) => {
324 this.customConfig = config
325
326 this.languageItems = languages.map(l => ({ label: l.label, id: l.id }))
327 this.categoryItems = categories.map(l => ({ label: l.label, id: l.id + '' }))
328
329 this.updateForm()
330 // Force form validation
331 this.forceCheck()
332 },
333
334 err => this.notifier.error(err.message)
335 )
336 }
337
338 private checkTranscodingFields () {
339 const hlsControl = this.form.get('transcoding.hls.enabled')
340 const webtorrentControl = this.form.get('transcoding.webtorrent.enabled')
341
342 webtorrentControl.valueChanges
343 .subscribe(newValue => {
344 if (newValue === false && !hlsControl.disabled) {
345 hlsControl.disable()
346 }
347
348 if (newValue === true && !hlsControl.enabled) {
349 hlsControl.enable()
350 }
351 })
352
353 hlsControl.valueChanges
354 .subscribe(newValue => {
355 if (newValue === false && !webtorrentControl.disabled) {
356 webtorrentControl.disable()
357 }
358
359 if (newValue === true && !webtorrentControl.enabled) {
360 webtorrentControl.enable()
361 }
362 })
363 }
364 }