Implemented configurable minimum signup age

Implements https://github.com/Chocobozzz/PeerTube/issues/3612

Fixed lint and removed debug

Fixed another lint error

Apply suggestions from code review

Co-authored-by: Chocobozzz <chocobozzz@cpy.re>

Add tests for min signup age config
pull/4141/head
Poslovitch 2021-04-24 09:57:01 +00:00 committed by Chocobozzz
parent f22e0e2c19
commit 1f256e7d3c
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
21 changed files with 55 additions and 11 deletions

View File

@ -158,6 +158,20 @@
<small i18n *ngIf="hasUnlimitedSignup()" class="text-muted">Signup won't be limited to a fixed number of users.</small>
</div>
<div [ngClass]="getDisabledSignupClass()" class="mt-3">
<label i18n for="signupMinimumAge">Minimum required age to create an account</label>
<div class="number-with-unit">
<input
type="number" min="1" id="signupMinimumAge" class="form-control"
formControlName="minimumAge" [ngClass]="{ 'input-error': formErrors['signup.minimumAge'] }"
>
<span i18n>{form.value['signup']['minimumAge'], plural, =1 {year old} other {years old}}</span>
</div>
<div *ngIf="formErrors.signup.minimumAge" class="form-error">{{ formErrors.signup.minimumAge }}</div>
</div>
</ng-container>
</my-peertube-checkbox>
</div>
@ -469,7 +483,7 @@
<ng-container formGroupName="twitter">
<div class="form-group">
<label i18n for="signupLimit">Your Twitter username</label>
<label for="servicesTwitterUsername" i18n>Your Twitter username</label>
<input
type="text" id="servicesTwitterUsername" class="form-control"

View File

@ -1,4 +1,3 @@
import { pairwise } from 'rxjs/operators'
import { SelectOptionsItem } from 'src/types/select-options-item.model'
import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'

View File

@ -21,6 +21,7 @@ import {
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'
@ -120,7 +121,8 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
signup: {
enabled: null,
limit: SIGNUP_LIMIT_VALIDATOR,
requiresEmailVerification: null
requiresEmailVerification: null,
minimumAge: SIGNUP_MINIMUM_AGE_VALIDATOR
},
import: {
videos: {

View File

@ -2,8 +2,8 @@
<div class="form-group form-group-terms">
<my-peertube-checkbox inputName="terms" formControlName="terms">
<ng-template ptTemplate="label">
<ng-container i18n>
I am at least 16 years old and agree
<ng-container i18n>
I am at least {{ minimumAge }} years old and agree
to the <a class="terms-anchor" (click)="onTermsClick($event)" href='#'>Terms</a>
<ng-container *ngIf="hasCodeOfConduct"> and to the <a (click)="onCodeOfConductClick($event)" href='#'>Code of Conduct</a></ng-container>
of this instance

View File

@ -12,6 +12,7 @@ import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
})
export class RegisterStepTermsComponent extends FormReactive implements OnInit {
@Input() hasCodeOfConduct = false
@Input() minimumAge = 16
@Output() formBuilt = new EventEmitter<FormGroup>()
@Output() termsClick = new EventEmitter<void>()

View File

@ -17,6 +17,7 @@
<my-register-step-terms
[hasCodeOfConduct]="!!aboutHtml.codeOfConduct"
[minimumAge]="minimumAge"
(formBuilt)="onTermsFormBuilt($event)" (termsClick)="onTermsClick()" (codeOfConductClick)="onCodeOfConductClick()"
></my-register-step-terms>

View File

@ -56,6 +56,10 @@ export class RegisterComponent implements OnInit {
return this.serverConfig.signup.requiresEmailVerification
}
get minimumAge () {
return this.serverConfig.signup.minimumAge
}
ngOnInit (): void {
this.serverConfig = this.route.snapshot.data.serverConfig

View File

@ -60,7 +60,8 @@ export class ServerService {
signup: {
allowed: false,
allowedForCurrentIP: false,
requiresEmailVerification: false
requiresEmailVerification: false,
minimumAge: 16
},
transcoding: {
profile: 'default',

View File

@ -49,6 +49,15 @@ export const SIGNUP_LIMIT_VALIDATOR: BuildFormValidator = {
}
}
export const SIGNUP_MINIMUM_AGE_VALIDATOR: BuildFormValidator = {
VALIDATORS: [Validators.required, Validators.min(1), Validators.pattern('[0-9]+')],
MESSAGES: {
'required': $localize`Signup minimum age is required.`,
'min': $localize`Signup minimum age must be greater than 1.`,
'pattern': $localize`Signup minimum age must be a number.`
}
}
export const ADMIN_EMAIL_VALIDATOR: BuildFormValidator = {
VALIDATORS: [Validators.required, Validators.email],
MESSAGES: {

View File

@ -229,6 +229,7 @@ contact_form:
signup:
enabled: false
limit: 10 # When the limit is reached, registrations are disabled. -1 == unlimited
minimum_age: 16 # Used to configure the signup form
requires_email_verification: false
filters:
cidr: # You can specify CIDR ranges to whitelist (empty = no filtering) or blacklist

View File

@ -239,6 +239,7 @@ contact_form:
signup:
enabled: false
limit: 10 # When the limit is reached, registrations are disabled. -1 == unlimited
mimimum_age: 16
requires_email_verification: false
filters:
cidr: # You can specify CIDR ranges to whitelist (empty = no filtering) or blacklist

View File

@ -174,7 +174,8 @@ function customConfig (): CustomConfig {
signup: {
enabled: CONFIG.SIGNUP.ENABLED,
limit: CONFIG.SIGNUP.LIMIT,
requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION,
minimumAge: CONFIG.SIGNUP.MINIMUM_AGE
},
admin: {
email: CONFIG.ADMIN.EMAIL

View File

@ -19,7 +19,7 @@ function checkMissedConfig () {
'csp.enabled', 'csp.report_only', 'csp.report_uri',
'security.frameguard.enabled',
'cache.previews.size', 'cache.captions.size', 'cache.torrents.size', 'admin.email', 'contact_form.enabled',
'signup.enabled', 'signup.limit', 'signup.requires_email_verification',
'signup.enabled', 'signup.limit', 'signup.requires_email_verification', 'signup.minimum_age',
'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist',
'redundancy.videos.strategies', 'redundancy.videos.check_interval',
'transcoding.enabled', 'transcoding.threads', 'transcoding.allow_additional_extensions', 'transcoding.hls.enabled',

View File

@ -185,6 +185,7 @@ const CONFIG = {
get ENABLED () { return config.get<boolean>('signup.enabled') },
get LIMIT () { return config.get<number>('signup.limit') },
get REQUIRES_EMAIL_VERIFICATION () { return config.get<boolean>('signup.requires_email_verification') },
get MINIMUM_AGE () { return config.get<number>('signup.minimum_age') },
FILTERS: {
CIDR: {
get WHITELIST () { return config.get<string[]>('signup.filters.cidr.whitelist') },

View File

@ -216,6 +216,7 @@ class ServerConfigManager {
const signup = {
allowed,
allowedForCurrentIP,
minimumAge: CONFIG.SIGNUP.MINIMUM_AGE,
requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
}

View File

@ -30,6 +30,7 @@ const customConfigUpdateValidator = [
body('signup.enabled').isBoolean().withMessage('Should have a valid signup enabled boolean'),
body('signup.limit').isInt().withMessage('Should have a valid signup limit'),
body('signup.requiresEmailVerification').isBoolean().withMessage('Should have a valid requiresEmailVerification boolean'),
body('signup.minimumAge').isInt().withMessage("Should have a valid minimum age required"),
body('admin.email').isEmail().withMessage('Should have a valid administrator email'),
body('contactForm.enabled').isBoolean().withMessage('Should have a valid contact form enabled boolean'),

View File

@ -73,7 +73,8 @@ describe('Test config API validators', function () {
signup: {
enabled: false,
limit: 5,
requiresEmailVerification: false
requiresEmailVerification: false,
minimumAge: 16
},
admin: {
email: 'superadmin1@example.com'

View File

@ -60,6 +60,7 @@ function checkInitialConfig (server: ServerInfo, data: CustomConfig) {
expect(data.signup.enabled).to.be.true
expect(data.signup.limit).to.equal(4)
expect(data.signup.minimumAge).to.equal(16)
expect(data.signup.requiresEmailVerification).to.be.false
expect(data.admin.email).to.equal('admin' + server.internalServerNumber + '@example.com')
@ -151,6 +152,7 @@ function checkUpdatedConfig (data: CustomConfig) {
expect(data.signup.enabled).to.be.false
expect(data.signup.limit).to.equal(5)
expect(data.signup.requiresEmailVerification).to.be.false
expect(data.signup.minimumAge).to.equal(10)
// We override admin email in parallel tests, so skip this exception
if (parallelTests() === false) {
@ -316,7 +318,8 @@ describe('Test config', function () {
signup: {
enabled: false,
limit: 5,
requiresEmailVerification: false
requiresEmailVerification: false,
minimumAge: 10
},
admin: {
email: 'superadmin1@example.com'

View File

@ -98,7 +98,8 @@ function updateCustomSubConfig (url: string, token: string, newConfig: DeepParti
signup: {
enabled: false,
limit: 5,
requiresEmailVerification: false
requiresEmailVerification: false,
minimumAge: 16
},
admin: {
email: 'superadmin1@example.com'

View File

@ -69,6 +69,7 @@ export interface CustomConfig {
enabled: boolean
limit: number
requiresEmailVerification: boolean
minimumAge: number
}
admin: {

View File

@ -84,6 +84,7 @@ export interface ServerConfig {
allowed: boolean
allowedForCurrentIP: boolean
requiresEmailVerification: boolean
minimumAge: number
}
transcoding: {