diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-06-15 13:18:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-15 13:18:22 +0200 |
commit | 228393302d98136d4dc35c5f197edc8cebd5d64f (patch) | |
tree | f92b3ad80bcc9c89088ff1d4de5ebff76a3f46ed | |
parent | 7dfe35288613967f5ac69cd46901ec60c5050b93 (diff) | |
download | PeerTube-228393302d98136d4dc35c5f197edc8cebd5d64f.tar.gz PeerTube-228393302d98136d4dc35c5f197edc8cebd5d64f.tar.zst PeerTube-228393302d98136d4dc35c5f197edc8cebd5d64f.zip |
factorize account/server blocklists for users and instance (#2875)
30 files changed, 326 insertions, 341 deletions
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index eb073f709..eccec8a49 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -27,7 +27,6 @@ import { SelectButtonModule } from 'primeng/selectbutton' | |||
27 | import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' | 27 | import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service' |
28 | import { VideoRedundancyInformationComponent } from '@app/+admin/follows/video-redundancies-list/video-redundancy-information.component' | 28 | import { VideoRedundancyInformationComponent } from '@app/+admin/follows/video-redundancies-list/video-redundancy-information.component' |
29 | import { ChartModule } from 'primeng/chart' | 29 | import { ChartModule } from 'primeng/chart' |
30 | import { BatchDomainsModalComponent } from './config/shared/batch-domains-modal.component' | ||
31 | import { VideoAbuseDetailsComponent } from './moderation/video-abuse-list/video-abuse-details.component' | 30 | import { VideoAbuseDetailsComponent } from './moderation/video-abuse-list/video-abuse-details.component' |
32 | 31 | ||
33 | @NgModule({ | 32 | @NgModule({ |
@@ -76,9 +75,7 @@ import { VideoAbuseDetailsComponent } from './moderation/video-abuse-list/video- | |||
76 | DebugComponent, | 75 | DebugComponent, |
77 | 76 | ||
78 | ConfigComponent, | 77 | ConfigComponent, |
79 | EditCustomConfigComponent, | 78 | EditCustomConfigComponent |
80 | |||
81 | BatchDomainsModalComponent | ||
82 | ], | 79 | ], |
83 | 80 | ||
84 | exports: [ | 81 | exports: [ |
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 298871fce..48b5681f4 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 | |||
@@ -56,7 +56,7 @@ | |||
56 | <ng-template pTemplate="emptymessage"> | 56 | <ng-template pTemplate="emptymessage"> |
57 | <tr> | 57 | <tr> |
58 | <td colspan="6"> | 58 | <td colspan="6"> |
59 | <div class="empty-table-message"> | 59 | <div class="no-results"> |
60 | <ng-container *ngIf="search" i18n>No follower found matching current filters.</ng-container> | 60 | <ng-container *ngIf="search" i18n>No follower found matching current filters.</ng-container> |
61 | <ng-container *ngIf="!search" i18n>Your instance doesn't have any follower.</ng-container> | 61 | <ng-container *ngIf="!search" i18n>Your instance doesn't have any follower.</ng-container> |
62 | </div> | 62 | </div> |
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html index ed521d650..a8fbf65d4 100644 --- a/client/src/app/+admin/follows/following-list/following-list.component.html +++ b/client/src/app/+admin/follows/following-list/following-list.component.html | |||
@@ -58,7 +58,7 @@ | |||
58 | <ng-template pTemplate="emptymessage"> | 58 | <ng-template pTemplate="emptymessage"> |
59 | <tr> | 59 | <tr> |
60 | <td colspan="6"> | 60 | <td colspan="6"> |
61 | <div class="empty-table-message"> | 61 | <div class="no-results"> |
62 | <ng-container *ngIf="search" i18n>No host found matching current filters.</ng-container> | 62 | <ng-container *ngIf="search" i18n>No host found matching current filters.</ng-container> |
63 | <ng-container *ngIf="!search" i18n>Your instance is not following anyone.</ng-container> | 63 | <ng-container *ngIf="!search" i18n>Your instance is not following anyone.</ng-container> |
64 | </div> | 64 | </div> |
diff --git a/client/src/app/+admin/follows/follows.component.scss b/client/src/app/+admin/follows/follows.component.scss index 32394f698..0cffcb555 100644 --- a/client/src/app/+admin/follows/follows.component.scss +++ b/client/src/app/+admin/follows/follows.component.scss | |||
@@ -4,7 +4,3 @@ | |||
4 | flex-grow: 0; | 4 | flex-grow: 0; |
5 | margin-right: 30px; | 5 | margin-right: 30px; |
6 | } | 6 | } |
7 | |||
8 | .empty-table-message { | ||
9 | @include empty-state; | ||
10 | } | ||
diff --git a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html index c08154bcd..44586cb67 100644 --- a/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html +++ b/client/src/app/+admin/follows/video-redundancies-list/video-redundancies-list.component.html | |||
@@ -73,7 +73,7 @@ | |||
73 | <ng-template pTemplate="emptymessage"> | 73 | <ng-template pTemplate="emptymessage"> |
74 | <tr> | 74 | <tr> |
75 | <td colspan="6"> | 75 | <td colspan="6"> |
76 | <div class="empty-table-message"> | 76 | <div class="no-results"> |
77 | <ng-container *ngIf="isDisplayingRemoteVideos()" i18n>Your instance doesn't mirror any video.</ng-container> | 77 | <ng-container *ngIf="isDisplayingRemoteVideos()" i18n>Your instance doesn't mirror any video.</ng-container> |
78 | <ng-container *ngIf="!isDisplayingRemoteVideos()" i18n>Your instance has no mirrored videos.</ng-container> | 78 | <ng-container *ngIf="!isDisplayingRemoteVideos()" i18n>Your instance has no mirrored videos.</ng-container> |
79 | </div> | 79 | </div> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html index b7d40be60..486785f35 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html | |||
@@ -54,7 +54,7 @@ | |||
54 | <ng-template pTemplate="emptymessage"> | 54 | <ng-template pTemplate="emptymessage"> |
55 | <tr> | 55 | <tr> |
56 | <td colspan="6"> | 56 | <td colspan="6"> |
57 | <div class="empty-table-message"> | 57 | <div class="no-results"> |
58 | <ng-container *ngIf="search" i18n>No account found matching current filters.</ng-container> | 58 | <ng-container *ngIf="search" i18n>No account found matching current filters.</ng-container> |
59 | <ng-container *ngIf="!search" i18n>No account found.</ng-container> | 59 | <ng-container *ngIf="!search" i18n>No account found.</ng-container> |
60 | </div> | 60 | </div> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.ts b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.ts index 73a9ae75d..90a176194 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.ts +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.ts | |||
@@ -1,70 +1,15 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { GenericAccountBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | import { RestPagination, RestTable } from '@app/shared' | ||
5 | import { SortMeta } from 'primeng/api' | ||
6 | import { AccountBlock, BlocklistService } from '@app/shared/blocklist' | ||
7 | import { Actor } from '@app/shared/actor/actor.model' | ||
8 | 3 | ||
9 | @Component({ | 4 | @Component({ |
10 | selector: 'my-instance-account-blocklist', | 5 | selector: 'my-instance-account-blocklist', |
11 | styleUrls: [ '../moderation.component.scss', './instance-account-blocklist.component.scss' ], | 6 | styleUrls: [ '../moderation.component.scss', '../../../shared/blocklist/account-blocklist.component.scss' ], |
12 | templateUrl: './instance-account-blocklist.component.html' | 7 | templateUrl: '../../../shared/blocklist/account-blocklist.component.html' |
13 | }) | 8 | }) |
14 | export class InstanceAccountBlocklistComponent extends RestTable implements OnInit { | 9 | export class InstanceAccountBlocklistComponent extends GenericAccountBlocklistComponent { |
15 | blockedAccounts: AccountBlock[] = [] | 10 | mode = BlocklistComponentType.Instance |
16 | totalRecords = 0 | ||
17 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
18 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
19 | |||
20 | constructor ( | ||
21 | private notifier: Notifier, | ||
22 | private blocklistService: BlocklistService, | ||
23 | private i18n: I18n | ||
24 | ) { | ||
25 | super() | ||
26 | } | ||
27 | |||
28 | ngOnInit () { | ||
29 | this.initialize() | ||
30 | } | ||
31 | 11 | ||
32 | getIdentifier () { | 12 | getIdentifier () { |
33 | return 'InstanceAccountBlocklistComponent' | 13 | return 'InstanceAccountBlocklistComponent' |
34 | } | 14 | } |
35 | |||
36 | switchToDefaultAvatar ($event: Event) { | ||
37 | ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() | ||
38 | } | ||
39 | |||
40 | unblockAccount (accountBlock: AccountBlock) { | ||
41 | const blockedAccount = accountBlock.blockedAccount | ||
42 | |||
43 | this.blocklistService.unblockAccountByInstance(blockedAccount) | ||
44 | .subscribe( | ||
45 | () => { | ||
46 | this.notifier.success( | ||
47 | this.i18n('Account {{nameWithHost}} unmuted by your instance.', { nameWithHost: blockedAccount.nameWithHost }) | ||
48 | ) | ||
49 | |||
50 | this.loadData() | ||
51 | } | ||
52 | ) | ||
53 | } | ||
54 | |||
55 | protected loadData () { | ||
56 | return this.blocklistService.getInstanceAccountBlocklist({ | ||
57 | pagination: this.pagination, | ||
58 | sort: this.sort, | ||
59 | search: this.search | ||
60 | }) | ||
61 | .subscribe( | ||
62 | resultList => { | ||
63 | this.blockedAccounts = resultList.data | ||
64 | this.totalRecords = resultList.total | ||
65 | }, | ||
66 | |||
67 | err => this.notifier.error(err.message) | ||
68 | ) | ||
69 | } | ||
70 | } | 15 | } |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.ts b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.ts index 559c9c0b0..9d4ec174a 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.ts +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.ts | |||
@@ -1,84 +1,15 @@ | |||
1 | import { Component, OnInit, ViewChild } from '@angular/core' | 1 | import { Component } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { GenericServerBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | import { RestPagination, RestTable } from '@app/shared' | ||
5 | import { SortMeta } from 'primeng/api' | ||
6 | import { BlocklistService } from '@app/shared/blocklist' | ||
7 | import { ServerBlock } from '../../../../../../shared' | ||
8 | import { BatchDomainsModalComponent } from '@app/+admin/config/shared/batch-domains-modal.component' | ||
9 | 3 | ||
10 | @Component({ | 4 | @Component({ |
11 | selector: 'my-instance-server-blocklist', | 5 | selector: 'my-instance-server-blocklist', |
12 | styleUrls: [ '../moderation.component.scss', './instance-server-blocklist.component.scss' ], | 6 | styleUrls: [ '../../../shared/blocklist/server-blocklist.component.scss' ], |
13 | templateUrl: './instance-server-blocklist.component.html' | 7 | templateUrl: '../../../shared/blocklist/server-blocklist.component.html' |
14 | }) | 8 | }) |
15 | export class InstanceServerBlocklistComponent extends RestTable implements OnInit { | 9 | export class InstanceServerBlocklistComponent extends GenericServerBlocklistComponent { |
16 | @ViewChild('batchDomainsModal') batchDomainsModal: BatchDomainsModalComponent | 10 | mode = BlocklistComponentType.Instance |
17 | |||
18 | blockedServers: ServerBlock[] = [] | ||
19 | totalRecords = 0 | ||
20 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
21 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
22 | |||
23 | constructor ( | ||
24 | private notifier: Notifier, | ||
25 | private blocklistService: BlocklistService, | ||
26 | private i18n: I18n | ||
27 | ) { | ||
28 | super() | ||
29 | } | ||
30 | |||
31 | ngOnInit () { | ||
32 | this.initialize() | ||
33 | } | ||
34 | 11 | ||
35 | getIdentifier () { | 12 | getIdentifier () { |
36 | return 'InstanceServerBlocklistComponent' | 13 | return 'InstanceServerBlocklistComponent' |
37 | } | 14 | } |
38 | |||
39 | unblockServer (serverBlock: ServerBlock) { | ||
40 | const host = serverBlock.blockedServer.host | ||
41 | |||
42 | this.blocklistService.unblockServerByInstance(host) | ||
43 | .subscribe( | ||
44 | () => { | ||
45 | this.notifier.success(this.i18n('Instance {{host}} unmuted by your instance.', { host })) | ||
46 | |||
47 | this.loadData() | ||
48 | } | ||
49 | ) | ||
50 | } | ||
51 | |||
52 | addServersToBlock () { | ||
53 | this.batchDomainsModal.openModal() | ||
54 | } | ||
55 | |||
56 | onDomainsToBlock (domains: string[]) { | ||
57 | domains.forEach(domain => { | ||
58 | this.blocklistService.blockServerByInstance(domain) | ||
59 | .subscribe( | ||
60 | () => { | ||
61 | this.notifier.success(this.i18n('Instance {{domain}} muted by your instance.', { domain })) | ||
62 | |||
63 | this.loadData() | ||
64 | } | ||
65 | ) | ||
66 | }) | ||
67 | } | ||
68 | |||
69 | protected loadData () { | ||
70 | return this.blocklistService.getInstanceServerBlocklist({ | ||
71 | pagination: this.pagination, | ||
72 | sort: this.sort, | ||
73 | search: this.search | ||
74 | }) | ||
75 | .subscribe( | ||
76 | resultList => { | ||
77 | this.blockedServers = resultList.data | ||
78 | this.totalRecords = resultList.total | ||
79 | }, | ||
80 | |||
81 | err => this.notifier.error(err.message) | ||
82 | ) | ||
83 | } | ||
84 | } | 15 | } |
diff --git a/client/src/app/+admin/moderation/moderation.component.scss b/client/src/app/+admin/moderation/moderation.component.scss index 404eb0504..ba68cf6f6 100644 --- a/client/src/app/+admin/moderation/moderation.component.scss +++ b/client/src/app/+admin/moderation/moderation.component.scss | |||
@@ -16,10 +16,6 @@ | |||
16 | } | 16 | } |
17 | } | 17 | } |
18 | 18 | ||
19 | .empty-table-message { | ||
20 | @include empty-state; | ||
21 | } | ||
22 | |||
23 | .moderation-expanded { | 19 | .moderation-expanded { |
24 | font-size: 90%; | 20 | font-size: 90%; |
25 | 21 | ||
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html index a2ed51559..64641b28a 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html | |||
@@ -137,7 +137,7 @@ | |||
137 | <ng-template pTemplate="emptymessage"> | 137 | <ng-template pTemplate="emptymessage"> |
138 | <tr> | 138 | <tr> |
139 | <td colspan="6"> | 139 | <td colspan="6"> |
140 | <div class="empty-table-message"> | 140 | <div class="no-results"> |
141 | <ng-container *ngIf="search" i18n>No video abuses found matching current filters.</ng-container> | 141 | <ng-container *ngIf="search" i18n>No video abuses found matching current filters.</ng-container> |
142 | <ng-container *ngIf="!search" i18n>No video abuses found.</ng-container> | 142 | <ng-container *ngIf="!search" i18n>No video abuses found.</ng-container> |
143 | </div> | 143 | </div> |
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html index a01a2566d..ec20e46f1 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html | |||
@@ -102,7 +102,7 @@ | |||
102 | <ng-template pTemplate="emptymessage"> | 102 | <ng-template pTemplate="emptymessage"> |
103 | <tr> | 103 | <tr> |
104 | <td colspan="6"> | 104 | <td colspan="6"> |
105 | <div class="empty-table-message"> | 105 | <div class="no-results"> |
106 | <ng-container *ngIf="search" i18n>No blocked video found matching current filters.</ng-container> | 106 | <ng-container *ngIf="search" i18n>No blocked video found matching current filters.</ng-container> |
107 | <ng-container *ngIf="!search" i18n>No blocked video found.</ng-container> | 107 | <ng-container *ngIf="!search" i18n>No blocked video found.</ng-container> |
108 | </div> | 108 | </div> |
diff --git a/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.html b/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.html deleted file mode 100644 index 90f657521..000000000 --- a/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.html +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | <div class="admin-sub-header"> | ||
2 | <h1 i18n class="form-sub-title">Muted accounts</h1> | ||
3 | </div> | ||
4 | |||
5 | <p-table | ||
6 | [value]="blockedAccounts" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
7 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" | ||
8 | > | ||
9 | |||
10 | <ng-template pTemplate="header"> | ||
11 | <tr> | ||
12 | <th i18n>Account</th> | ||
13 | <th i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
14 | <th></th> <!-- column for action buttons --> | ||
15 | </tr> | ||
16 | </ng-template> | ||
17 | |||
18 | <ng-template pTemplate="body" let-accountBlock> | ||
19 | <tr> | ||
20 | <td>{{ accountBlock.blockedAccount.nameWithHost }}</td> | ||
21 | <td>{{ accountBlock.createdAt }}</td> | ||
22 | <td class="action-cell"> | ||
23 | <button class="unblock-button" (click)="unblockAccount(accountBlock)" i18n>Unmute</button> | ||
24 | </td> | ||
25 | </tr> | ||
26 | </ng-template> | ||
27 | </p-table> | ||
diff --git a/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.scss b/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.scss deleted file mode 100644 index 6028b75ea..000000000 --- a/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.scss +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .unblock-button { | ||
5 | @include peertube-button; | ||
6 | @include grey-button; | ||
7 | } \ No newline at end of file | ||
diff --git a/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.ts b/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.ts index fd1fabcdb..e48c39cdf 100644 --- a/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.ts +++ b/client/src/app/+my-account/my-account-blocklist/my-account-blocklist.component.ts | |||
@@ -1,59 +1,15 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { GenericAccountBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | import { RestPagination, RestTable } from '@app/shared' | ||
5 | import { SortMeta } from 'primeng/api' | ||
6 | import { AccountBlock, BlocklistService } from '@app/shared/blocklist' | ||
7 | 3 | ||
8 | @Component({ | 4 | @Component({ |
9 | selector: 'my-account-blocklist', | 5 | selector: 'my-account-blocklist', |
10 | styleUrls: [ './my-account-blocklist.component.scss' ], | 6 | styleUrls: [ '../../shared/blocklist/account-blocklist.component.scss' ], |
11 | templateUrl: './my-account-blocklist.component.html' | 7 | templateUrl: '../../shared/blocklist/account-blocklist.component.html' |
12 | }) | 8 | }) |
13 | export class MyAccountBlocklistComponent extends RestTable implements OnInit { | 9 | export class MyAccountBlocklistComponent extends GenericAccountBlocklistComponent { |
14 | blockedAccounts: AccountBlock[] = [] | 10 | mode = BlocklistComponentType.Account |
15 | totalRecords = 0 | ||
16 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
17 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
18 | |||
19 | constructor ( | ||
20 | private notifier: Notifier, | ||
21 | private blocklistService: BlocklistService, | ||
22 | private i18n: I18n | ||
23 | ) { | ||
24 | super() | ||
25 | } | ||
26 | |||
27 | ngOnInit () { | ||
28 | this.initialize() | ||
29 | } | ||
30 | 11 | ||
31 | getIdentifier () { | 12 | getIdentifier () { |
32 | return 'MyAccountBlocklistComponent' | 13 | return 'MyAccountBlocklistComponent' |
33 | } | 14 | } |
34 | |||
35 | unblockAccount (accountBlock: AccountBlock) { | ||
36 | const blockedAccount = accountBlock.blockedAccount | ||
37 | |||
38 | this.blocklistService.unblockAccountByUser(blockedAccount) | ||
39 | .subscribe( | ||
40 | () => { | ||
41 | this.notifier.success(this.i18n('Account {{nameWithHost}} unmuted.', { nameWithHost: blockedAccount.nameWithHost })) | ||
42 | |||
43 | this.loadData() | ||
44 | } | ||
45 | ) | ||
46 | } | ||
47 | |||
48 | protected loadData () { | ||
49 | return this.blocklistService.getUserAccountBlocklist(this.pagination, this.sort) | ||
50 | .subscribe( | ||
51 | resultList => { | ||
52 | this.blockedAccounts = resultList.data | ||
53 | this.totalRecords = resultList.total | ||
54 | }, | ||
55 | |||
56 | err => this.notifier.error(err.message) | ||
57 | ) | ||
58 | } | ||
59 | } | 15 | } |
diff --git a/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.html b/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.html deleted file mode 100644 index c31cff16f..000000000 --- a/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.html +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | <div class="admin-sub-header"> | ||
2 | <h1 i18n class="form-sub-title">Muted instances</h1> | ||
3 | </div> | ||
4 | |||
5 | <p-table | ||
6 | [value]="blockedServers" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" | ||
7 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" | ||
8 | > | ||
9 | |||
10 | <ng-template pTemplate="header"> | ||
11 | <tr> | ||
12 | <th i18n>Instance</th> | ||
13 | <th i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
14 | <th></th> <!-- column for action buttons --> | ||
15 | </tr> | ||
16 | </ng-template> | ||
17 | |||
18 | <ng-template pTemplate="body" let-serverBlock> | ||
19 | <tr> | ||
20 | <td>{{ serverBlock.blockedServer.host }}</td> | ||
21 | <td>{{ serverBlock.createdAt }}</td> | ||
22 | <td class="action-cell"> | ||
23 | <button class="unblock-button" (click)="unblockServer(serverBlock)" i18n>Unmute</button> | ||
24 | </td> | ||
25 | </tr> | ||
26 | </ng-template> | ||
27 | </p-table> | ||
diff --git a/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.scss b/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.scss deleted file mode 100644 index 6028b75ea..000000000 --- a/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.scss +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .unblock-button { | ||
5 | @include peertube-button; | ||
6 | @include grey-button; | ||
7 | } \ No newline at end of file | ||
diff --git a/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.ts b/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.ts index 483c11804..cfaba1c7b 100644 --- a/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.ts +++ b/client/src/app/+my-account/my-account-blocklist/my-account-server-blocklist.component.ts | |||
@@ -1,60 +1,15 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component } from '@angular/core' |
2 | import { Notifier } from '@app/core' | 2 | import { GenericServerBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist' |
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | import { RestPagination, RestTable } from '@app/shared' | ||
5 | import { SortMeta } from 'primeng/api' | ||
6 | import { ServerBlock } from '../../../../../shared' | ||
7 | import { BlocklistService } from '@app/shared/blocklist' | ||
8 | 3 | ||
9 | @Component({ | 4 | @Component({ |
10 | selector: 'my-account-server-blocklist', | 5 | selector: 'my-account-server-blocklist', |
11 | styleUrls: [ './my-account-server-blocklist.component.scss' ], | 6 | styleUrls: [ '../../+admin/moderation/moderation.component.scss', '../../shared/blocklist/server-blocklist.component.scss' ], |
12 | templateUrl: './my-account-server-blocklist.component.html' | 7 | templateUrl: '../../shared/blocklist/server-blocklist.component.html' |
13 | }) | 8 | }) |
14 | export class MyAccountServerBlocklistComponent extends RestTable implements OnInit { | 9 | export class MyAccountServerBlocklistComponent extends GenericServerBlocklistComponent { |
15 | blockedServers: ServerBlock[] = [] | 10 | mode = BlocklistComponentType.Account |
16 | totalRecords = 0 | ||
17 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
18 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
19 | |||
20 | constructor ( | ||
21 | private notifier: Notifier, | ||
22 | private blocklistService: BlocklistService, | ||
23 | private i18n: I18n | ||
24 | ) { | ||
25 | super() | ||
26 | } | ||
27 | |||
28 | ngOnInit () { | ||
29 | this.initialize() | ||
30 | } | ||
31 | 11 | ||
32 | getIdentifier () { | 12 | getIdentifier () { |
33 | return 'MyAccountServerBlocklistComponent' | 13 | return 'MyAccountServerBlocklistComponent' |
34 | } | 14 | } |
35 | |||
36 | unblockServer (serverBlock: ServerBlock) { | ||
37 | const host = serverBlock.blockedServer.host | ||
38 | |||
39 | this.blocklistService.unblockServerByUser(host) | ||
40 | .subscribe( | ||
41 | () => { | ||
42 | this.notifier.success(this.i18n('Instance {{host}} unmuted.', { host })) | ||
43 | |||
44 | this.loadData() | ||
45 | } | ||
46 | ) | ||
47 | } | ||
48 | |||
49 | protected loadData () { | ||
50 | return this.blocklistService.getUserServerBlocklist(this.pagination, this.sort) | ||
51 | .subscribe( | ||
52 | resultList => { | ||
53 | this.blockedServers = resultList.data | ||
54 | this.totalRecords = resultList.total | ||
55 | }, | ||
56 | |||
57 | err => this.notifier.error(err.message) | ||
58 | ) | ||
59 | } | ||
60 | } | 15 | } |
diff --git a/client/src/app/+my-account/my-account-routing.module.ts b/client/src/app/+my-account/my-account-routing.module.ts index f44b60ec9..f6b711e09 100644 --- a/client/src/app/+my-account/my-account-routing.module.ts +++ b/client/src/app/+my-account/my-account-routing.module.ts | |||
@@ -140,7 +140,7 @@ const myAccountRoutes: Routes = [ | |||
140 | component: MyAccountServerBlocklistComponent, | 140 | component: MyAccountServerBlocklistComponent, |
141 | data: { | 141 | data: { |
142 | meta: { | 142 | meta: { |
143 | title: 'Muted instances' | 143 | title: 'Muted servers' |
144 | } | 144 | } |
145 | } | 145 | } |
146 | }, | 146 | }, |
diff --git a/client/src/app/+my-account/my-account.component.ts b/client/src/app/+my-account/my-account.component.ts index 05dcf522d..ca447c054 100644 --- a/client/src/app/+my-account/my-account.component.ts +++ b/client/src/app/+my-account/my-account.component.ts | |||
@@ -72,7 +72,7 @@ export class MyAccountComponent implements OnInit { | |||
72 | iconName: 'user' | 72 | iconName: 'user' |
73 | }, | 73 | }, |
74 | { | 74 | { |
75 | label: this.i18n('Muted instances'), | 75 | label: this.i18n('Muted servers'), |
76 | routerLink: '/my-account/blocklist/servers', | 76 | routerLink: '/my-account/blocklist/servers', |
77 | iconName: 'server' | 77 | iconName: 'server' |
78 | }, | 78 | }, |
diff --git a/client/src/app/shared/blocklist/account-blocklist.component.html b/client/src/app/shared/blocklist/account-blocklist.component.html new file mode 100644 index 000000000..486785f35 --- /dev/null +++ b/client/src/app/shared/blocklist/account-blocklist.component.html | |||
@@ -0,0 +1,64 @@ | |||
1 | <p-table | ||
2 | [value]="blockedAccounts" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | ||
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" (onPage)="onPage($event)" | ||
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | ||
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted accounts" | ||
6 | > | ||
7 | <ng-template pTemplate="caption"> | ||
8 | <div class="caption"> | ||
9 | <div class="ml-auto has-feedback has-clear"> | ||
10 | <input | ||
11 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
12 | (keyup)="onSearch($event)" | ||
13 | > | ||
14 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
15 | <span class="sr-only" i18n>Clear filters</span> | ||
16 | </div> | ||
17 | </div> | ||
18 | </ng-template> | ||
19 | |||
20 | <ng-template pTemplate="header"> | ||
21 | <tr> | ||
22 | <th style="width: 100%;" i18n>Account</th> | ||
23 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
24 | <th style="width: 150px;"></th> <!-- column for action buttons --> | ||
25 | </tr> | ||
26 | </ng-template> | ||
27 | |||
28 | <ng-template pTemplate="body" let-accountBlock> | ||
29 | <tr> | ||
30 | <td> | ||
31 | <a [href]="accountBlock.blockedAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> | ||
32 | <div class="chip two-lines"> | ||
33 | <img | ||
34 | class="avatar" | ||
35 | [src]="accountBlock.blockedAccount.avatar?.path" | ||
36 | (error)="switchToDefaultAvatar($event)" | ||
37 | alt="Avatar" | ||
38 | > | ||
39 | <div> | ||
40 | {{ accountBlock.blockedAccount.displayName }} | ||
41 | <span class="text-muted">{{ accountBlock.blockedAccount.nameWithHost }}</span> | ||
42 | </div> | ||
43 | </div> | ||
44 | </a> | ||
45 | </td> | ||
46 | |||
47 | <td>{{ accountBlock.createdAt | date: 'short' }}</td> | ||
48 | <td class="action-cell"> | ||
49 | <button class="unblock-button" (click)="unblockAccount(accountBlock)" i18n>Unmute</button> | ||
50 | </td> | ||
51 | </tr> | ||
52 | </ng-template> | ||
53 | |||
54 | <ng-template pTemplate="emptymessage"> | ||
55 | <tr> | ||
56 | <td colspan="6"> | ||
57 | <div class="no-results"> | ||
58 | <ng-container *ngIf="search" i18n>No account found matching current filters.</ng-container> | ||
59 | <ng-container *ngIf="!search" i18n>No account found.</ng-container> | ||
60 | </div> | ||
61 | </td> | ||
62 | </tr> | ||
63 | </ng-template> | ||
64 | </p-table> | ||
diff --git a/client/src/app/shared/blocklist/account-blocklist.component.scss b/client/src/app/shared/blocklist/account-blocklist.component.scss new file mode 100644 index 000000000..aa8363ff4 --- /dev/null +++ b/client/src/app/shared/blocklist/account-blocklist.component.scss | |||
@@ -0,0 +1,16 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .caption { | ||
5 | justify-content: flex-end; | ||
6 | |||
7 | input { | ||
8 | @include peertube-input-text(250px); | ||
9 | flex-grow: 1; | ||
10 | } | ||
11 | } | ||
12 | |||
13 | .unblock-button { | ||
14 | @include peertube-button; | ||
15 | @include grey-button; | ||
16 | } \ No newline at end of file | ||
diff --git a/client/src/app/shared/blocklist/account-blocklist.component.ts b/client/src/app/shared/blocklist/account-blocklist.component.ts new file mode 100644 index 000000000..dc5ac4044 --- /dev/null +++ b/client/src/app/shared/blocklist/account-blocklist.component.ts | |||
@@ -0,0 +1,79 @@ | |||
1 | import { OnInit } from '@angular/core' | ||
2 | import { Notifier } from '@app/core' | ||
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | import { RestPagination, RestTable } from '@app/shared/rest' | ||
5 | import { SortMeta } from 'primeng/api' | ||
6 | import { AccountBlock } from './account-block.model' | ||
7 | import { BlocklistService, BlocklistComponentType } from './blocklist.service' | ||
8 | import { Actor } from '@app/shared/actor/actor.model' | ||
9 | |||
10 | export class GenericAccountBlocklistComponent extends RestTable implements OnInit { | ||
11 | // @ts-ignore: "Abstract methods can only appear within an abstract class" | ||
12 | abstract mode: BlocklistComponentType | ||
13 | |||
14 | blockedAccounts: AccountBlock[] = [] | ||
15 | totalRecords = 0 | ||
16 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
17 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
18 | |||
19 | constructor ( | ||
20 | private notifier: Notifier, | ||
21 | private blocklistService: BlocklistService, | ||
22 | private i18n: I18n | ||
23 | ) { | ||
24 | super() | ||
25 | } | ||
26 | |||
27 | // @ts-ignore: "Abstract methods can only appear within an abstract class" | ||
28 | abstract getIdentifier (): string | ||
29 | |||
30 | ngOnInit () { | ||
31 | this.initialize() | ||
32 | } | ||
33 | |||
34 | switchToDefaultAvatar ($event: Event) { | ||
35 | ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() | ||
36 | } | ||
37 | |||
38 | unblockAccount (accountBlock: AccountBlock) { | ||
39 | const blockedAccount = accountBlock.blockedAccount | ||
40 | const operation = this.mode === BlocklistComponentType.Account | ||
41 | ? this.blocklistService.unblockAccountByUser(blockedAccount) | ||
42 | : this.blocklistService.unblockAccountByInstance(blockedAccount) | ||
43 | |||
44 | operation.subscribe( | ||
45 | () => { | ||
46 | this.notifier.success( | ||
47 | this.mode === BlocklistComponentType.Account | ||
48 | ? this.i18n('Account {{nameWithHost}} unmuted.', { nameWithHost: blockedAccount.nameWithHost }) | ||
49 | : this.i18n('Account {{nameWithHost}} unmuted by your instance.', { nameWithHost: blockedAccount.nameWithHost }) | ||
50 | ) | ||
51 | |||
52 | this.loadData() | ||
53 | } | ||
54 | ) | ||
55 | } | ||
56 | |||
57 | protected loadData () { | ||
58 | const operation = this.mode === BlocklistComponentType.Account | ||
59 | ? this.blocklistService.getUserAccountBlocklist({ | ||
60 | pagination: this.pagination, | ||
61 | sort: this.sort, | ||
62 | search: this.search | ||
63 | }) | ||
64 | : this.blocklistService.getInstanceAccountBlocklist({ | ||
65 | pagination: this.pagination, | ||
66 | sort: this.sort, | ||
67 | search: this.search | ||
68 | }) | ||
69 | |||
70 | return operation.subscribe( | ||
71 | resultList => { | ||
72 | this.blockedAccounts = resultList.data | ||
73 | this.totalRecords = resultList.total | ||
74 | }, | ||
75 | |||
76 | err => this.notifier.error(err.message) | ||
77 | ) | ||
78 | } | ||
79 | } | ||
diff --git a/client/src/app/shared/blocklist/blocklist.service.ts b/client/src/app/shared/blocklist/blocklist.service.ts index 5cf265bc1..c70a8173a 100644 --- a/client/src/app/shared/blocklist/blocklist.service.ts +++ b/client/src/app/shared/blocklist/blocklist.service.ts | |||
@@ -8,6 +8,8 @@ import { AccountBlock as AccountBlockServer, ResultList, ServerBlock } from '../ | |||
8 | import { Account } from '@app/shared/account/account.model' | 8 | import { Account } from '@app/shared/account/account.model' |
9 | import { AccountBlock } from '@app/shared/blocklist/account-block.model' | 9 | import { AccountBlock } from '@app/shared/blocklist/account-block.model' |
10 | 10 | ||
11 | export enum BlocklistComponentType { Account, Instance } | ||
12 | |||
11 | @Injectable() | 13 | @Injectable() |
12 | export class BlocklistService { | 14 | export class BlocklistService { |
13 | static BASE_USER_BLOCKLIST_URL = environment.apiUrl + '/api/v1/users/me/blocklist' | 15 | static BASE_USER_BLOCKLIST_URL = environment.apiUrl + '/api/v1/users/me/blocklist' |
@@ -21,10 +23,14 @@ export class BlocklistService { | |||
21 | 23 | ||
22 | /*********************** User -> Account blocklist ***********************/ | 24 | /*********************** User -> Account blocklist ***********************/ |
23 | 25 | ||
24 | getUserAccountBlocklist (pagination: RestPagination, sort: SortMeta) { | 26 | getUserAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) { |
27 | const { pagination, sort, search } = options | ||
28 | |||
25 | let params = new HttpParams() | 29 | let params = new HttpParams() |
26 | params = this.restService.addRestGetParams(params, pagination, sort) | 30 | params = this.restService.addRestGetParams(params, pagination, sort) |
27 | 31 | ||
32 | if (search) params = params.append('search', search) | ||
33 | |||
28 | return this.authHttp.get<ResultList<AccountBlock>>(BlocklistService.BASE_USER_BLOCKLIST_URL + '/accounts', { params }) | 34 | return this.authHttp.get<ResultList<AccountBlock>>(BlocklistService.BASE_USER_BLOCKLIST_URL + '/accounts', { params }) |
29 | .pipe( | 35 | .pipe( |
30 | map(res => this.restExtractor.convertResultListDateToHuman(res)), | 36 | map(res => this.restExtractor.convertResultListDateToHuman(res)), |
@@ -49,10 +55,14 @@ export class BlocklistService { | |||
49 | 55 | ||
50 | /*********************** User -> Server blocklist ***********************/ | 56 | /*********************** User -> Server blocklist ***********************/ |
51 | 57 | ||
52 | getUserServerBlocklist (pagination: RestPagination, sort: SortMeta) { | 58 | getUserServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) { |
59 | const { pagination, sort, search } = options | ||
60 | |||
53 | let params = new HttpParams() | 61 | let params = new HttpParams() |
54 | params = this.restService.addRestGetParams(params, pagination, sort) | 62 | params = this.restService.addRestGetParams(params, pagination, sort) |
55 | 63 | ||
64 | if (search) params = params.append('search', search) | ||
65 | |||
56 | return this.authHttp.get<ResultList<ServerBlock>>(BlocklistService.BASE_USER_BLOCKLIST_URL + '/servers', { params }) | 66 | return this.authHttp.get<ResultList<ServerBlock>>(BlocklistService.BASE_USER_BLOCKLIST_URL + '/servers', { params }) |
57 | .pipe( | 67 | .pipe( |
58 | map(res => this.restExtractor.convertResultListDateToHuman(res)), | 68 | map(res => this.restExtractor.convertResultListDateToHuman(res)), |
@@ -76,7 +86,7 @@ export class BlocklistService { | |||
76 | 86 | ||
77 | /*********************** Instance -> Account blocklist ***********************/ | 87 | /*********************** Instance -> Account blocklist ***********************/ |
78 | 88 | ||
79 | getInstanceAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search: string }) { | 89 | getInstanceAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) { |
80 | const { pagination, sort, search } = options | 90 | const { pagination, sort, search } = options |
81 | 91 | ||
82 | let params = new HttpParams() | 92 | let params = new HttpParams() |
@@ -108,7 +118,7 @@ export class BlocklistService { | |||
108 | 118 | ||
109 | /*********************** Instance -> Server blocklist ***********************/ | 119 | /*********************** Instance -> Server blocklist ***********************/ |
110 | 120 | ||
111 | getInstanceServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search: string }) { | 121 | getInstanceServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) { |
112 | const { pagination, sort, search } = options | 122 | const { pagination, sort, search } = options |
113 | 123 | ||
114 | let params = new HttpParams() | 124 | let params = new HttpParams() |
diff --git a/client/src/app/shared/blocklist/index.ts b/client/src/app/shared/blocklist/index.ts index 5886ca07e..188057b19 100644 --- a/client/src/app/shared/blocklist/index.ts +++ b/client/src/app/shared/blocklist/index.ts | |||
@@ -1,2 +1,4 @@ | |||
1 | export * from './blocklist.service' | 1 | export * from './blocklist.service' |
2 | export * from './account-block.model' | 2 | export * from './account-block.model' |
3 | export * from './server-blocklist.component' | ||
4 | export * from './account-blocklist.component' | ||
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html b/client/src/app/shared/blocklist/server-blocklist.component.html index 7a77b8842..977e0e141 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html +++ b/client/src/app/shared/blocklist/server-blocklist.component.html | |||
@@ -47,7 +47,7 @@ | |||
47 | <ng-template pTemplate="emptymessage"> | 47 | <ng-template pTemplate="emptymessage"> |
48 | <tr> | 48 | <tr> |
49 | <td colspan="6"> | 49 | <td colspan="6"> |
50 | <div class="empty-table-message"> | 50 | <div class="no-results"> |
51 | <ng-container *ngIf="search" i18n>No server found matching current filters.</ng-container> | 51 | <ng-container *ngIf="search" i18n>No server found matching current filters.</ng-container> |
52 | <ng-container *ngIf="!search" i18n>No server found.</ng-container> | 52 | <ng-container *ngIf="!search" i18n>No server found.</ng-container> |
53 | </div> | 53 | </div> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.scss b/client/src/app/shared/blocklist/server-blocklist.component.scss index c1f66116b..9ddb76850 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.scss +++ b/client/src/app/shared/blocklist/server-blocklist.component.scss | |||
@@ -15,6 +15,15 @@ a { | |||
15 | } | 15 | } |
16 | } | 16 | } |
17 | 17 | ||
18 | .caption { | ||
19 | justify-content: flex-end; | ||
20 | |||
21 | input { | ||
22 | @include peertube-input-text(250px); | ||
23 | flex-grow: 1; | ||
24 | } | ||
25 | } | ||
26 | |||
18 | .unblock-button { | 27 | .unblock-button { |
19 | @include peertube-button; | 28 | @include peertube-button; |
20 | @include grey-button; | 29 | @include grey-button; |
diff --git a/client/src/app/shared/blocklist/server-blocklist.component.ts b/client/src/app/shared/blocklist/server-blocklist.component.ts new file mode 100644 index 000000000..f2b36badc --- /dev/null +++ b/client/src/app/shared/blocklist/server-blocklist.component.ts | |||
@@ -0,0 +1,101 @@ | |||
1 | import { OnInit, ViewChild } from '@angular/core' | ||
2 | import { Notifier } from '@app/core' | ||
3 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
4 | import { RestPagination, RestTable } from '@app/shared/rest' | ||
5 | import { SortMeta } from 'primeng/api' | ||
6 | import { BlocklistService, BlocklistComponentType } from './blocklist.service' | ||
7 | import { ServerBlock } from '../../../../../shared/models/blocklist/server-block.model' | ||
8 | import { BatchDomainsModalComponent } from '@app/+admin/config/shared/batch-domains-modal.component' | ||
9 | |||
10 | export class GenericServerBlocklistComponent extends RestTable implements OnInit { | ||
11 | @ViewChild('batchDomainsModal') batchDomainsModal: BatchDomainsModalComponent | ||
12 | |||
13 | // @ts-ignore: "Abstract methods can only appear within an abstract class" | ||
14 | public abstract mode: BlocklistComponentType | ||
15 | |||
16 | blockedServers: ServerBlock[] = [] | ||
17 | totalRecords = 0 | ||
18 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
19 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
20 | |||
21 | constructor ( | ||
22 | protected notifier: Notifier, | ||
23 | protected blocklistService: BlocklistService, | ||
24 | protected i18n: I18n | ||
25 | ) { | ||
26 | super() | ||
27 | } | ||
28 | |||
29 | ngOnInit () { | ||
30 | this.initialize() | ||
31 | } | ||
32 | |||
33 | // @ts-ignore: "Abstract methods can only appear within an abstract class" | ||
34 | public abstract getIdentifier (): string | ||
35 | |||
36 | unblockServer (serverBlock: ServerBlock) { | ||
37 | const operation = (host: string) => this.mode === BlocklistComponentType.Account | ||
38 | ? this.blocklistService.unblockServerByUser(host) | ||
39 | : this.blocklistService.unblockServerByInstance(host) | ||
40 | const host = serverBlock.blockedServer.host | ||
41 | |||
42 | operation(host).subscribe( | ||
43 | () => { | ||
44 | this.notifier.success( | ||
45 | this.mode === BlocklistComponentType.Account | ||
46 | ? this.i18n('Instance {{host}} unmuted.', { host }) | ||
47 | : this.i18n('Instance {{host}} unmuted by your instance.', { host }) | ||
48 | ) | ||
49 | |||
50 | this.loadData() | ||
51 | } | ||
52 | ) | ||
53 | } | ||
54 | |||
55 | addServersToBlock () { | ||
56 | this.batchDomainsModal.openModal() | ||
57 | } | ||
58 | |||
59 | onDomainsToBlock (domains: string[]) { | ||
60 | const operation = (domain: string) => this.mode === BlocklistComponentType.Account | ||
61 | ? this.blocklistService.blockServerByUser(domain) | ||
62 | : this.blocklistService.blockServerByInstance(domain) | ||
63 | |||
64 | domains.forEach(domain => { | ||
65 | operation(domain).subscribe( | ||
66 | () => { | ||
67 | this.notifier.success( | ||
68 | this.mode === BlocklistComponentType.Account | ||
69 | ? this.i18n('Instance {{domain}} muted.', { domain }) | ||
70 | : this.i18n('Instance {{domain}} muted by your instance.', { domain }) | ||
71 | ) | ||
72 | |||
73 | this.loadData() | ||
74 | } | ||
75 | ) | ||
76 | }) | ||
77 | } | ||
78 | |||
79 | protected loadData () { | ||
80 | const operation = this.mode === BlocklistComponentType.Account | ||
81 | ? this.blocklistService.getUserServerBlocklist({ | ||
82 | pagination: this.pagination, | ||
83 | sort: this.sort, | ||
84 | search: this.search | ||
85 | }) | ||
86 | : this.blocklistService.getInstanceServerBlocklist({ | ||
87 | pagination: this.pagination, | ||
88 | sort: this.sort, | ||
89 | search: this.search | ||
90 | }) | ||
91 | |||
92 | return operation.subscribe( | ||
93 | resultList => { | ||
94 | this.blockedServers = resultList.data | ||
95 | this.totalRecords = resultList.total | ||
96 | }, | ||
97 | |||
98 | err => this.notifier.error(err.message) | ||
99 | ) | ||
100 | } | ||
101 | } | ||
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 2035097d7..98fab9e16 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -10,6 +10,7 @@ import { NgModule } from '@angular/core' | |||
10 | import { FormsModule, ReactiveFormsModule } from '@angular/forms' | 10 | import { FormsModule, ReactiveFormsModule } from '@angular/forms' |
11 | import { RouterModule } from '@angular/router' | 11 | import { RouterModule } from '@angular/router' |
12 | import { BatchDomainsValidatorsService } from '@app/+admin/config/shared/batch-domains-validators.service' | 12 | import { BatchDomainsValidatorsService } from '@app/+admin/config/shared/batch-domains-validators.service' |
13 | import { BatchDomainsModalComponent } from '@app/+admin/config/shared/batch-domains-modal.component' | ||
13 | import { MyAccountInterfaceSettingsComponent } from '@app/+my-account/my-account-settings/my-account-interface' | 14 | import { MyAccountInterfaceSettingsComponent } from '@app/+my-account/my-account-settings/my-account-interface' |
14 | import { MyAccountVideoSettingsComponent } from '@app/+my-account/my-account-settings/my-account-video-settings' | 15 | import { MyAccountVideoSettingsComponent } from '@app/+my-account/my-account-settings/my-account-video-settings' |
15 | import { ActorAvatarInfoComponent } from '@app/+my-account/shared/actor-avatar-info.component' | 16 | import { ActorAvatarInfoComponent } from '@app/+my-account/shared/actor-avatar-info.component' |
@@ -192,7 +193,8 @@ import { VideoService } from './video/video.service' | |||
192 | 193 | ||
193 | MyAccountVideoSettingsComponent, | 194 | MyAccountVideoSettingsComponent, |
194 | MyAccountInterfaceSettingsComponent, | 195 | MyAccountInterfaceSettingsComponent, |
195 | ActorAvatarInfoComponent | 196 | ActorAvatarInfoComponent, |
197 | BatchDomainsModalComponent | ||
196 | ], | 198 | ], |
197 | 199 | ||
198 | exports: [ | 200 | exports: [ |
@@ -274,7 +276,8 @@ import { VideoService } from './video/video.service' | |||
274 | 276 | ||
275 | MyAccountVideoSettingsComponent, | 277 | MyAccountVideoSettingsComponent, |
276 | MyAccountInterfaceSettingsComponent, | 278 | MyAccountInterfaceSettingsComponent, |
277 | ActorAvatarInfoComponent | 279 | ActorAvatarInfoComponent, |
280 | BatchDomainsModalComponent | ||
278 | ], | 281 | ], |
279 | 282 | ||
280 | providers: [ | 283 | providers: [ |
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss index aaa1c05bd..4f753e041 100644 --- a/client/src/sass/application.scss +++ b/client/src/sass/application.scss | |||
@@ -258,6 +258,8 @@ table { | |||
258 | 258 | ||
259 | .no-results { | 259 | .no-results { |
260 | height: 40vh; | 260 | height: 40vh; |
261 | max-height: 500px; | ||
262 | |||
261 | display: flex; | 263 | display: flex; |
262 | align-items: center; | 264 | align-items: center; |
263 | justify-content: center; | 265 | justify-content: center; |
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index 5971bb72a..eb80ea0e3 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss | |||
@@ -856,15 +856,6 @@ | |||
856 | } | 856 | } |
857 | } | 857 | } |
858 | 858 | ||
859 | @mixin empty-state { | ||
860 | min-height: 40vh; | ||
861 | max-height: 500px; | ||
862 | |||
863 | display: flex; | ||
864 | justify-content: center; | ||
865 | align-items: center; | ||
866 | } | ||
867 | |||
868 | @mixin admin-sub-header-responsive ($horizontal-margins) { | 859 | @mixin admin-sub-header-responsive ($horizontal-margins) { |
869 | flex-direction: column; | 860 | flex-direction: column; |
870 | 861 | ||