aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-07-20 14:15:15 +0200
committerChocobozzz <me@florianbigard.com>2021-07-21 13:35:31 +0200
commit4d029ef8ec3d5274eeaa3ee6d808eb7035e7faef (patch)
tree20bcdd660ab4eb731814db3a4a40fffb48ce7482 /client/src/app/shared
parent7f28f2ddbaeecf451d501e99ded0408c14a33600 (diff)
downloadPeerTube-4d029ef8ec3d5274eeaa3ee6d808eb7035e7faef.tar.gz
PeerTube-4d029ef8ec3d5274eeaa3ee6d808eb7035e7faef.tar.zst
PeerTube-4d029ef8ec3d5274eeaa3ee6d808eb7035e7faef.zip
Add ability for instances to follow any actor
Diffstat (limited to 'client/src/app/shared')
-rw-r--r--client/src/app/shared/form-validators/batch-domains-validators.ts60
-rw-r--r--client/src/app/shared/form-validators/host-validators.ts105
-rw-r--r--client/src/app/shared/form-validators/host.ts8
-rw-r--r--client/src/app/shared/form-validators/index.ts1
-rw-r--r--client/src/app/shared/shared-instance/instance-follow.service.ts13
-rw-r--r--client/src/app/shared/shared-moderation/batch-domains-modal.component.html14
-rw-r--r--client/src/app/shared/shared-moderation/batch-domains-modal.component.ts8
7 files changed, 123 insertions, 86 deletions
diff --git a/client/src/app/shared/form-validators/batch-domains-validators.ts b/client/src/app/shared/form-validators/batch-domains-validators.ts
deleted file mode 100644
index 423d1337f..000000000
--- a/client/src/app/shared/form-validators/batch-domains-validators.ts
+++ /dev/null
@@ -1,60 +0,0 @@
1import { AbstractControl, FormControl, ValidatorFn, Validators } from '@angular/forms'
2import { BuildFormValidator } from './form-validator.model'
3import { validateHost } from './host'
4
5export function getNotEmptyHosts (hosts: string) {
6 return hosts
7 .split('\n')
8 .filter((host: string) => host && host.length !== 0) // Eject empty hosts
9}
10
11const validDomains: ValidatorFn = (control: FormControl) => {
12 if (!control.value) return null
13
14 const newHostsErrors = []
15 const hosts = getNotEmptyHosts(control.value)
16
17 for (const host of hosts) {
18 if (validateHost(host) === false) {
19 newHostsErrors.push($localize`${host} is not valid`)
20 }
21 }
22
23 /* Is not valid. */
24 if (newHostsErrors.length !== 0) {
25 return {
26 'validDomains': {
27 reason: 'invalid',
28 value: newHostsErrors.join('. ') + '.'
29 }
30 }
31 }
32
33 /* Is valid. */
34 return null
35}
36
37const isHostsUnique: ValidatorFn = (control: AbstractControl) => {
38 if (!control.value) return null
39
40 const hosts = getNotEmptyHosts(control.value)
41
42 if (hosts.every((host: string) => hosts.indexOf(host) === hosts.lastIndexOf(host))) {
43 return null
44 } else {
45 return {
46 'uniqueDomains': {
47 reason: 'invalid'
48 }
49 }
50 }
51}
52
53export const DOMAINS_VALIDATOR: BuildFormValidator = {
54 VALIDATORS: [Validators.required, validDomains, isHostsUnique],
55 MESSAGES: {
56 'required': $localize`Domain is required.`,
57 'validDomains': $localize`Domains entered are invalid.`,
58 'uniqueDomains': $localize`Domains entered contain duplicates.`
59 }
60}
diff --git a/client/src/app/shared/form-validators/host-validators.ts b/client/src/app/shared/form-validators/host-validators.ts
new file mode 100644
index 000000000..d750113ef
--- /dev/null
+++ b/client/src/app/shared/form-validators/host-validators.ts
@@ -0,0 +1,105 @@
1import { AbstractControl, ValidatorFn, Validators } from '@angular/forms'
2import { BuildFormValidator } from './form-validator.model'
3
4function validateHost (value: string) {
5 // Thanks to http://stackoverflow.com/a/106223
6 const HOST_REGEXP = new RegExp(
7 '^(([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])$'
8 )
9
10 return HOST_REGEXP.test(value)
11}
12
13function validateHandle (value: string) {
14 if (!value) return false
15
16 return value.includes('@')
17}
18
19const validHosts: ValidatorFn = (control: AbstractControl) => {
20 if (!control.value) return null
21
22 const errors = []
23 const hosts = splitAndGetNotEmpty(control.value)
24
25 for (const host of hosts) {
26 if (validateHost(host) === false) {
27 errors.push($localize`${host} is not valid`)
28 }
29 }
30
31 // valid
32 if (errors.length === 0) return null
33
34 return {
35 'validHosts': {
36 reason: 'invalid',
37 value: errors.join('. ') + '.'
38 }
39 }
40}
41
42const validHostsOrHandles: ValidatorFn = (control: AbstractControl) => {
43 if (!control.value) return null
44
45 const errors = []
46 const lines = splitAndGetNotEmpty(control.value)
47
48 for (const line of lines) {
49 if (validateHost(line) === false && validateHandle(line) === false) {
50 errors.push($localize`${line} is not valid`)
51 }
52 }
53
54 // valid
55 if (errors.length === 0) return null
56
57 return {
58 'validHostsOrHandles': {
59 reason: 'invalid',
60 value: errors.join('. ') + '.'
61 }
62 }
63}
64
65// ---------------------------------------------------------------------------
66
67export function splitAndGetNotEmpty (value: string) {
68 return value
69 .split('\n')
70 .filter(line => line && line.length !== 0) // Eject empty hosts
71}
72
73export const unique: ValidatorFn = (control: AbstractControl) => {
74 if (!control.value) return null
75
76 const hosts = splitAndGetNotEmpty(control.value)
77
78 if (hosts.every((host: string) => hosts.indexOf(host) === hosts.lastIndexOf(host))) {
79 return null
80 }
81
82 return {
83 'unique': {
84 reason: 'invalid'
85 }
86 }
87}
88
89export const UNIQUE_HOSTS_VALIDATOR: BuildFormValidator = {
90 VALIDATORS: [ Validators.required, validHosts, unique ],
91 MESSAGES: {
92 'required': $localize`Domain is required.`,
93 'validHosts': $localize`Hosts entered are invalid.`,
94 'unique': $localize`Hosts entered contain duplicates.`
95 }
96}
97
98export const UNIQUE_HOSTS_OR_HANDLE_VALIDATOR: BuildFormValidator = {
99 VALIDATORS: [ Validators.required, validHostsOrHandles, unique ],
100 MESSAGES: {
101 'required': $localize`Domain is required.`,
102 'validHostsOrHandles': $localize`Hosts or handles are invalid.`,
103 'unique': $localize`Hosts or handles contain duplicates.`
104 }
105}
diff --git a/client/src/app/shared/form-validators/host.ts b/client/src/app/shared/form-validators/host.ts
deleted file mode 100644
index c18a35f9b..000000000
--- a/client/src/app/shared/form-validators/host.ts
+++ /dev/null
@@ -1,8 +0,0 @@
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/form-validators/index.ts b/client/src/app/shared/form-validators/index.ts
index f621f03a4..c14272a2a 100644
--- a/client/src/app/shared/form-validators/index.ts
+++ b/client/src/app/shared/form-validators/index.ts
@@ -1,5 +1,4 @@
1export * from './form-validator.model' 1export * from './form-validator.model'
2export * from './host'
3 2
4// Don't re export const variables because webpack 4 cannot do tree shaking with them 3// Don't re export const variables because webpack 4 cannot do tree shaking with them
5// export * from './abuse-validators' 4// export * from './abuse-validators'
diff --git a/client/src/app/shared/shared-instance/instance-follow.service.ts b/client/src/app/shared/shared-instance/instance-follow.service.ts
index e52660140..af44020cf 100644
--- a/client/src/app/shared/shared-instance/instance-follow.service.ts
+++ b/client/src/app/shared/shared-instance/instance-follow.service.ts
@@ -4,7 +4,7 @@ import { catchError, map } from 'rxjs/operators'
4import { HttpClient, HttpParams } from '@angular/common/http' 4import { HttpClient, HttpParams } from '@angular/common/http'
5import { Injectable } from '@angular/core' 5import { Injectable } from '@angular/core'
6import { RestExtractor, RestPagination, RestService } from '@app/core' 6import { RestExtractor, RestPagination, RestService } from '@app/core'
7import { ActivityPubActorType, ActorFollow, FollowState, ResultList } from '@shared/models' 7import { ActivityPubActorType, ActorFollow, FollowState, ResultList, ServerFollowCreate } from '@shared/models'
8import { environment } from '../../../environments/environment' 8import { environment } from '../../../environments/environment'
9 9
10@Injectable() 10@Injectable()
@@ -64,9 +64,10 @@ export class InstanceFollowService {
64 ) 64 )
65 } 65 }
66 66
67 follow (notEmptyHosts: string[]) { 67 follow (hostsOrHandles: string[]) {
68 const body = { 68 const body: ServerFollowCreate = {
69 hosts: notEmptyHosts 69 handles: hostsOrHandles.filter(v => v.includes('@')),
70 hosts: hostsOrHandles.filter(v => !v.includes('@'))
70 } 71 }
71 72
72 return this.authHttp.post(InstanceFollowService.BASE_APPLICATION_URL + '/following', body) 73 return this.authHttp.post(InstanceFollowService.BASE_APPLICATION_URL + '/following', body)
@@ -77,7 +78,9 @@ export class InstanceFollowService {
77 } 78 }
78 79
79 unfollow (follow: ActorFollow) { 80 unfollow (follow: ActorFollow) {
80 return this.authHttp.delete(InstanceFollowService.BASE_APPLICATION_URL + '/following/' + follow.following.host) 81 const handle = follow.following.name + '@' + follow.following.host
82
83 return this.authHttp.delete(InstanceFollowService.BASE_APPLICATION_URL + '/following/' + handle)
81 .pipe( 84 .pipe(
82 map(this.restExtractor.extractDataBool), 85 map(this.restExtractor.extractDataBool),
83 catchError(res => this.restExtractor.handleError(res)) 86 catchError(res => this.restExtractor.handleError(res))
diff --git a/client/src/app/shared/shared-moderation/batch-domains-modal.component.html b/client/src/app/shared/shared-moderation/batch-domains-modal.component.html
index 6a3c65721..8306a96bc 100644
--- a/client/src/app/shared/shared-moderation/batch-domains-modal.component.html
+++ b/client/src/app/shared/shared-moderation/batch-domains-modal.component.html
@@ -1,6 +1,6 @@
1<ng-template #modal> 1<ng-template #modal>
2 <div class="modal-header"> 2 <div class="modal-header">
3 <h4 i18n class="modal-title">{{ action }}</h4> 3 <h4 class="modal-title">{{ action }}</h4>
4 4
5 <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> 5 <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
6 </div> 6 </div>
@@ -11,15 +11,15 @@
11 <label i18n for="hosts">1 host (without "http://") per line</label> 11 <label i18n for="hosts">1 host (without "http://") per line</label>
12 12
13 <textarea 13 <textarea
14 [placeholder]="placeholder" formControlName="domains" type="text" id="hosts" name="hosts" 14 [placeholder]="placeholder" formControlName="hosts" type="text" id="hosts" name="hosts"
15 class="form-control" [ngClass]="{ 'input-error': formErrors['domains'] }" ngbAutofocus 15 class="form-control" [ngClass]="{ 'input-error': formErrors['hosts'] }" ngbAutofocus
16 ></textarea> 16 ></textarea>
17 17
18 <div *ngIf="formErrors.domains" class="form-error"> 18 <div *ngIf="formErrors.hosts" class="form-error">
19 {{ formErrors.domains }} 19 {{ formErrors.hosts }}
20 20
21 <div *ngIf="form.controls['domains'].errors.validDomains"> 21 <div *ngIf="form.controls['hosts'].errors.validHosts">
22 {{ form.controls['domains'].errors.validDomains.value }} 22 {{ form.controls['hosts'].errors.validHosts.value }}
23 </div> 23 </div>
24 </div> 24 </div>
25 </div> 25 </div>
diff --git a/client/src/app/shared/shared-moderation/batch-domains-modal.component.ts b/client/src/app/shared/shared-moderation/batch-domains-modal.component.ts
index 6edbb6023..20be728f6 100644
--- a/client/src/app/shared/shared-moderation/batch-domains-modal.component.ts
+++ b/client/src/app/shared/shared-moderation/batch-domains-modal.component.ts
@@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angu
2import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' 2import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
3import { NgbModal } from '@ng-bootstrap/ng-bootstrap' 3import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
4import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' 4import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
5import { DOMAINS_VALIDATOR, getNotEmptyHosts } from '../form-validators/batch-domains-validators' 5import { splitAndGetNotEmpty, UNIQUE_HOSTS_VALIDATOR } from '../form-validators/host-validators'
6 6
7@Component({ 7@Component({
8 selector: 'my-batch-domains-modal', 8 selector: 'my-batch-domains-modal',
@@ -28,7 +28,7 @@ export class BatchDomainsModalComponent extends FormReactive implements OnInit {
28 if (!this.action) this.action = $localize`Process domains` 28 if (!this.action) this.action = $localize`Process domains`
29 29
30 this.buildForm({ 30 this.buildForm({
31 domains: DOMAINS_VALIDATOR 31 hosts: UNIQUE_HOSTS_VALIDATOR
32 }) 32 })
33 } 33 }
34 34
@@ -41,9 +41,7 @@ export class BatchDomainsModalComponent extends FormReactive implements OnInit {
41 } 41 }
42 42
43 submit () { 43 submit () {
44 this.domains.emit( 44 this.domains.emit(splitAndGetNotEmpty(this.form.controls['hosts'].value))
45 getNotEmptyHosts(this.form.controls['domains'].value)
46 )
47 this.form.reset() 45 this.form.reset()
48 this.hide() 46 this.hide()
49 } 47 }