+import omit from 'lodash-es/omit'
+import { forkJoin } from 'rxjs'
+import { SelectOptionsItem } from 'src/types/select-options-item.model'
import { Component, OnInit } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { ConfigService } from '@app/+admin/config/shared/config.service'
INDEX_URL_VALIDATOR,
INSTANCE_NAME_VALIDATOR,
INSTANCE_SHORT_DESCRIPTION_VALIDATOR,
+ MAX_INSTANCE_LIVES_VALIDATOR,
+ MAX_LIVE_DURATION_VALIDATOR,
+ MAX_USER_LIVES_VALIDATOR,
+ MAX_VIDEO_CHANNELS_PER_USER_VALIDATOR,
SEARCH_INDEX_URL_VALIDATOR,
SERVICES_TWITTER_USERNAME_VALIDATOR,
SIGNUP_LIMIT_VALIDATOR,
+ SIGNUP_MINIMUM_AGE_VALIDATOR,
TRANSCODING_THREADS_VALIDATOR
} from '@app/shared/form-validators/custom-config-validators'
import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators'
-import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
-import { CustomConfig, ServerConfig } from '@shared/models'
-import { forkJoin } from 'rxjs'
-import { SelectOptionsItem } from 'src/types/select-options-item.model'
+import { FormReactive, FormReactiveService } from '@app/shared/shared-forms'
+import { CustomPageService } from '@app/shared/shared-main/custom-page'
+import { CustomConfig, CustomPage, HTMLServerConfig } from '@shared/models'
import { EditConfigurationService } from './edit-configuration.service'
+type ComponentCustomConfig = CustomConfig & {
+ instanceCustomHomepage: CustomPage
+}
+
@Component({
selector: 'my-edit-custom-config',
templateUrl: './edit-custom-config.component.html',
export class EditCustomConfigComponent extends FormReactive implements OnInit {
activeNav: string
- customConfig: CustomConfig
- serverConfig: ServerConfig
+ customConfig: ComponentCustomConfig
+ serverConfig: HTMLServerConfig
+
+ homepage: CustomPage
languageItems: SelectOptionsItem[] = []
categoryItems: SelectOptionsItem[] = []
constructor (
+ protected formReactiveService: FormReactiveService,
private router: Router,
private route: ActivatedRoute,
- protected formValidatorService: FormValidatorService,
private notifier: Notifier,
private configService: ConfigService,
+ private customPage: CustomPageService,
private serverService: ServerService,
private editConfigurationService: EditConfigurationService
) {
}
ngOnInit () {
- this.serverConfig = this.serverService.getTmpConfig()
- this.serverService.getConfig()
- .subscribe(config => {
- this.serverConfig = config
- })
+ this.serverConfig = this.serverService.getHTMLConfig()
- const formGroupData: { [key in keyof CustomConfig ]: any } = {
+ const formGroupData: { [key in keyof ComponentCustomConfig ]: any } = {
instance: {
name: INSTANCE_NAME_VALIDATOR,
shortDescription: INSTANCE_SHORT_DESCRIPTION_VALIDATOR,
whitelisted: null
}
},
+ client: {
+ videos: {
+ miniature: {
+ preferAuthorDisplayName: null
+ }
+ },
+ menu: {
+ login: {
+ redirectOnSingleExternalAuth: null
+ }
+ }
+ },
cache: {
previews: {
size: CACHE_PREVIEWS_SIZE_VALIDATOR
},
captions: {
size: CACHE_CAPTIONS_SIZE_VALIDATOR
+ },
+ torrents: {
+ size: CACHE_CAPTIONS_SIZE_VALIDATOR
}
},
signup: {
enabled: null,
limit: SIGNUP_LIMIT_VALIDATOR,
- requiresEmailVerification: null
+ requiresApproval: null,
+ requiresEmailVerification: null,
+ minimumAge: SIGNUP_MINIMUM_AGE_VALIDATOR
},
import: {
videos: {
torrent: {
enabled: null
}
+ },
+ videoChannelSynchronization: {
+ enabled: null
}
},
trending: {
enabled: null
},
user: {
+ history: {
+ videos: {
+ enabled: null
+ }
+ },
videoQuota: USER_VIDEO_QUOTA_VALIDATOR,
videoQuotaDaily: USER_VIDEO_QUOTA_DAILY_VALIDATOR
},
+ videoChannels: {
+ maxPerUser: MAX_VIDEO_CHANNELS_PER_USER_VALIDATOR
+ },
transcoding: {
enabled: null,
threads: TRANSCODING_THREADS_VALIDATOR,
profile: null,
concurrency: CONCURRENCY_VALIDATOR,
resolutions: {},
+ alwaysTranscodeOriginalResolution: null,
hls: {
enabled: null
},
webtorrent: {
enabled: null
+ },
+ remoteRunners: {
+ enabled: null
}
},
live: {
enabled: null,
- maxDuration: null,
- maxInstanceLives: null,
- maxUserLives: null,
+ maxDuration: MAX_LIVE_DURATION_VALIDATOR,
+ maxInstanceLives: MAX_INSTANCE_LIVES_VALIDATOR,
+ maxUserLives: MAX_USER_LIVES_VALIDATOR,
allowReplay: null,
+ latencySetting: {
+ enabled: null
+ },
transcoding: {
enabled: null,
threads: TRANSCODING_THREADS_VALIDATOR,
profile: null,
- resolutions: {}
+ resolutions: {},
+ alwaysTranscodeOriginalResolution: null,
+ remoteRunners: {
+ enabled: null
+ }
+ }
+ },
+ videoStudio: {
+ enabled: null,
+ remoteRunners: {
+ enabled: null
}
},
autoBlacklist: {
disableLocalSearch: null,
isDefaultSearch: null
}
+ },
+
+ instanceCustomHomepage: {
+ content: null
}
}
const defaultValues = {
transcoding: {
- resolutions: {}
+ resolutions: {} as { [id: string]: string }
},
live: {
transcoding: {
- resolutions: {}
+ resolutions: {} as { [id: string]: string }
}
}
}
this.loadConfigAndUpdateForm()
this.loadCategoriesAndLanguages()
+
+ if (!this.isUpdateAllowed()) {
+ this.form.disable()
+ }
}
- async formValidated () {
- const value: CustomConfig = this.form.getRawValue()
+ formValidated () {
+ this.forceCheck()
+ if (!this.form.valid) return
- this.configService.updateCustomConfig(value)
- .subscribe(
- res => {
- this.customConfig = res
+ const value: ComponentCustomConfig = this.form.getRawValue()
+
+ forkJoin([
+ this.configService.updateCustomConfig(omit(value, 'instanceCustomHomepage')),
+ this.customPage.updateInstanceHomepage(value.instanceCustomHomepage.content)
+ ])
+ .subscribe({
+ next: ([ resConfig ]) => {
+ const instanceCustomHomepage = {
+ content: value.instanceCustomHomepage.content
+ }
+
+ this.customConfig = { ...resConfig, instanceCustomHomepage }
// Reload general configuration
this.serverService.resetConfig()
+ .subscribe(config => {
+ this.serverConfig = config
+ })
this.updateForm()
this.notifier.success($localize`Configuration updated.`)
},
- err => this.notifier.error(err.message)
- )
+ error: err => this.notifier.error(err.message)
+ })
+ }
+
+ isUpdateAllowed () {
+ return this.serverConfig.webadmin.configuration.edition.allowed === true
}
hasConsistentOptions () {
this.router.navigate([], { fragment: this.activeNav })
}
+ grabAllErrors (errorObjectArg?: any) {
+ const errorObject = errorObjectArg || this.formErrors
+
+ let acc: string[] = []
+
+ for (const key of Object.keys(errorObject)) {
+ const value = errorObject[key]
+ if (!value) continue
+
+ if (typeof value === 'string') {
+ acc.push(value)
+ } else {
+ acc = acc.concat(this.grabAllErrors(value))
+ }
+ }
+
+ return acc
+ }
+
private updateForm () {
this.form.patchValue(this.customConfig)
}
private loadConfigAndUpdateForm () {
- this.configService.getCustomConfig()
- .subscribe(config => {
- this.customConfig = config
+ forkJoin([
+ this.configService.getCustomConfig(),
+ this.customPage.getInstanceHomepage()
+ ]).subscribe({
+ next: ([ config, homepage ]) => {
+ this.customConfig = { ...config, instanceCustomHomepage: homepage }
this.updateForm()
- // Force form validation
- this.forceCheck()
+ this.markAllAsDirty()
},
- err => this.notifier.error(err.message)
- )
+ error: err => this.notifier.error(err.message)
+ })
}
private loadCategoriesAndLanguages () {
forkJoin([
this.serverService.getVideoLanguages(),
this.serverService.getVideoCategories()
- ]).subscribe(
- ([ languages, categories ]) => {
+ ]).subscribe({
+ next: ([ languages, categories ]) => {
this.languageItems = languages.map(l => ({ label: l.label, id: l.id }))
this.categoryItems = categories.map(l => ({ label: l.label, id: l.id + '' }))
},
- err => this.notifier.error(err.message)
- )
+ error: err => this.notifier.error(err.message)
+ })
}
}