mirror of
https://github.com/Chocobozzz/PeerTube.git
synced 2025-10-05 19:42:24 +02:00
Add defaults values config in web admin
This commit is contained in:
parent
eb11e5793f
commit
e9bb222b6c
9 changed files with 241 additions and 40 deletions
|
@ -2,7 +2,7 @@ import { inject } from '@angular/core'
|
||||||
import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot, Routes } from '@angular/router'
|
import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot, Routes } from '@angular/router'
|
||||||
import { CanDeactivateGuard, ServerService, UserRightGuard } from '@app/core'
|
import { CanDeactivateGuard, ServerService, UserRightGuard } from '@app/core'
|
||||||
import { CustomPageService } from '@app/shared/shared-main/custom-page/custom-page.service'
|
import { CustomPageService } from '@app/shared/shared-main/custom-page/custom-page.service'
|
||||||
import { CustomConfig, UserRight, VideoConstant } from '@peertube/peertube-models'
|
import { CustomConfig, UserRight, VideoCommentPolicyType, VideoConstant, VideoPrivacyType } from '@peertube/peertube-models'
|
||||||
import { map } from 'rxjs'
|
import { map } from 'rxjs'
|
||||||
import { AdminConfigComponent } from './admin-config.component'
|
import { AdminConfigComponent } from './admin-config.component'
|
||||||
import {
|
import {
|
||||||
|
@ -33,6 +33,24 @@ export const languagesResolver: ResolveFn<VideoConstant<string>[]> = (_route: Ac
|
||||||
return inject(ServerService).getVideoLanguages()
|
return inject(ServerService).getVideoLanguages()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const licencesResolver: ResolveFn<VideoConstant<number>[]> = (_route: ActivatedRouteSnapshot, _state: RouterStateSnapshot) => {
|
||||||
|
return inject(ServerService).getVideoLicences()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const privaciesResolver: ResolveFn<VideoConstant<VideoPrivacyType>[]> = (
|
||||||
|
_route: ActivatedRouteSnapshot,
|
||||||
|
_state: RouterStateSnapshot
|
||||||
|
) => {
|
||||||
|
return inject(ServerService).getVideoPrivacies()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const commentPoliciesResolver: ResolveFn<VideoConstant<VideoCommentPolicyType>[]> = (
|
||||||
|
_route: ActivatedRouteSnapshot,
|
||||||
|
_state: RouterStateSnapshot
|
||||||
|
) => {
|
||||||
|
return inject(ServerService).getCommentPolicies()
|
||||||
|
}
|
||||||
|
|
||||||
export const configRoutes: Routes = [
|
export const configRoutes: Routes = [
|
||||||
{
|
{
|
||||||
path: 'config',
|
path: 'config',
|
||||||
|
@ -97,6 +115,11 @@ export const configRoutes: Routes = [
|
||||||
path: 'general',
|
path: 'general',
|
||||||
component: AdminConfigGeneralComponent,
|
component: AdminConfigGeneralComponent,
|
||||||
canDeactivate: [ CanDeactivateGuard ],
|
canDeactivate: [ CanDeactivateGuard ],
|
||||||
|
resolve: {
|
||||||
|
privacies: privaciesResolver,
|
||||||
|
licences: licencesResolver,
|
||||||
|
commentPolicies: commentPoliciesResolver
|
||||||
|
},
|
||||||
data: {
|
data: {
|
||||||
meta: {
|
meta: {
|
||||||
title: $localize`General configuration`
|
title: $localize`General configuration`
|
||||||
|
|
|
@ -53,9 +53,9 @@
|
||||||
>
|
>
|
||||||
<ng-container ngProjectAs="description">
|
<ng-container ngProjectAs="description">
|
||||||
@if (countExternalAuth() === 0) {
|
@if (countExternalAuth() === 0) {
|
||||||
<span *ngIf="" i18n>⚠️ You don't have any external auth plugin enabled.</span>
|
<span i18n>⚠️ You don't have any external auth plugin enabled</span>
|
||||||
} @else if (countExternalAuth() > 1) {
|
} @else if (countExternalAuth() > 1) {
|
||||||
<span i18n>⚠️ You have multiple external auth plugins enabled.</span>
|
<span i18n>⚠️ You have multiple external auth plugins enabled</span>
|
||||||
}
|
}
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</my-peertube-checkbox>
|
</my-peertube-checkbox>
|
||||||
|
@ -137,7 +137,7 @@
|
||||||
i18n-labelText labelText="Enable Signup"
|
i18n-labelText labelText="Enable Signup"
|
||||||
>
|
>
|
||||||
<ng-container ngProjectAs="description">
|
<ng-container ngProjectAs="description">
|
||||||
<span i18n>⚠️ This functionality requires a lot of attention and extra moderation.</span>
|
<span i18n>⚠️ This functionality requires a lot of attention and extra moderation</span>
|
||||||
|
|
||||||
<my-alert type="primary" class="d-block mt-2" *ngIf="signupAlertMessage">{{ signupAlertMessage }}</my-alert>
|
<my-alert type="primary" class="d-block mt-2" *ngIf="signupAlertMessage">{{ signupAlertMessage }}</my-alert>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
@ -171,7 +171,7 @@
|
||||||
|
|
||||||
<div *ngIf="formErrors.signup.limit" class="form-error" role="alert">{{ formErrors.signup.limit }}</div>
|
<div *ngIf="formErrors.signup.limit" class="form-error" role="alert">{{ formErrors.signup.limit }}</div>
|
||||||
|
|
||||||
<small i18n *ngIf="hasUnlimitedSignup()" class="muted small">Signup won't be limited to a fixed number of users.</small>
|
<small i18n *ngIf="hasUnlimitedSignup()" class="muted small">Signup won't be limited to a fixed number of users</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div [ngClass]="getDisabledSignupClass()" class="mt-3">
|
<div [ngClass]="getDisabledSignupClass()" class="mt-3">
|
||||||
|
@ -253,7 +253,7 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label i18n for="importConcurrency">Import jobs concurrency</label>
|
<label i18n for="importConcurrency">Import jobs concurrency</label>
|
||||||
<span i18n class="small muted ms-1">allows to import multiple videos in parallel. ⚠️ Requires a PeerTube restart.</span>
|
<span i18n class="small muted ms-1">allows to import multiple videos in parallel. ⚠️ Requires a PeerTube restart</span>
|
||||||
|
|
||||||
<div class="number-with-unit">
|
<div class="number-with-unit">
|
||||||
<input type="number" id="importConcurrency" formControlName="concurrency" />
|
<input type="number" id="importConcurrency" formControlName="concurrency" />
|
||||||
|
@ -399,6 +399,35 @@
|
||||||
</my-peertube-checkbox>
|
</my-peertube-checkbox>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container formGroupName="defaults">
|
||||||
|
<ng-container formGroupName="publish">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="defaultsPublishPrivacy">Default video privacy</label>
|
||||||
|
|
||||||
|
<my-select-options inputId="defaultsPublishPrivacy" [items]="privacyOptions" formControlName="privacy"></my-select-options>
|
||||||
|
|
||||||
|
<div *ngIf="formErrors.defaults.publish.privacy" class="form-error" role="alert">{{ formErrors.defaults.publish.privacy }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="defaultsPublishLicence">Default video licence</label>
|
||||||
|
|
||||||
|
<my-select-options inputId="defaultsPublishLicence" [items]="licenceOptions" formControlName="licence"></my-select-options>
|
||||||
|
|
||||||
|
<div *ngIf="formErrors.defaults.publish.licence" class="form-error" role="alert">{{ formErrors.defaults.publish.licence }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label i18n for="defaultsPublishCommentsPolicy">Default comment policy</label>
|
||||||
|
|
||||||
|
<my-select-options inputId="defaultsPublishCommentsPolicy" [items]="commentPoliciesOptions" formControlName="commentsPolicy"></my-select-options>
|
||||||
|
|
||||||
|
<div *ngIf="formErrors.defaults.publish.commentsPolicy" class="form-error" role="alert">{{ formErrors.defaults.publish.commentsPolicy }}</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -424,6 +453,41 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pt-two-cols mt-4">
|
||||||
|
<div class="title-col">
|
||||||
|
<h2 i18n>PLAYER</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content-col">
|
||||||
|
<ng-container formGroupName="defaults">
|
||||||
|
|
||||||
|
<div class="form-group" formGroupName="player">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="defaultsPlayerAutoplay" formControlName="autoPlay"
|
||||||
|
i18n-labelText labelText="Automatically play videos in the player"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-container formGroupName="p2p">
|
||||||
|
|
||||||
|
<div class="form-group" formGroupName="webapp">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="defaultsP2PWebappEnabled" formControlName="enabled"
|
||||||
|
i18n-labelText labelText="Enable P2P streaming by default on your platform"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" formGroupName="embed">
|
||||||
|
<my-peertube-checkbox
|
||||||
|
inputName="defaultsP2PEmbedEnabled" formControlName="enabled"
|
||||||
|
i18n-labelText labelText="Enable P2P streaming by default for videos embedded on external websites"
|
||||||
|
></my-peertube-checkbox>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="pt-two-cols mt-4">
|
<div class="pt-two-cols mt-4">
|
||||||
<div class="title-col">
|
<div class="title-col">
|
||||||
<h2 i18n>SEARCH</h2>
|
<h2 i18n>SEARCH</h2>
|
||||||
|
@ -465,7 +529,7 @@
|
||||||
i18n-labelText labelText="Enable global search"
|
i18n-labelText labelText="Enable global search"
|
||||||
>
|
>
|
||||||
<ng-container ngProjectAs="description">
|
<ng-container ngProjectAs="description">
|
||||||
<div i18n>⚠️ This functionality depends heavily on the moderation of platforms followed by the search index you select.</div>
|
<div i18n>⚠️ This functionality depends heavily on the moderation of platforms followed by the search index you select</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container ngProjectAs="extra">
|
<ng-container ngProjectAs="extra">
|
||||||
|
@ -573,7 +637,7 @@
|
||||||
|
|
||||||
<my-select-options inputId="exportUsersExportExpiration" [items]="exportExpirationOptions" formControlName="exportExpiration"></my-select-options>
|
<my-select-options inputId="exportUsersExportExpiration" [items]="exportExpirationOptions" formControlName="exportExpiration"></my-select-options>
|
||||||
|
|
||||||
<div i18n class="mt-1 small muted">The archive file is deleted after this period.</div>
|
<div i18n class="mt-1 small muted">The archive file is deleted after this period</div>
|
||||||
|
|
||||||
<div *ngIf="formErrors.export.users.exportExpiration" class="form-error" role="alert">{{ formErrors.export.users.exportExpiration }}</div>
|
<div *ngIf="formErrors.export.users.exportExpiration" class="form-error" role="alert">{{ formErrors.export.users.exportExpiration }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -626,7 +690,7 @@
|
||||||
i18n-labelText labelText="Automatically follow back followers that follow your platform"
|
i18n-labelText labelText="Automatically follow back followers that follow your platform"
|
||||||
>
|
>
|
||||||
<ng-container ngProjectAs="description">
|
<ng-container ngProjectAs="description">
|
||||||
<span i18n>⚠️ This functionality requires a lot of attention and extra moderation.</span>
|
<span i18n>⚠️ This functionality requires a lot of attention and extra moderation</span>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</my-peertube-checkbox>
|
</my-peertube-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -23,7 +23,8 @@ import {
|
||||||
import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators'
|
import { USER_VIDEO_QUOTA_DAILY_VALIDATOR, USER_VIDEO_QUOTA_VALIDATOR } from '@app/shared/form-validators/user-validators'
|
||||||
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
|
import { FormReactiveService } from '@app/shared/shared-forms/form-reactive.service'
|
||||||
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
|
import { AlertComponent } from '@app/shared/shared-main/common/alert.component'
|
||||||
import { BroadcastMessageLevel, CustomConfig } from '@peertube/peertube-models'
|
import { VideoService } from '@app/shared/shared-main/video/video.service'
|
||||||
|
import { BroadcastMessageLevel, CustomConfig, VideoCommentPolicyType, VideoConstant, VideoPrivacyType } from '@peertube/peertube-models'
|
||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
import { pairwise } from 'rxjs/operators'
|
import { pairwise } from 'rxjs/operators'
|
||||||
import { SelectOptionsItem } from 'src/types/select-options-item.model'
|
import { SelectOptionsItem } from 'src/types/select-options-item.model'
|
||||||
|
@ -172,6 +173,28 @@ type Form = {
|
||||||
storyboards: FormGroup<{
|
storyboards: FormGroup<{
|
||||||
enabled: FormControl<boolean>
|
enabled: FormControl<boolean>
|
||||||
}>
|
}>
|
||||||
|
|
||||||
|
defaults: FormGroup<{
|
||||||
|
publish: FormGroup<{
|
||||||
|
commentsPolicy: FormControl<VideoCommentPolicyType>
|
||||||
|
privacy: FormControl<VideoPrivacyType>
|
||||||
|
licence: FormControl<number>
|
||||||
|
}>
|
||||||
|
|
||||||
|
p2p: FormGroup<{
|
||||||
|
webapp: FormGroup<{
|
||||||
|
enabled: FormControl<boolean>
|
||||||
|
}>
|
||||||
|
|
||||||
|
embed: FormGroup<{
|
||||||
|
enabled: FormControl<boolean>
|
||||||
|
}>
|
||||||
|
}>
|
||||||
|
|
||||||
|
player: FormGroup<{
|
||||||
|
autoPlay: FormControl<boolean>
|
||||||
|
}>
|
||||||
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -198,6 +221,7 @@ export class AdminConfigGeneralComponent implements OnInit, OnDestroy, CanCompon
|
||||||
private route = inject(ActivatedRoute)
|
private route = inject(ActivatedRoute)
|
||||||
private formReactiveService = inject(FormReactiveService)
|
private formReactiveService = inject(FormReactiveService)
|
||||||
private adminConfigService = inject(AdminConfigService)
|
private adminConfigService = inject(AdminConfigService)
|
||||||
|
private videoService = inject(VideoService)
|
||||||
|
|
||||||
form: FormGroup<Form>
|
form: FormGroup<Form>
|
||||||
formErrors: FormReactiveErrorsTyped<Form> = {}
|
formErrors: FormReactiveErrorsTyped<Form> = {}
|
||||||
|
@ -209,12 +233,26 @@ export class AdminConfigGeneralComponent implements OnInit, OnDestroy, CanCompon
|
||||||
exportExpirationOptions: SelectOptionsItem[] = []
|
exportExpirationOptions: SelectOptionsItem[] = []
|
||||||
exportMaxUserVideoQuotaOptions: SelectOptionsItem[] = []
|
exportMaxUserVideoQuotaOptions: SelectOptionsItem[] = []
|
||||||
|
|
||||||
|
privacyOptions: SelectOptionsItem[] = []
|
||||||
|
commentPoliciesOptions: SelectOptionsItem[] = []
|
||||||
|
licenceOptions: SelectOptionsItem[] = []
|
||||||
|
|
||||||
private customConfig: CustomConfig
|
private customConfig: CustomConfig
|
||||||
private customConfigSub: Subscription
|
private customConfigSub: Subscription
|
||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.customConfig = this.route.parent.snapshot.data['customConfig']
|
this.customConfig = this.route.parent.snapshot.data['customConfig']
|
||||||
|
|
||||||
|
const data = this.route.snapshot.data as {
|
||||||
|
licences: VideoConstant<number>[]
|
||||||
|
privacies: VideoConstant<VideoPrivacyType>[]
|
||||||
|
commentPolicies: VideoConstant<VideoCommentPolicyType>[]
|
||||||
|
}
|
||||||
|
|
||||||
|
this.privacyOptions = this.videoService.explainedPrivacyLabels(data.privacies).videoPrivacies
|
||||||
|
this.licenceOptions = data.licences
|
||||||
|
this.commentPoliciesOptions = data.commentPolicies
|
||||||
|
|
||||||
this.buildLandingPageOptions()
|
this.buildLandingPageOptions()
|
||||||
|
|
||||||
this.exportExpirationOptions = [
|
this.exportExpirationOptions = [
|
||||||
|
@ -360,9 +398,26 @@ export class AdminConfigGeneralComponent implements OnInit, OnDestroy, CanCompon
|
||||||
isDefaultSearch: null
|
isDefaultSearch: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
storyboards: {
|
storyboards: {
|
||||||
enabled: null
|
enabled: null
|
||||||
|
},
|
||||||
|
defaults: {
|
||||||
|
publish: {
|
||||||
|
commentsPolicy: null,
|
||||||
|
privacy: null,
|
||||||
|
licence: null
|
||||||
|
},
|
||||||
|
p2p: {
|
||||||
|
webapp: {
|
||||||
|
enabled: null
|
||||||
|
},
|
||||||
|
embed: {
|
||||||
|
enabled: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
player: {
|
||||||
|
autoPlay: null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { exists } from '@peertube/peertube-core-utils'
|
import { exists } from '@peertube/peertube-core-utils'
|
||||||
import { CustomConfig, VideoPrivacy } from '@peertube/peertube-models'
|
import { CustomConfig, VideoCommentPolicy, VideoPrivacy } from '@peertube/peertube-models'
|
||||||
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
|
import { AttributesOnly } from '@peertube/peertube-typescript-utils'
|
||||||
import { getBytes } from '@root-helpers/bytes'
|
import { getBytes } from '@root-helpers/bytes'
|
||||||
import merge from 'lodash-es/merge'
|
import merge from 'lodash-es/merge'
|
||||||
|
@ -16,6 +16,7 @@ export class UsageType {
|
||||||
live: EnabledDisabled
|
live: EnabledDisabled
|
||||||
globalSearch: EnabledDisabled
|
globalSearch: EnabledDisabled
|
||||||
defaultPrivacy: typeof VideoPrivacy.INTERNAL | typeof VideoPrivacy.PUBLIC
|
defaultPrivacy: typeof VideoPrivacy.INTERNAL | typeof VideoPrivacy.PUBLIC
|
||||||
|
defaultCommentPolicy: typeof VideoCommentPolicy.REQUIRES_APPROVAL
|
||||||
p2p: EnabledDisabled
|
p2p: EnabledDisabled
|
||||||
federation: EnabledDisabled
|
federation: EnabledDisabled
|
||||||
keepOriginalVideo: EnabledDisabled
|
keepOriginalVideo: EnabledDisabled
|
||||||
|
@ -46,7 +47,7 @@ export class UsageType {
|
||||||
usageType.keepOriginalVideo = 'disabled'
|
usageType.keepOriginalVideo = 'disabled'
|
||||||
usageType.allowReplaceFile = 'disabled'
|
usageType.allowReplaceFile = 'disabled'
|
||||||
|
|
||||||
// Use current config for: authType, preferDisplayName and transcription
|
// Use current config for: defaultCommentPolicy, authType, preferDisplayName and transcription
|
||||||
|
|
||||||
usageType.compute()
|
usageType.compute()
|
||||||
|
|
||||||
|
@ -69,7 +70,7 @@ export class UsageType {
|
||||||
usageType.allowReplaceFile = 'enabled'
|
usageType.allowReplaceFile = 'enabled'
|
||||||
usageType.preferDisplayName = 'enabled'
|
usageType.preferDisplayName = 'enabled'
|
||||||
|
|
||||||
// Use current config for: authType and transcription
|
// Use current config for: defaultCommentPolicy, authType and transcription
|
||||||
|
|
||||||
usageType.compute()
|
usageType.compute()
|
||||||
|
|
||||||
|
@ -94,6 +95,8 @@ export class UsageType {
|
||||||
usageType.authType = 'local'
|
usageType.authType = 'local'
|
||||||
usageType.transcription = 'enabled'
|
usageType.transcription = 'enabled'
|
||||||
|
|
||||||
|
usageType.defaultCommentPolicy = VideoCommentPolicy.REQUIRES_APPROVAL
|
||||||
|
|
||||||
// Use current config for: federation
|
// Use current config for: federation
|
||||||
|
|
||||||
usageType.compute()
|
usageType.compute()
|
||||||
|
@ -107,7 +110,7 @@ export class UsageType {
|
||||||
this.config = {}
|
this.config = {}
|
||||||
|
|
||||||
this.computeRegistration()
|
this.computeRegistration()
|
||||||
this.computeVideoPrivacy()
|
this.computeDefaultVideoPrivacy()
|
||||||
this.computeVideoQuota()
|
this.computeVideoQuota()
|
||||||
this.computeKeepOriginalVideo()
|
this.computeKeepOriginalVideo()
|
||||||
this.computeReplaceVideoFile()
|
this.computeReplaceVideoFile()
|
||||||
|
@ -115,6 +118,7 @@ export class UsageType {
|
||||||
this.computeStreamLives()
|
this.computeStreamLives()
|
||||||
this.computeP2P()
|
this.computeP2P()
|
||||||
this.computeGlobalSearch()
|
this.computeGlobalSearch()
|
||||||
|
this.computeDefaultVideoCommentPolicy()
|
||||||
this.computeFederation()
|
this.computeFederation()
|
||||||
this.computeMiniatureSettings()
|
this.computeMiniatureSettings()
|
||||||
this.computeTranscription()
|
this.computeTranscription()
|
||||||
|
@ -256,7 +260,7 @@ export class UsageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private computeVideoPrivacy () {
|
private computeDefaultVideoPrivacy () {
|
||||||
if (!exists(this.defaultPrivacy)) return
|
if (!exists(this.defaultPrivacy)) return
|
||||||
|
|
||||||
this.addConfig({
|
this.addConfig({
|
||||||
|
@ -274,6 +278,20 @@ export class UsageType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private computeDefaultVideoCommentPolicy () {
|
||||||
|
if (!exists(this.defaultCommentPolicy)) return
|
||||||
|
|
||||||
|
this.addConfig({
|
||||||
|
defaults: {
|
||||||
|
publish: {
|
||||||
|
commentsPolicy: this.defaultCommentPolicy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.addExplanation($localize`<strong>Require approval</strong> by default of new video comment`)
|
||||||
|
}
|
||||||
|
|
||||||
private computeP2P () {
|
private computeP2P () {
|
||||||
if (!exists(this.p2p)) return
|
if (!exists(this.p2p)) return
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
|
||||||
import merge from 'lodash-es/merge.js'
|
|
||||||
import { omit } from '@peertube/peertube-core-utils'
|
import { omit } from '@peertube/peertube-core-utils'
|
||||||
import { ActorImageType, CustomConfig, HttpStatusCode } from '@peertube/peertube-models'
|
import { ActorImageType, CustomConfig, HttpStatusCode } from '@peertube/peertube-models'
|
||||||
|
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
||||||
import {
|
import {
|
||||||
cleanupTests,
|
cleanupTests,
|
||||||
createSingleServer,
|
createSingleServer,
|
||||||
|
@ -12,7 +12,7 @@ import {
|
||||||
PeerTubeServer,
|
PeerTubeServer,
|
||||||
setAccessTokensToServers
|
setAccessTokensToServers
|
||||||
} from '@peertube/peertube-server-commands'
|
} from '@peertube/peertube-server-commands'
|
||||||
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
|
import merge from 'lodash-es/merge.js'
|
||||||
|
|
||||||
describe('Test config API validators', function () {
|
describe('Test config API validators', function () {
|
||||||
const path = '/api/v1/config/custom'
|
const path = '/api/v1/config/custom'
|
||||||
|
@ -91,13 +91,29 @@ describe('Test config API validators', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a bad default NSFW policy', async function () {
|
it('Should fail with a bad default NSFW policy', async function () {
|
||||||
const newUpdateParams = {
|
const newUpdateParams = merge({}, updateParams, {
|
||||||
...updateParams,
|
|
||||||
|
|
||||||
instance: {
|
instance: {
|
||||||
defaultNSFWPolicy: 'hello'
|
defaultNSFWPolicy: 'hello'
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
|
await makePutBodyRequest({
|
||||||
|
url: server.url,
|
||||||
|
path,
|
||||||
|
fields: newUpdateParams,
|
||||||
|
token: server.accessToken,
|
||||||
|
expectedStatus: HttpStatusCode.BAD_REQUEST_400
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Should fail with a bad default comment policy', async function () {
|
||||||
|
const newUpdateParams = merge({}, updateParams, {
|
||||||
|
defaults: {
|
||||||
|
publish: {
|
||||||
|
commentsPolicy: 11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
await makePutBodyRequest({
|
await makePutBodyRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
|
@ -110,16 +126,14 @@ describe('Test config API validators', function () {
|
||||||
|
|
||||||
it('Should fail if email disabled and signup requires email verification', async function () {
|
it('Should fail if email disabled and signup requires email verification', async function () {
|
||||||
// opposite scenario - success when enable enabled - covered via tests/api/users/user-verification.ts
|
// opposite scenario - success when enable enabled - covered via tests/api/users/user-verification.ts
|
||||||
const newUpdateParams = {
|
const newUpdateParams = merge({}, updateParams, {
|
||||||
...updateParams,
|
|
||||||
|
|
||||||
signup: {
|
signup: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
limit: 5,
|
limit: 5,
|
||||||
requiresApproval: true,
|
requiresApproval: true,
|
||||||
requiresEmailVerification: true
|
requiresEmailVerification: true
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
await makePutBodyRequest({
|
await makePutBodyRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
|
@ -131,18 +145,17 @@ describe('Test config API validators', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a disabled web videos & hls transcoding', async function () {
|
it('Should fail with a disabled web videos & hls transcoding', async function () {
|
||||||
const newUpdateParams = {
|
const newUpdateParams = merge({}, updateParams, {
|
||||||
...updateParams,
|
|
||||||
|
|
||||||
transcoding: {
|
transcoding: {
|
||||||
|
enabled: true,
|
||||||
hls: {
|
hls: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
web_videos: {
|
webVideos: {
|
||||||
enabled: false
|
enabled: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
|
||||||
await makePutBodyRequest({
|
await makePutBodyRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
|
@ -154,7 +167,7 @@ describe('Test config API validators', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should fail with a disabled http upload & enabled sync', async function () {
|
it('Should fail with a disabled http upload & enabled sync', async function () {
|
||||||
const newUpdateParams: CustomConfig = merge({}, updateParams, {
|
const newUpdateParams: CustomConfig = merge({}, {}, updateParams, {
|
||||||
import: {
|
import: {
|
||||||
videos: {
|
videos: {
|
||||||
http: { enabled: false }
|
http: { enabled: false }
|
||||||
|
@ -184,7 +197,6 @@ describe('Test config API validators', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('When deleting the configuration', function () {
|
describe('When deleting the configuration', function () {
|
||||||
|
|
||||||
it('Should fail without token', async function () {
|
it('Should fail without token', async function () {
|
||||||
await makeDeleteRequest({
|
await makeDeleteRequest({
|
||||||
url: server.url,
|
url: server.url,
|
||||||
|
|
|
@ -146,6 +146,14 @@ function checkInitialConfig (server: PeerTubeServer, data: CustomConfig) {
|
||||||
expect(data.export.users.enabled).to.be.true
|
expect(data.export.users.enabled).to.be.true
|
||||||
expect(data.export.users.exportExpiration).to.equal(1000 * 3600 * 48)
|
expect(data.export.users.exportExpiration).to.equal(1000 * 3600 * 48)
|
||||||
expect(data.export.users.maxUserVideoQuota).to.equal(10737418240)
|
expect(data.export.users.maxUserVideoQuota).to.equal(10737418240)
|
||||||
|
|
||||||
|
expect(data.defaults.publish.commentsPolicy).to.equal(VideoCommentPolicy.ENABLED)
|
||||||
|
expect(data.defaults.publish.downloadEnabled).to.be.true
|
||||||
|
expect(data.defaults.publish.licence).to.be.null
|
||||||
|
expect(data.defaults.publish.privacy).to.equal(VideoPrivacy.PUBLIC)
|
||||||
|
expect(data.defaults.p2p.embed.enabled).to.be.true
|
||||||
|
expect(data.defaults.p2p.webapp.enabled).to.be.true
|
||||||
|
expect(data.defaults.player.autoPlay).to.be.true
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildNewCustomConfig (server: PeerTubeServer): CustomConfig {
|
function buildNewCustomConfig (server: PeerTubeServer): CustomConfig {
|
||||||
|
|
|
@ -537,12 +537,13 @@ function convertCustomConfigBody (body: CustomConfig) {
|
||||||
// Transcoding resolutions exception
|
// Transcoding resolutions exception
|
||||||
if (/^\d{3,4}p$/.exec(k)) return k
|
if (/^\d{3,4}p$/.exec(k)) return k
|
||||||
if (k === '0p') return k
|
if (k === '0p') return k
|
||||||
|
if (k === 'p2p') return k
|
||||||
|
|
||||||
return snakeCase(k)
|
return snakeCase(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
function valueConverter (v: any) {
|
function valueConverter (v: any) {
|
||||||
if (validator.default.isNumeric(v + '')) return parseInt('' + v, 10)
|
if (validator.isNumeric(v + '')) return parseInt('' + v, 10)
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,17 +138,29 @@ const CONFIG = {
|
||||||
|
|
||||||
DEFAULTS: {
|
DEFAULTS: {
|
||||||
PUBLISH: {
|
PUBLISH: {
|
||||||
DOWNLOAD_ENABLED: config.get<boolean>('defaults.publish.download_enabled'),
|
get DOWNLOAD_ENABLED () {
|
||||||
COMMENTS_POLICY: config.get<VideoCommentPolicyType>('defaults.publish.comments_policy'),
|
return config.get<boolean>('defaults.publish.download_enabled')
|
||||||
PRIVACY: config.get<VideoPrivacyType>('defaults.publish.privacy'),
|
},
|
||||||
LICENCE: config.get<number>('defaults.publish.licence')
|
get COMMENTS_POLICY () {
|
||||||
|
return config.get<VideoCommentPolicyType>('defaults.publish.comments_policy')
|
||||||
|
},
|
||||||
|
get PRIVACY () {
|
||||||
|
return config.get<VideoPrivacyType>('defaults.publish.privacy')
|
||||||
|
},
|
||||||
|
get LICENCE () {
|
||||||
|
return config.get<number>('defaults.publish.licence')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
P2P: {
|
P2P: {
|
||||||
WEBAPP: {
|
WEBAPP: {
|
||||||
ENABLED: config.get<boolean>('defaults.p2p.webapp.enabled')
|
get ENABLED () {
|
||||||
|
return config.get<boolean>('defaults.p2p.webapp.enabled')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
EMBED: {
|
EMBED: {
|
||||||
ENABLED: config.get<boolean>('defaults.p2p.embed.enabled')
|
get ENABLED () {
|
||||||
|
return config.get<boolean>('defaults.p2p.embed.enabled')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
PLAYER: {
|
PLAYER: {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { isUserNSFWPolicyValid, isUserVideoQuotaDailyValid, isUserVideoQuotaVali
|
||||||
import { isThemeRegistered } from '../../lib/plugins/theme-utils.js'
|
import { isThemeRegistered } from '../../lib/plugins/theme-utils.js'
|
||||||
import { areValidationErrors } from './shared/index.js'
|
import { areValidationErrors } from './shared/index.js'
|
||||||
import { isNumberArray, isStringArray } from '@server/helpers/custom-validators/search.js'
|
import { isNumberArray, isStringArray } from '@server/helpers/custom-validators/search.js'
|
||||||
|
import { isVideoCommentsPolicyValid, isVideoLicenceValid, isVideoPrivacyValid } from '@server/helpers/custom-validators/videos.js'
|
||||||
|
|
||||||
const customConfigUpdateValidator = [
|
const customConfigUpdateValidator = [
|
||||||
body('instance.name').exists(),
|
body('instance.name').exists(),
|
||||||
|
@ -135,6 +136,13 @@ const customConfigUpdateValidator = [
|
||||||
body('search.searchIndex.disableLocalSearch').isBoolean(),
|
body('search.searchIndex.disableLocalSearch').isBoolean(),
|
||||||
body('search.searchIndex.isDefaultSearch').isBoolean(),
|
body('search.searchIndex.isDefaultSearch').isBoolean(),
|
||||||
|
|
||||||
|
body('defaults.publish.commentsPolicy').custom(isVideoCommentsPolicyValid),
|
||||||
|
body('defaults.publish.privacy').custom(isVideoPrivacyValid),
|
||||||
|
body('defaults.publish.licence').custom(isVideoLicenceValid),
|
||||||
|
body('defaults.p2p.webapp.enabled').isBoolean(),
|
||||||
|
body('defaults.p2p.embed.enabled').isBoolean(),
|
||||||
|
body('defaults.player.autoPlay').isBoolean(),
|
||||||
|
|
||||||
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
(req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||||
if (areValidationErrors(req, res)) return
|
if (areValidationErrors(req, res)) return
|
||||||
if (!checkInvalidConfigIfEmailDisabled(req.body, res)) return
|
if (!checkInvalidConfigIfEmailDisabled(req.body, res)) return
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue