diff options
Diffstat (limited to 'client/src')
7 files changed, 149 insertions, 21 deletions
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html index 00a0d98f8..637484622 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html | |||
@@ -84,6 +84,7 @@ | |||
84 | </div> | 84 | </div> |
85 | </ng-container> | 85 | </ng-container> |
86 | 86 | ||
87 | |||
87 | <div i18n class="inner-form-title">Signup</div> | 88 | <div i18n class="inner-form-title">Signup</div> |
88 | 89 | ||
89 | <ng-container formGroupName="signup"> | 90 | <ng-container formGroupName="signup"> |
@@ -111,6 +112,7 @@ | |||
111 | </div> | 112 | </div> |
112 | </ng-container> | 113 | </ng-container> |
113 | 114 | ||
115 | |||
114 | <div i18n class="inner-form-title">Users</div> | 116 | <div i18n class="inner-form-title">Users</div> |
115 | 117 | ||
116 | <ng-container formGroupName="user"> | 118 | <ng-container formGroupName="user"> |
@@ -139,6 +141,7 @@ | |||
139 | </div> | 141 | </div> |
140 | </ng-container> | 142 | </ng-container> |
141 | 143 | ||
144 | |||
142 | <div i18n class="inner-form-title">Import</div> | 145 | <div i18n class="inner-form-title">Import</div> |
143 | 146 | ||
144 | <ng-container formGroupName="import"> | 147 | <ng-container formGroupName="import"> |
@@ -161,6 +164,7 @@ | |||
161 | </ng-container> | 164 | </ng-container> |
162 | </ng-container> | 165 | </ng-container> |
163 | 166 | ||
167 | |||
164 | <div i18n class="inner-form-title">Auto-blacklist</div> | 168 | <div i18n class="inner-form-title">Auto-blacklist</div> |
165 | 169 | ||
166 | <ng-container formGroupName="autoBlacklist"> | 170 | <ng-container formGroupName="autoBlacklist"> |
@@ -178,6 +182,29 @@ | |||
178 | </ng-container> | 182 | </ng-container> |
179 | </ng-container> | 183 | </ng-container> |
180 | 184 | ||
185 | |||
186 | <div i18n class="inner-form-title">Instance followers</div> | ||
187 | |||
188 | <ng-container formGroupName="followers"> | ||
189 | <ng-container formGroupName="instance"> | ||
190 | |||
191 | <div class="form-group"> | ||
192 | <my-peertube-checkbox | ||
193 | inputName="followersInstanceEnabled" formControlName="enabled" | ||
194 | i18n-labelText labelText="Other instances can follow your instance" | ||
195 | ></my-peertube-checkbox> | ||
196 | </div> | ||
197 | |||
198 | <div class="form-group"> | ||
199 | <my-peertube-checkbox | ||
200 | inputName="followersInstanceManualApproval" formControlName="manualApproval" | ||
201 | i18n-labelText labelText="Manually approve new instance follower" | ||
202 | ></my-peertube-checkbox> | ||
203 | </div> | ||
204 | </ng-container> | ||
205 | </ng-container> | ||
206 | |||
207 | |||
181 | <div i18n class="inner-form-title">Administrator</div> | 208 | <div i18n class="inner-form-title">Administrator</div> |
182 | 209 | ||
183 | <div class="form-group" formGroupName="admin"> | 210 | <div class="form-group" formGroupName="admin"> |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts index d8eb55da7..e64750713 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts | |||
@@ -5,7 +5,7 @@ import { CustomConfigValidatorsService, FormReactive, UserValidatorsService } fr | |||
5 | import { Notifier } from '@app/core' | 5 | import { Notifier } from '@app/core' |
6 | import { CustomConfig } from '../../../../../../shared/models/server/custom-config.model' | 6 | import { CustomConfig } from '../../../../../../shared/models/server/custom-config.model' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | 7 | import { I18n } from '@ngx-translate/i18n-polyfill' |
8 | import { BuildFormDefaultValues, FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | 8 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' |
9 | 9 | ||
10 | @Component({ | 10 | @Component({ |
11 | selector: 'my-edit-custom-config', | 11 | selector: 'my-edit-custom-config', |
@@ -124,6 +124,12 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit { | |||
124 | enabled: null | 124 | enabled: null |
125 | } | 125 | } |
126 | } | 126 | } |
127 | }, | ||
128 | followers: { | ||
129 | instance: { | ||
130 | enabled: null, | ||
131 | manualApproval: null | ||
132 | } | ||
127 | } | 133 | } |
128 | } | 134 | } |
129 | 135 | ||
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html index fc022bdb4..da0ba95e3 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.html +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html | |||
@@ -14,25 +14,33 @@ | |||
14 | <ng-template pTemplate="header"> | 14 | <ng-template pTemplate="header"> |
15 | <tr> | 15 | <tr> |
16 | <th i18n style="width: 60px">ID</th> | 16 | <th i18n style="width: 60px">ID</th> |
17 | <th i18n>Score</th> | 17 | <th i18n>Follower handle</th> |
18 | <th i18n>Name</th> | ||
19 | <th i18n>Host</th> | ||
20 | <th i18n>State</th> | 18 | <th i18n>State</th> |
19 | <th i18n>Score</th> | ||
21 | <th i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | 20 | <th i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> |
21 | <th></th> | ||
22 | </tr> | 22 | </tr> |
23 | </ng-template> | 23 | </ng-template> |
24 | 24 | ||
25 | <ng-template pTemplate="body" let-follow> | 25 | <ng-template pTemplate="body" let-follow> |
26 | <tr> | 26 | <tr> |
27 | <td>{{ follow.id }}</td> | 27 | <td>{{ follow.id }}</td> |
28 | <td>{{ follow.score }}</td> | 28 | <td>{{ follow.follower.name + '@' + follow.follower.host }}</td> |
29 | <td>{{ follow.follower.name }}</td> | ||
30 | <td>{{ follow.follower.host }}</td> | ||
31 | 29 | ||
32 | <td *ngIf="follow.state === 'accepted'" i18n>Accepted</td> | 30 | <td *ngIf="follow.state === 'accepted'" i18n>Accepted</td> |
33 | <td *ngIf="follow.state === 'pending'" i18n>Pending</td> | 31 | <td *ngIf="follow.state === 'pending'" i18n>Pending</td> |
34 | 32 | ||
33 | <td>{{ follow.score }}</td> | ||
35 | <td>{{ follow.createdAt }}</td> | 34 | <td>{{ follow.createdAt }}</td> |
35 | |||
36 | <td class="action-cell"> | ||
37 | <ng-container *ngIf="follow.state === 'pending'"> | ||
38 | <my-button i18n-label label="Accept" icon="tick" (click)="acceptFollower(follow)"></my-button> | ||
39 | <my-button i18n-label label="Refuse" icon="cross" (click)="rejectFollower(follow)"></my-button> | ||
40 | </ng-container> | ||
41 | |||
42 | <my-delete-button *ngIf="follow.state === 'accepted'" (click)="deleteFollower(follow)"></my-delete-button> | ||
43 | </td> | ||
36 | </tr> | 44 | </tr> |
37 | </ng-template> | 45 | </ng-template> |
38 | </p-table> | 46 | </p-table> |
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.scss b/client/src/app/+admin/follows/followers-list/followers-list.component.scss index a6f0656b8..964b3f99b 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.scss +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.scss | |||
@@ -7,4 +7,10 @@ | |||
7 | input { | 7 | input { |
8 | @include peertube-input-text(250px); | 8 | @include peertube-input-text(250px); |
9 | } | 9 | } |
10 | } \ No newline at end of file | 10 | } |
11 | |||
12 | .action-cell { | ||
13 | my-button:first-child { | ||
14 | margin-right: 10px; | ||
15 | } | ||
16 | } | ||
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.ts b/client/src/app/+admin/follows/followers-list/followers-list.component.ts index 9a8848bfb..b78cdf656 100644 --- a/client/src/app/+admin/follows/followers-list/followers-list.component.ts +++ b/client/src/app/+admin/follows/followers-list/followers-list.component.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | 2 | import { ConfirmService, Notifier } from '@app/core' | |
3 | import { Notifier } from '@app/core' | ||
4 | import { SortMeta } from 'primeng/primeng' | 3 | import { SortMeta } from 'primeng/primeng' |
5 | import { ActorFollow } from '../../../../../../shared/models/actors/follow.model' | 4 | import { ActorFollow } from '../../../../../../shared/models/actors/follow.model' |
6 | import { RestPagination, RestTable } from '../../../shared' | 5 | import { RestPagination, RestTable } from '../../../shared' |
@@ -20,9 +19,10 @@ export class FollowersListComponent extends RestTable implements OnInit { | |||
20 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 19 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
21 | 20 | ||
22 | constructor ( | 21 | constructor ( |
22 | private confirmService: ConfirmService, | ||
23 | private notifier: Notifier, | 23 | private notifier: Notifier, |
24 | private followService: FollowService, | 24 | private i18n: I18n, |
25 | private i18n: I18n | 25 | private followService: FollowService |
26 | ) { | 26 | ) { |
27 | super() | 27 | super() |
28 | } | 28 | } |
@@ -31,6 +31,62 @@ export class FollowersListComponent extends RestTable implements OnInit { | |||
31 | this.initialize() | 31 | this.initialize() |
32 | } | 32 | } |
33 | 33 | ||
34 | acceptFollower (follow: ActorFollow) { | ||
35 | follow.state = 'accepted' | ||
36 | |||
37 | this.followService.acceptFollower(follow) | ||
38 | .subscribe( | ||
39 | () => { | ||
40 | const handle = follow.follower.name + '@' + follow.follower.host | ||
41 | this.notifier.success(this.i18n('{{handle}} accepted in instance followers', { handle })) | ||
42 | }, | ||
43 | |||
44 | err => { | ||
45 | follow.state = 'pending' | ||
46 | this.notifier.error(err.message) | ||
47 | } | ||
48 | ) | ||
49 | } | ||
50 | |||
51 | async rejectFollower (follow: ActorFollow) { | ||
52 | const message = this.i18n('Do you really want to reject this follower?') | ||
53 | const res = await this.confirmService.confirm(message, this.i18n('Reject')) | ||
54 | if (res === false) return | ||
55 | |||
56 | this.followService.rejectFollower(follow) | ||
57 | .subscribe( | ||
58 | () => { | ||
59 | const handle = follow.follower.name + '@' + follow.follower.host | ||
60 | this.notifier.success(this.i18n('{{handle}} rejected from instance followers', { handle })) | ||
61 | |||
62 | this.loadData() | ||
63 | }, | ||
64 | |||
65 | err => { | ||
66 | follow.state = 'pending' | ||
67 | this.notifier.error(err.message) | ||
68 | } | ||
69 | ) | ||
70 | } | ||
71 | |||
72 | async deleteFollower (follow: ActorFollow) { | ||
73 | const message = this.i18n('Do you really want to delete this follower?') | ||
74 | const res = await this.confirmService.confirm(message, this.i18n('Delete')) | ||
75 | if (res === false) return | ||
76 | |||
77 | this.followService.removeFollower(follow) | ||
78 | .subscribe( | ||
79 | () => { | ||
80 | const handle = follow.follower.name + '@' + follow.follower.host | ||
81 | this.notifier.success(this.i18n('{{handle}} removed from instance followers', { handle })) | ||
82 | |||
83 | this.loadData() | ||
84 | }, | ||
85 | |||
86 | err => this.notifier.error(err.message) | ||
87 | ) | ||
88 | } | ||
89 | |||
34 | protected loadData () { | 90 | protected loadData () { |
35 | this.followService.getFollowers(this.pagination, this.sort, this.search) | 91 | this.followService.getFollowers(this.pagination, this.sort, this.search) |
36 | .subscribe( | 92 | .subscribe( |
diff --git a/client/src/app/+admin/follows/shared/follow.service.ts b/client/src/app/+admin/follows/shared/follow.service.ts index a2904179e..c2b8ef006 100644 --- a/client/src/app/+admin/follows/shared/follow.service.ts +++ b/client/src/app/+admin/follows/shared/follow.service.ts | |||
@@ -63,4 +63,34 @@ export class FollowService { | |||
63 | catchError(res => this.restExtractor.handleError(res)) | 63 | catchError(res => this.restExtractor.handleError(res)) |
64 | ) | 64 | ) |
65 | } | 65 | } |
66 | |||
67 | acceptFollower (follow: ActorFollow) { | ||
68 | const handle = follow.follower.name + '@' + follow.follower.host | ||
69 | |||
70 | return this.authHttp.post(`${FollowService.BASE_APPLICATION_URL}/followers/${handle}/accept`, {}) | ||
71 | .pipe( | ||
72 | map(this.restExtractor.extractDataBool), | ||
73 | catchError(res => this.restExtractor.handleError(res)) | ||
74 | ) | ||
75 | } | ||
76 | |||
77 | rejectFollower (follow: ActorFollow) { | ||
78 | const handle = follow.follower.name + '@' + follow.follower.host | ||
79 | |||
80 | return this.authHttp.post(`${FollowService.BASE_APPLICATION_URL}/followers/${handle}/reject`, {}) | ||
81 | .pipe( | ||
82 | map(this.restExtractor.extractDataBool), | ||
83 | catchError(res => this.restExtractor.handleError(res)) | ||
84 | ) | ||
85 | } | ||
86 | |||
87 | removeFollower (follow: ActorFollow) { | ||
88 | const handle = follow.follower.name + '@' + follow.follower.host | ||
89 | |||
90 | return this.authHttp.delete(`${FollowService.BASE_APPLICATION_URL}/followers/${handle}`) | ||
91 | .pipe( | ||
92 | map(this.restExtractor.extractDataBool), | ||
93 | catchError(res => this.restExtractor.handleError(res)) | ||
94 | ) | ||
95 | } | ||
66 | } | 96 | } |
diff --git a/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.html b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.html index 5709e9f54..c5fd3ccb9 100644 --- a/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.html +++ b/client/src/app/+my-account/my-account-ownership/my-account-ownership.component.html | |||
@@ -30,8 +30,7 @@ | |||
30 | </a> | 30 | </a> |
31 | </td> | 31 | </td> |
32 | <td> | 32 | <td> |
33 | <a [href]="videoChangeOwnership.video.url" i18n-title title="Go to the video" target="_blank" | 33 | <a [href]="videoChangeOwnership.video.url" i18n-title title="Go to the video" target="_blank" rel="noopener noreferrer"> |
34 | rel="noopener noreferrer"> | ||
35 | {{ videoChangeOwnership.video.name }} | 34 | {{ videoChangeOwnership.video.name }} |
36 | </a> | 35 | </a> |
37 | </td> | 36 | </td> |
@@ -39,16 +38,12 @@ | |||
39 | <td i18n>{{ videoChangeOwnership.status }}</td> | 38 | <td i18n>{{ videoChangeOwnership.status }}</td> |
40 | <td class="action-cell"> | 39 | <td class="action-cell"> |
41 | <ng-container *ngIf="videoChangeOwnership.status === 'WAITING'"> | 40 | <ng-container *ngIf="videoChangeOwnership.status === 'WAITING'"> |
42 | <my-button i18n label="Accept" | 41 | <my-button i18n-label label="Accept" icon="tick" (click)="openAcceptModal(videoChangeOwnership)"></my-button> |
43 | icon="tick" | 42 | <my-button i18n-label label="Refuse" icon="cross" (click)="refuse(videoChangeOwnership)"></my-button> |
44 | (click)="openAcceptModal(videoChangeOwnership)"></my-button> | ||
45 | <my-button i18n label="Refuse" | ||
46 | icon="cross" | ||
47 | (click)="refuse(videoChangeOwnership)">Refuse</my-button> | ||
48 | </ng-container> | 43 | </ng-container> |
49 | </td> | 44 | </td> |
50 | </tr> | 45 | </tr> |
51 | </ng-template> | 46 | </ng-template> |
52 | </p-table> | 47 | </p-table> |
53 | 48 | ||
54 | <my-account-accept-ownership #myAccountAcceptOwnershipComponent (accepted)="accepted()"></my-account-accept-ownership> \ No newline at end of file | 49 | <my-account-accept-ownership #myAccountAcceptOwnershipComponent (accepted)="accepted()"></my-account-accept-ownership> |