aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared/shared-forms/form-validators
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-06-23 14:10:17 +0200
committerChocobozzz <chocobozzz@cpy.re>2020-06-23 16:00:49 +0200
commit67ed6552b831df66713bac9e672738796128d33f (patch)
tree59c97d41e0b49d75a90aa3de987968ab9b1ff447 /client/src/app/shared/shared-forms/form-validators
parent0c4bacbff53bc732f5a2677d62a6ead7752e2405 (diff)
downloadPeerTube-67ed6552b831df66713bac9e672738796128d33f.tar.gz
PeerTube-67ed6552b831df66713bac9e672738796128d33f.tar.zst
PeerTube-67ed6552b831df66713bac9e672738796128d33f.zip
Reorganize client shared modules
Diffstat (limited to 'client/src/app/shared/shared-forms/form-validators')
-rw-r--r--client/src/app/shared/shared-forms/form-validators/batch-domains-validators.service.ts69
-rw-r--r--client/src/app/shared/shared-forms/form-validators/custom-config-validators.service.ts98
-rw-r--r--client/src/app/shared/shared-forms/form-validators/form-validator.service.ts87
-rw-r--r--client/src/app/shared/shared-forms/form-validators/host.ts8
-rw-r--r--client/src/app/shared/shared-forms/form-validators/index.ts17
-rw-r--r--client/src/app/shared/shared-forms/form-validators/instance-validators.service.ts62
-rw-r--r--client/src/app/shared/shared-forms/form-validators/login-validators.service.ts30
-rw-r--r--client/src/app/shared/shared-forms/form-validators/reset-password-validators.service.ts20
-rw-r--r--client/src/app/shared/shared-forms/form-validators/user-validators.service.ts151
-rw-r--r--client/src/app/shared/shared-forms/form-validators/video-abuse-validators.service.ts30
-rw-r--r--client/src/app/shared/shared-forms/form-validators/video-accept-ownership-validators.service.ts18
-rw-r--r--client/src/app/shared/shared-forms/form-validators/video-block-validators.service.ts19
-rw-r--r--client/src/app/shared/shared-forms/form-validators/video-captions-validators.service.ts27
-rw-r--r--client/src/app/shared/shared-forms/form-validators/video-change-ownership-validators.service.ts27
-rw-r--r--client/src/app/shared/shared-forms/form-validators/video-channel-validators.service.ts64
-rw-r--r--client/src/app/shared/shared-forms/form-validators/video-comment-validators.service.ts20
-rw-r--r--client/src/app/shared/shared-forms/form-validators/video-playlist-validators.service.ts66
-rw-r--r--client/src/app/shared/shared-forms/form-validators/video-validators.service.ts102
18 files changed, 915 insertions, 0 deletions
diff --git a/client/src/app/shared/shared-forms/form-validators/batch-domains-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/batch-domains-validators.service.ts
new file mode 100644
index 000000000..f270b602b
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/batch-domains-validators.service.ts
@@ -0,0 +1,69 @@
1import { Injectable } from '@angular/core'
2import { ValidatorFn, Validators } from '@angular/forms'
3import { I18n } from '@ngx-translate/i18n-polyfill'
4import { BuildFormValidator } from './form-validator.service'
5import { validateHost } from './host'
6
7@Injectable()
8export class BatchDomainsValidatorsService {
9 readonly DOMAINS: BuildFormValidator
10
11 constructor (private i18n: I18n) {
12 this.DOMAINS = {
13 VALIDATORS: [ Validators.required, this.validDomains, this.isHostsUnique ],
14 MESSAGES: {
15 'required': this.i18n('Domain is required.'),
16 'validDomains': this.i18n('Domains entered are invalid.'),
17 'uniqueDomains': this.i18n('Domains entered contain duplicates.')
18 }
19 }
20 }
21
22 getNotEmptyHosts (hosts: string) {
23 return hosts
24 .split('\n')
25 .filter((host: string) => host && host.length !== 0) // Eject empty hosts
26 }
27
28 private validDomains: ValidatorFn = (control) => {
29 if (!control.value) return null
30
31 const newHostsErrors = []
32 const hosts = this.getNotEmptyHosts(control.value)
33
34 for (const host of hosts) {
35 if (validateHost(host) === false) {
36 newHostsErrors.push(this.i18n('{{host}} is not valid', { host }))
37 }
38 }
39
40 /* Is not valid. */
41 if (newHostsErrors.length !== 0) {
42 return {
43 'validDomains': {
44 reason: 'invalid',
45 value: newHostsErrors.join('. ') + '.'
46 }
47 }
48 }
49
50 /* Is valid. */
51 return null
52 }
53
54 private isHostsUnique: ValidatorFn = (control) => {
55 if (!control.value) return null
56
57 const hosts = this.getNotEmptyHosts(control.value)
58
59 if (hosts.every((host: string) => hosts.indexOf(host) === hosts.lastIndexOf(host))) {
60 return null
61 } else {
62 return {
63 'uniqueDomains': {
64 reason: 'invalid'
65 }
66 }
67 }
68 }
69}
diff --git a/client/src/app/shared/shared-forms/form-validators/custom-config-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/custom-config-validators.service.ts
new file mode 100644
index 000000000..c77aba6a1
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/custom-config-validators.service.ts
@@ -0,0 +1,98 @@
1import { Validators } from '@angular/forms'
2import { I18n } from '@ngx-translate/i18n-polyfill'
3import { BuildFormValidator } from './form-validator.service'
4import { Injectable } from '@angular/core'
5
6@Injectable()
7export class CustomConfigValidatorsService {
8 readonly INSTANCE_NAME: BuildFormValidator
9 readonly INSTANCE_SHORT_DESCRIPTION: BuildFormValidator
10 readonly SERVICES_TWITTER_USERNAME: BuildFormValidator
11 readonly CACHE_PREVIEWS_SIZE: BuildFormValidator
12 readonly CACHE_CAPTIONS_SIZE: BuildFormValidator
13 readonly SIGNUP_LIMIT: BuildFormValidator
14 readonly ADMIN_EMAIL: BuildFormValidator
15 readonly TRANSCODING_THREADS: BuildFormValidator
16 readonly INDEX_URL: BuildFormValidator
17 readonly SEARCH_INDEX_URL: BuildFormValidator
18
19 constructor (private i18n: I18n) {
20 this.INSTANCE_NAME = {
21 VALIDATORS: [ Validators.required ],
22 MESSAGES: {
23 'required': this.i18n('Instance name is required.')
24 }
25 }
26
27 this.INSTANCE_SHORT_DESCRIPTION = {
28 VALIDATORS: [ Validators.max(250) ],
29 MESSAGES: {
30 'max': this.i18n('Short description should not be longer than 250 characters.')
31 }
32 }
33
34 this.SERVICES_TWITTER_USERNAME = {
35 VALIDATORS: [ Validators.required ],
36 MESSAGES: {
37 'required': this.i18n('Twitter username is required.')
38 }
39 }
40
41 this.CACHE_PREVIEWS_SIZE = {
42 VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ],
43 MESSAGES: {
44 'required': this.i18n('Previews cache size is required.'),
45 'min': this.i18n('Previews cache size must be greater than 1.'),
46 'pattern': this.i18n('Previews cache size must be a number.')
47 }
48 }
49
50 this.CACHE_CAPTIONS_SIZE = {
51 VALIDATORS: [ Validators.required, Validators.min(1), Validators.pattern('[0-9]+') ],
52 MESSAGES: {
53 'required': this.i18n('Captions cache size is required.'),
54 'min': this.i18n('Captions cache size must be greater than 1.'),
55 'pattern': this.i18n('Captions cache size must be a number.')
56 }
57 }
58
59 this.SIGNUP_LIMIT = {
60 VALIDATORS: [ Validators.required, Validators.min(-1), Validators.pattern('-?[0-9]+') ],
61 MESSAGES: {
62 'required': this.i18n('Signup limit is required.'),
63 'min': this.i18n('Signup limit must be greater than 1.'),
64 'pattern': this.i18n('Signup limit must be a number.')
65 }
66 }
67
68 this.ADMIN_EMAIL = {
69 VALIDATORS: [ Validators.required, Validators.email ],
70 MESSAGES: {
71 'required': this.i18n('Admin email is required.'),
72 'email': this.i18n('Admin email must be valid.')
73 }
74 }
75
76 this.TRANSCODING_THREADS = {
77 VALIDATORS: [ Validators.required, Validators.min(0) ],
78 MESSAGES: {
79 'required': this.i18n('Transcoding threads is required.'),
80 'min': this.i18n('Transcoding threads must be greater or equal to 0.')
81 }
82 }
83
84 this.INDEX_URL = {
85 VALIDATORS: [ Validators.pattern(/^https:\/\//) ],
86 MESSAGES: {
87 'pattern': this.i18n('Index URL should be a URL')
88 }
89 }
90
91 this.SEARCH_INDEX_URL = {
92 VALIDATORS: [ Validators.pattern(/^https?:\/\//) ],
93 MESSAGES: {
94 'pattern': this.i18n('Search index URL should be a URL')
95 }
96 }
97 }
98}
diff --git a/client/src/app/shared/shared-forms/form-validators/form-validator.service.ts b/client/src/app/shared/shared-forms/form-validators/form-validator.service.ts
new file mode 100644
index 000000000..dec7d8d9a
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/form-validator.service.ts
@@ -0,0 +1,87 @@
1import { FormBuilder, FormControl, FormGroup, ValidatorFn } from '@angular/forms'
2import { Injectable } from '@angular/core'
3import { FormReactiveErrors, FormReactiveValidationMessages } from '../form-reactive'
4
5export type BuildFormValidator = {
6 VALIDATORS: ValidatorFn[],
7 MESSAGES: { [ name: string ]: string }
8}
9export type BuildFormArgument = {
10 [ id: string ]: BuildFormValidator | BuildFormArgument
11}
12export type BuildFormDefaultValues = {
13 [ name: string ]: string | string[] | BuildFormDefaultValues
14}
15
16@Injectable()
17export class FormValidatorService {
18
19 constructor (
20 private formBuilder: FormBuilder
21 ) {}
22
23 buildForm (obj: BuildFormArgument, defaultValues: BuildFormDefaultValues = {}) {
24 const formErrors: FormReactiveErrors = {}
25 const validationMessages: FormReactiveValidationMessages = {}
26 const group: { [key: string]: any } = {}
27
28 for (const name of Object.keys(obj)) {
29 formErrors[name] = ''
30
31 const field = obj[name]
32 if (this.isRecursiveField(field)) {
33 const result = this.buildForm(field as BuildFormArgument, defaultValues[name] as BuildFormDefaultValues)
34 group[name] = result.form
35 formErrors[name] = result.formErrors
36 validationMessages[name] = result.validationMessages
37
38 continue
39 }
40
41 if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES as { [ name: string ]: string }
42
43 const defaultValue = defaultValues[name] || ''
44
45 if (field && field.VALIDATORS) group[name] = [ defaultValue, field.VALIDATORS ]
46 else group[name] = [ defaultValue ]
47 }
48
49 const form = this.formBuilder.group(group)
50 return { form, formErrors, validationMessages }
51 }
52
53 updateForm (
54 form: FormGroup,
55 formErrors: FormReactiveErrors,
56 validationMessages: FormReactiveValidationMessages,
57 obj: BuildFormArgument,
58 defaultValues: BuildFormDefaultValues = {}
59 ) {
60 for (const name of Object.keys(obj)) {
61 formErrors[name] = ''
62
63 const field = obj[name]
64 if (this.isRecursiveField(field)) {
65 this.updateForm(
66 form[name],
67 formErrors[name] as FormReactiveErrors,
68 validationMessages[name] as FormReactiveValidationMessages,
69 obj[name] as BuildFormArgument,
70 defaultValues[name] as BuildFormDefaultValues
71 )
72 continue
73 }
74
75 if (field && field.MESSAGES) validationMessages[name] = field.MESSAGES as { [ name: string ]: string }
76
77 const defaultValue = defaultValues[name] || ''
78
79 if (field && field.VALIDATORS) form.addControl(name, new FormControl(defaultValue, field.VALIDATORS as ValidatorFn[]))
80 else form.addControl(name, new FormControl(defaultValue))
81 }
82 }
83
84 private isRecursiveField (field: any) {
85 return field && typeof field === 'object' && !field.MESSAGES && !field.VALIDATORS
86 }
87}
diff --git a/client/src/app/shared/shared-forms/form-validators/host.ts b/client/src/app/shared/shared-forms/form-validators/host.ts
new file mode 100644
index 000000000..c18a35f9b
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/host.ts
@@ -0,0 +1,8 @@
1export function validateHost (value: string) {
2 // Thanks to http://stackoverflow.com/a/106223
3 const HOST_REGEXP = new RegExp(
4 '^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$'
5 )
6
7 return HOST_REGEXP.test(value)
8}
diff --git a/client/src/app/shared/shared-forms/form-validators/index.ts b/client/src/app/shared/shared-forms/form-validators/index.ts
new file mode 100644
index 000000000..8b71841a9
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/index.ts
@@ -0,0 +1,17 @@
1export * from './batch-domains-validators.service'
2export * from './custom-config-validators.service'
3export * from './form-validator.service'
4export * from './host'
5export * from './instance-validators.service'
6export * from './login-validators.service'
7export * from './reset-password-validators.service'
8export * from './user-validators.service'
9export * from './video-abuse-validators.service'
10export * from './video-accept-ownership-validators.service'
11export * from './video-block-validators.service'
12export * from './video-captions-validators.service'
13export * from './video-change-ownership-validators.service'
14export * from './video-channel-validators.service'
15export * from './video-comment-validators.service'
16export * from './video-playlist-validators.service'
17export * from './video-validators.service'
diff --git a/client/src/app/shared/shared-forms/form-validators/instance-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/instance-validators.service.ts
new file mode 100644
index 000000000..96a35a48f
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/instance-validators.service.ts
@@ -0,0 +1,62 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { BuildFormValidator } from './form-validator.service'
4import { Injectable } from '@angular/core'
5
6@Injectable()
7export class InstanceValidatorsService {
8 readonly FROM_EMAIL: BuildFormValidator
9 readonly FROM_NAME: BuildFormValidator
10 readonly SUBJECT: BuildFormValidator
11 readonly BODY: BuildFormValidator
12
13 constructor (private i18n: I18n) {
14
15 this.FROM_EMAIL = {
16 VALIDATORS: [ Validators.required, Validators.email ],
17 MESSAGES: {
18 'required': this.i18n('Email is required.'),
19 'email': this.i18n('Email must be valid.')
20 }
21 }
22
23 this.FROM_NAME = {
24 VALIDATORS: [
25 Validators.required,
26 Validators.minLength(1),
27 Validators.maxLength(120)
28 ],
29 MESSAGES: {
30 'required': this.i18n('Your name is required.'),
31 'minlength': this.i18n('Your name must be at least 1 character long.'),
32 'maxlength': this.i18n('Your name cannot be more than 120 characters long.')
33 }
34 }
35
36 this.SUBJECT = {
37 VALIDATORS: [
38 Validators.required,
39 Validators.minLength(1),
40 Validators.maxLength(120)
41 ],
42 MESSAGES: {
43 'required': this.i18n('A subject is required.'),
44 'minlength': this.i18n('The subject must be at least 1 character long.'),
45 'maxlength': this.i18n('The subject cannot be more than 120 characters long.')
46 }
47 }
48
49 this.BODY = {
50 VALIDATORS: [
51 Validators.required,
52 Validators.minLength(3),
53 Validators.maxLength(5000)
54 ],
55 MESSAGES: {
56 'required': this.i18n('A message is required.'),
57 'minlength': this.i18n('The message must be at least 3 characters long.'),
58 'maxlength': this.i18n('The message cannot be more than 5000 characters long.')
59 }
60 }
61 }
62}
diff --git a/client/src/app/shared/shared-forms/form-validators/login-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/login-validators.service.ts
new file mode 100644
index 000000000..a5837357e
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/login-validators.service.ts
@@ -0,0 +1,30 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class LoginValidatorsService {
8 readonly LOGIN_USERNAME: BuildFormValidator
9 readonly LOGIN_PASSWORD: BuildFormValidator
10
11 constructor (private i18n: I18n) {
12 this.LOGIN_USERNAME = {
13 VALIDATORS: [
14 Validators.required
15 ],
16 MESSAGES: {
17 'required': this.i18n('Username is required.')
18 }
19 }
20
21 this.LOGIN_PASSWORD = {
22 VALIDATORS: [
23 Validators.required
24 ],
25 MESSAGES: {
26 'required': this.i18n('Password is required.')
27 }
28 }
29 }
30}
diff --git a/client/src/app/shared/shared-forms/form-validators/reset-password-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/reset-password-validators.service.ts
new file mode 100644
index 000000000..d2085a309
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/reset-password-validators.service.ts
@@ -0,0 +1,20 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class ResetPasswordValidatorsService {
8 readonly RESET_PASSWORD_CONFIRM: BuildFormValidator
9
10 constructor (private i18n: I18n) {
11 this.RESET_PASSWORD_CONFIRM = {
12 VALIDATORS: [
13 Validators.required
14 ],
15 MESSAGES: {
16 'required': this.i18n('Confirmation of the password is required.')
17 }
18 }
19 }
20}
diff --git a/client/src/app/shared/shared-forms/form-validators/user-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/user-validators.service.ts
new file mode 100644
index 000000000..bd3030a54
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/user-validators.service.ts
@@ -0,0 +1,151 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { BuildFormValidator } from './form-validator.service'
4import { Injectable } from '@angular/core'
5
6@Injectable()
7export class UserValidatorsService {
8 readonly USER_USERNAME: BuildFormValidator
9 readonly USER_EMAIL: BuildFormValidator
10 readonly USER_PASSWORD: BuildFormValidator
11 readonly USER_PASSWORD_OPTIONAL: BuildFormValidator
12 readonly USER_CONFIRM_PASSWORD: BuildFormValidator
13 readonly USER_VIDEO_QUOTA: BuildFormValidator
14 readonly USER_VIDEO_QUOTA_DAILY: BuildFormValidator
15 readonly USER_ROLE: BuildFormValidator
16 readonly USER_DISPLAY_NAME_REQUIRED: BuildFormValidator
17 readonly USER_DESCRIPTION: BuildFormValidator
18 readonly USER_TERMS: BuildFormValidator
19
20 readonly USER_BAN_REASON: BuildFormValidator
21
22 constructor (private i18n: I18n) {
23
24 this.USER_USERNAME = {
25 VALIDATORS: [
26 Validators.required,
27 Validators.minLength(1),
28 Validators.maxLength(50),
29 Validators.pattern(/^[a-z0-9][a-z0-9._]*$/)
30 ],
31 MESSAGES: {
32 'required': this.i18n('Username is required.'),
33 'minlength': this.i18n('Username must be at least 1 character long.'),
34 'maxlength': this.i18n('Username cannot be more than 50 characters long.'),
35 'pattern': this.i18n('Username should be lowercase alphanumeric; dots and underscores are allowed.')
36 }
37 }
38
39 this.USER_EMAIL = {
40 VALIDATORS: [ Validators.required, Validators.email ],
41 MESSAGES: {
42 'required': this.i18n('Email is required.'),
43 'email': this.i18n('Email must be valid.')
44 }
45 }
46
47 this.USER_PASSWORD = {
48 VALIDATORS: [
49 Validators.required,
50 Validators.minLength(6),
51 Validators.maxLength(255)
52 ],
53 MESSAGES: {
54 'required': this.i18n('Password is required.'),
55 'minlength': this.i18n('Password must be at least 6 characters long.'),
56 'maxlength': this.i18n('Password cannot be more than 255 characters long.')
57 }
58 }
59
60 this.USER_PASSWORD_OPTIONAL = {
61 VALIDATORS: [
62 Validators.minLength(6),
63 Validators.maxLength(255)
64 ],
65 MESSAGES: {
66 'minlength': this.i18n('Password must be at least 6 characters long.'),
67 'maxlength': this.i18n('Password cannot be more than 255 characters long.')
68 }
69 }
70
71 this.USER_CONFIRM_PASSWORD = {
72 VALIDATORS: [],
73 MESSAGES: {
74 'matchPassword': this.i18n('The new password and the confirmed password do not correspond.')
75 }
76 }
77
78 this.USER_VIDEO_QUOTA = {
79 VALIDATORS: [ Validators.required, Validators.min(-1) ],
80 MESSAGES: {
81 'required': this.i18n('Video quota is required.'),
82 'min': this.i18n('Quota must be greater than -1.')
83 }
84 }
85 this.USER_VIDEO_QUOTA_DAILY = {
86 VALIDATORS: [ Validators.required, Validators.min(-1) ],
87 MESSAGES: {
88 'required': this.i18n('Daily upload limit is required.'),
89 'min': this.i18n('Daily upload limit must be greater than -1.')
90 }
91 }
92
93 this.USER_ROLE = {
94 VALIDATORS: [ Validators.required ],
95 MESSAGES: {
96 'required': this.i18n('User role is required.')
97 }
98 }
99
100 this.USER_DISPLAY_NAME_REQUIRED = this.getDisplayName(true)
101
102 this.USER_DESCRIPTION = {
103 VALIDATORS: [
104 Validators.minLength(3),
105 Validators.maxLength(1000)
106 ],
107 MESSAGES: {
108 'minlength': this.i18n('Description must be at least 3 characters long.'),
109 'maxlength': this.i18n('Description cannot be more than 1000 characters long.')
110 }
111 }
112
113 this.USER_TERMS = {
114 VALIDATORS: [
115 Validators.requiredTrue
116 ],
117 MESSAGES: {
118 'required': this.i18n('You must agree with the instance terms in order to register on it.')
119 }
120 }
121
122 this.USER_BAN_REASON = {
123 VALIDATORS: [
124 Validators.minLength(3),
125 Validators.maxLength(250)
126 ],
127 MESSAGES: {
128 'minlength': this.i18n('Ban reason must be at least 3 characters long.'),
129 'maxlength': this.i18n('Ban reason cannot be more than 250 characters long.')
130 }
131 }
132 }
133
134 private getDisplayName (required: boolean) {
135 const control = {
136 VALIDATORS: [
137 Validators.minLength(1),
138 Validators.maxLength(120)
139 ],
140 MESSAGES: {
141 'required': this.i18n('Display name is required.'),
142 'minlength': this.i18n('Display name must be at least 1 character long.'),
143 'maxlength': this.i18n('Display name cannot be more than 50 characters long.')
144 }
145 }
146
147 if (required) control.VALIDATORS.push(Validators.required)
148
149 return control
150 }
151}
diff --git a/client/src/app/shared/shared-forms/form-validators/video-abuse-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/video-abuse-validators.service.ts
new file mode 100644
index 000000000..aae56d607
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/video-abuse-validators.service.ts
@@ -0,0 +1,30 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class VideoAbuseValidatorsService {
8 readonly VIDEO_ABUSE_REASON: BuildFormValidator
9 readonly VIDEO_ABUSE_MODERATION_COMMENT: BuildFormValidator
10
11 constructor (private i18n: I18n) {
12 this.VIDEO_ABUSE_REASON = {
13 VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ],
14 MESSAGES: {
15 'required': this.i18n('Report reason is required.'),
16 'minlength': this.i18n('Report reason must be at least 2 characters long.'),
17 'maxlength': this.i18n('Report reason cannot be more than 3000 characters long.')
18 }
19 }
20
21 this.VIDEO_ABUSE_MODERATION_COMMENT = {
22 VALIDATORS: [ Validators.required, Validators.minLength(2), Validators.maxLength(3000) ],
23 MESSAGES: {
24 'required': this.i18n('Moderation comment is required.'),
25 'minlength': this.i18n('Moderation comment must be at least 2 characters long.'),
26 'maxlength': this.i18n('Moderation comment cannot be more than 3000 characters long.')
27 }
28 }
29 }
30}
diff --git a/client/src/app/shared/shared-forms/form-validators/video-accept-ownership-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/video-accept-ownership-validators.service.ts
new file mode 100644
index 000000000..998d616ec
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/video-accept-ownership-validators.service.ts
@@ -0,0 +1,18 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class VideoAcceptOwnershipValidatorsService {
8 readonly CHANNEL: BuildFormValidator
9
10 constructor (private i18n: I18n) {
11 this.CHANNEL = {
12 VALIDATORS: [ Validators.required ],
13 MESSAGES: {
14 'required': this.i18n('The channel is required.')
15 }
16 }
17 }
18}
diff --git a/client/src/app/shared/shared-forms/form-validators/video-block-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/video-block-validators.service.ts
new file mode 100644
index 000000000..ddf0ab5eb
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/video-block-validators.service.ts
@@ -0,0 +1,19 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class VideoBlockValidatorsService {
8 readonly VIDEO_BLOCK_REASON: BuildFormValidator
9
10 constructor (private i18n: I18n) {
11 this.VIDEO_BLOCK_REASON = {
12 VALIDATORS: [ Validators.minLength(2), Validators.maxLength(300) ],
13 MESSAGES: {
14 'minlength': this.i18n('Block reason must be at least 2 characters long.'),
15 'maxlength': this.i18n('Block reason cannot be more than 300 characters long.')
16 }
17 }
18 }
19}
diff --git a/client/src/app/shared/shared-forms/form-validators/video-captions-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/video-captions-validators.service.ts
new file mode 100644
index 000000000..280d28414
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/video-captions-validators.service.ts
@@ -0,0 +1,27 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class VideoCaptionsValidatorsService {
8 readonly VIDEO_CAPTION_LANGUAGE: BuildFormValidator
9 readonly VIDEO_CAPTION_FILE: BuildFormValidator
10
11 constructor (private i18n: I18n) {
12
13 this.VIDEO_CAPTION_LANGUAGE = {
14 VALIDATORS: [ Validators.required ],
15 MESSAGES: {
16 'required': this.i18n('Video caption language is required.')
17 }
18 }
19
20 this.VIDEO_CAPTION_FILE = {
21 VALIDATORS: [ Validators.required ],
22 MESSAGES: {
23 'required': this.i18n('Video caption file is required.')
24 }
25 }
26 }
27}
diff --git a/client/src/app/shared/shared-forms/form-validators/video-change-ownership-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/video-change-ownership-validators.service.ts
new file mode 100644
index 000000000..59659defd
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/video-change-ownership-validators.service.ts
@@ -0,0 +1,27 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { AbstractControl, ValidationErrors, Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class VideoChangeOwnershipValidatorsService {
8 readonly USERNAME: BuildFormValidator
9
10 constructor (private i18n: I18n) {
11 this.USERNAME = {
12 VALIDATORS: [ Validators.required, this.localAccountValidator ],
13 MESSAGES: {
14 'required': this.i18n('The username is required.'),
15 'localAccountOnly': this.i18n('You can only transfer ownership to a local account')
16 }
17 }
18 }
19
20 localAccountValidator (control: AbstractControl): ValidationErrors {
21 if (control.value.includes('@')) {
22 return { 'localAccountOnly': true }
23 }
24
25 return null
26 }
27}
diff --git a/client/src/app/shared/shared-forms/form-validators/video-channel-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/video-channel-validators.service.ts
new file mode 100644
index 000000000..bb650b149
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/video-channel-validators.service.ts
@@ -0,0 +1,64 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class VideoChannelValidatorsService {
8 readonly VIDEO_CHANNEL_NAME: BuildFormValidator
9 readonly VIDEO_CHANNEL_DISPLAY_NAME: BuildFormValidator
10 readonly VIDEO_CHANNEL_DESCRIPTION: BuildFormValidator
11 readonly VIDEO_CHANNEL_SUPPORT: BuildFormValidator
12
13 constructor (private i18n: I18n) {
14 this.VIDEO_CHANNEL_NAME = {
15 VALIDATORS: [
16 Validators.required,
17 Validators.minLength(1),
18 Validators.maxLength(50),
19 Validators.pattern(/^[a-z0-9][a-z0-9._]*$/)
20 ],
21 MESSAGES: {
22 'required': this.i18n('Name is required.'),
23 'minlength': this.i18n('Name must be at least 1 character long.'),
24 'maxlength': this.i18n('Name cannot be more than 50 characters long.'),
25 'pattern': this.i18n('Name should be lowercase alphanumeric; dots and underscores are allowed.')
26 }
27 }
28
29 this.VIDEO_CHANNEL_DISPLAY_NAME = {
30 VALIDATORS: [
31 Validators.required,
32 Validators.minLength(1),
33 Validators.maxLength(50)
34 ],
35 MESSAGES: {
36 'required': i18n('Display name is required.'),
37 'minlength': i18n('Display name must be at least 1 character long.'),
38 'maxlength': i18n('Display name cannot be more than 50 characters long.')
39 }
40 }
41
42 this.VIDEO_CHANNEL_DESCRIPTION = {
43 VALIDATORS: [
44 Validators.minLength(3),
45 Validators.maxLength(1000)
46 ],
47 MESSAGES: {
48 'minlength': i18n('Description must be at least 3 characters long.'),
49 'maxlength': i18n('Description cannot be more than 1000 characters long.')
50 }
51 }
52
53 this.VIDEO_CHANNEL_SUPPORT = {
54 VALIDATORS: [
55 Validators.minLength(3),
56 Validators.maxLength(1000)
57 ],
58 MESSAGES: {
59 'minlength': i18n('Support text must be at least 3 characters long.'),
60 'maxlength': i18n('Support text cannot be more than 1000 characters long.')
61 }
62 }
63 }
64}
diff --git a/client/src/app/shared/shared-forms/form-validators/video-comment-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/video-comment-validators.service.ts
new file mode 100644
index 000000000..97c8e967e
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/video-comment-validators.service.ts
@@ -0,0 +1,20 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class VideoCommentValidatorsService {
8 readonly VIDEO_COMMENT_TEXT: BuildFormValidator
9
10 constructor (private i18n: I18n) {
11 this.VIDEO_COMMENT_TEXT = {
12 VALIDATORS: [ Validators.required, Validators.minLength(1), Validators.maxLength(3000) ],
13 MESSAGES: {
14 'required': this.i18n('Comment is required.'),
15 'minlength': this.i18n('Comment must be at least 2 characters long.'),
16 'maxlength': this.i18n('Comment cannot be more than 3000 characters long.')
17 }
18 }
19 }
20}
diff --git a/client/src/app/shared/shared-forms/form-validators/video-playlist-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/video-playlist-validators.service.ts
new file mode 100644
index 000000000..ab9c43625
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/video-playlist-validators.service.ts
@@ -0,0 +1,66 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { AbstractControl, FormControl, Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5import { VideoPlaylistPrivacy } from '@shared/models'
6
7@Injectable()
8export class VideoPlaylistValidatorsService {
9 readonly VIDEO_PLAYLIST_DISPLAY_NAME: BuildFormValidator
10 readonly VIDEO_PLAYLIST_PRIVACY: BuildFormValidator
11 readonly VIDEO_PLAYLIST_DESCRIPTION: BuildFormValidator
12 readonly VIDEO_PLAYLIST_CHANNEL_ID: BuildFormValidator
13
14 constructor (private i18n: I18n) {
15 this.VIDEO_PLAYLIST_DISPLAY_NAME = {
16 VALIDATORS: [
17 Validators.required,
18 Validators.minLength(1),
19 Validators.maxLength(120)
20 ],
21 MESSAGES: {
22 'required': this.i18n('Display name is required.'),
23 'minlength': this.i18n('Display name must be at least 1 character long.'),
24 'maxlength': this.i18n('Display name cannot be more than 120 characters long.')
25 }
26 }
27
28 this.VIDEO_PLAYLIST_PRIVACY = {
29 VALIDATORS: [
30 Validators.required
31 ],
32 MESSAGES: {
33 'required': this.i18n('Privacy is required.')
34 }
35 }
36
37 this.VIDEO_PLAYLIST_DESCRIPTION = {
38 VALIDATORS: [
39 Validators.minLength(3),
40 Validators.maxLength(1000)
41 ],
42 MESSAGES: {
43 'minlength': i18n('Description must be at least 3 characters long.'),
44 'maxlength': i18n('Description cannot be more than 1000 characters long.')
45 }
46 }
47
48 this.VIDEO_PLAYLIST_CHANNEL_ID = {
49 VALIDATORS: [ ],
50 MESSAGES: {
51 'required': this.i18n('The channel is required when the playlist is public.')
52 }
53 }
54 }
55
56 setChannelValidator (channelControl: AbstractControl, privacy: VideoPlaylistPrivacy) {
57 if (privacy.toString() === VideoPlaylistPrivacy.PUBLIC.toString()) {
58 channelControl.setValidators([ Validators.required ])
59 } else {
60 channelControl.setValidators(null)
61 }
62
63 channelControl.markAsDirty()
64 channelControl.updateValueAndValidity()
65 }
66}
diff --git a/client/src/app/shared/shared-forms/form-validators/video-validators.service.ts b/client/src/app/shared/shared-forms/form-validators/video-validators.service.ts
new file mode 100644
index 000000000..9b24e4f62
--- /dev/null
+++ b/client/src/app/shared/shared-forms/form-validators/video-validators.service.ts
@@ -0,0 +1,102 @@
1import { I18n } from '@ngx-translate/i18n-polyfill'
2import { Validators } from '@angular/forms'
3import { Injectable } from '@angular/core'
4import { BuildFormValidator } from './form-validator.service'
5
6@Injectable()
7export class VideoValidatorsService {
8 readonly VIDEO_NAME: BuildFormValidator
9 readonly VIDEO_PRIVACY: BuildFormValidator
10 readonly VIDEO_CATEGORY: BuildFormValidator
11 readonly VIDEO_LICENCE: BuildFormValidator
12 readonly VIDEO_LANGUAGE: BuildFormValidator
13 readonly VIDEO_IMAGE: BuildFormValidator
14 readonly VIDEO_CHANNEL: BuildFormValidator
15 readonly VIDEO_DESCRIPTION: BuildFormValidator
16 readonly VIDEO_TAGS: BuildFormValidator
17 readonly VIDEO_SUPPORT: BuildFormValidator
18 readonly VIDEO_SCHEDULE_PUBLICATION_AT: BuildFormValidator
19 readonly VIDEO_ORIGINALLY_PUBLISHED_AT: BuildFormValidator
20
21 constructor (private i18n: I18n) {
22
23 this.VIDEO_NAME = {
24 VALIDATORS: [ Validators.required, Validators.minLength(3), Validators.maxLength(120) ],
25 MESSAGES: {
26 'required': this.i18n('Video name is required.'),
27 'minlength': this.i18n('Video name must be at least 3 characters long.'),
28 'maxlength': this.i18n('Video name cannot be more than 120 characters long.')
29 }
30 }
31
32 this.VIDEO_PRIVACY = {
33 VALIDATORS: [ Validators.required ],
34 MESSAGES: {
35 'required': this.i18n('Video privacy is required.')
36 }
37 }
38
39 this.VIDEO_CATEGORY = {
40 VALIDATORS: [ ],
41 MESSAGES: {}
42 }
43
44 this.VIDEO_LICENCE = {
45 VALIDATORS: [ ],
46 MESSAGES: {}
47 }
48
49 this.VIDEO_LANGUAGE = {
50 VALIDATORS: [ ],
51 MESSAGES: {}
52 }
53
54 this.VIDEO_IMAGE = {
55 VALIDATORS: [ ],
56 MESSAGES: {}
57 }
58
59 this.VIDEO_CHANNEL = {
60 VALIDATORS: [ Validators.required ],
61 MESSAGES: {
62 'required': this.i18n('Video channel is required.')
63 }
64 }
65
66 this.VIDEO_DESCRIPTION = {
67 VALIDATORS: [ Validators.minLength(3), Validators.maxLength(10000) ],
68 MESSAGES: {
69 'minlength': this.i18n('Video description must be at least 3 characters long.'),
70 'maxlength': this.i18n('Video description cannot be more than 10000 characters long.')
71 }
72 }
73
74 this.VIDEO_TAGS = {
75 VALIDATORS: [ Validators.minLength(2), Validators.maxLength(30) ],
76 MESSAGES: {
77 'minlength': this.i18n('A tag should be more than 2 characters long.'),
78 'maxlength': this.i18n('A tag should be less than 30 characters long.')
79 }
80 }
81
82 this.VIDEO_SUPPORT = {
83 VALIDATORS: [ Validators.minLength(3), Validators.maxLength(1000) ],
84 MESSAGES: {
85 'minlength': this.i18n('Video support must be at least 3 characters long.'),
86 'maxlength': this.i18n('Video support cannot be more than 1000 characters long.')
87 }
88 }
89
90 this.VIDEO_SCHEDULE_PUBLICATION_AT = {
91 VALIDATORS: [ ],
92 MESSAGES: {
93 'required': this.i18n('A date is required to schedule video update.')
94 }
95 }
96
97 this.VIDEO_ORIGINALLY_PUBLISHED_AT = {
98 VALIDATORS: [ ],
99 MESSAGES: {}
100 }
101 }
102}