factorize account/server blocklists for users and instance (#2875)
This commit is contained in:
parent
7dfe352886
commit
228393302d
|
@ -27,7 +27,6 @@ import { SelectButtonModule } from 'primeng/selectbutton'
|
|||
import { PluginApiService } from '@app/+admin/plugins/shared/plugin-api.service'
|
||||
import { VideoRedundancyInformationComponent } from '@app/+admin/follows/video-redundancies-list/video-redundancy-information.component'
|
||||
import { ChartModule } from 'primeng/chart'
|
||||
import { BatchDomainsModalComponent } from './config/shared/batch-domains-modal.component'
|
||||
import { VideoAbuseDetailsComponent } from './moderation/video-abuse-list/video-abuse-details.component'
|
||||
|
||||
@NgModule({
|
||||
|
@ -76,9 +75,7 @@ import { VideoAbuseDetailsComponent } from './moderation/video-abuse-list/video-
|
|||
DebugComponent,
|
||||
|
||||
ConfigComponent,
|
||||
EditCustomConfigComponent,
|
||||
|
||||
BatchDomainsModalComponent
|
||||
EditCustomConfigComponent
|
||||
],
|
||||
|
||||
exports: [
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<ng-template pTemplate="emptymessage">
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div class="empty-table-message">
|
||||
<div class="no-results">
|
||||
<ng-container *ngIf="search" i18n>No follower found matching current filters.</ng-container>
|
||||
<ng-container *ngIf="!search" i18n>Your instance doesn't have any follower.</ng-container>
|
||||
</div>
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<ng-template pTemplate="emptymessage">
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div class="empty-table-message">
|
||||
<div class="no-results">
|
||||
<ng-container *ngIf="search" i18n>No host found matching current filters.</ng-container>
|
||||
<ng-container *ngIf="!search" i18n>Your instance is not following anyone.</ng-container>
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,3 @@
|
|||
flex-grow: 0;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.empty-table-message {
|
||||
@include empty-state;
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
<ng-template pTemplate="emptymessage">
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div class="empty-table-message">
|
||||
<div class="no-results">
|
||||
<ng-container *ngIf="isDisplayingRemoteVideos()" i18n>Your instance doesn't mirror any video.</ng-container>
|
||||
<ng-container *ngIf="!isDisplayingRemoteVideos()" i18n>Your instance has no mirrored videos.</ng-container>
|
||||
</div>
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
<ng-template pTemplate="emptymessage">
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div class="empty-table-message">
|
||||
<div class="no-results">
|
||||
<ng-container *ngIf="search" i18n>No account found matching current filters.</ng-container>
|
||||
<ng-container *ngIf="!search" i18n>No account found.</ng-container>
|
||||
</div>
|
||||
|
|
|
@ -1,70 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core'
|
||||
import { Notifier } from '@app/core'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { RestPagination, RestTable } from '@app/shared'
|
||||
import { SortMeta } from 'primeng/api'
|
||||
import { AccountBlock, BlocklistService } from '@app/shared/blocklist'
|
||||
import { Actor } from '@app/shared/actor/actor.model'
|
||||
import { Component } from '@angular/core'
|
||||
import { GenericAccountBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist'
|
||||
|
||||
@Component({
|
||||
selector: 'my-instance-account-blocklist',
|
||||
styleUrls: [ '../moderation.component.scss', './instance-account-blocklist.component.scss' ],
|
||||
templateUrl: './instance-account-blocklist.component.html'
|
||||
styleUrls: [ '../moderation.component.scss', '../../../shared/blocklist/account-blocklist.component.scss' ],
|
||||
templateUrl: '../../../shared/blocklist/account-blocklist.component.html'
|
||||
})
|
||||
export class InstanceAccountBlocklistComponent extends RestTable implements OnInit {
|
||||
blockedAccounts: AccountBlock[] = []
|
||||
totalRecords = 0
|
||||
sort: SortMeta = { field: 'createdAt', order: -1 }
|
||||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||
|
||||
constructor (
|
||||
private notifier: Notifier,
|
||||
private blocklistService: BlocklistService,
|
||||
private i18n: I18n
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.initialize()
|
||||
}
|
||||
export class InstanceAccountBlocklistComponent extends GenericAccountBlocklistComponent {
|
||||
mode = BlocklistComponentType.Instance
|
||||
|
||||
getIdentifier () {
|
||||
return 'InstanceAccountBlocklistComponent'
|
||||
}
|
||||
|
||||
switchToDefaultAvatar ($event: Event) {
|
||||
($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL()
|
||||
}
|
||||
|
||||
unblockAccount (accountBlock: AccountBlock) {
|
||||
const blockedAccount = accountBlock.blockedAccount
|
||||
|
||||
this.blocklistService.unblockAccountByInstance(blockedAccount)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(
|
||||
this.i18n('Account {{nameWithHost}} unmuted by your instance.', { nameWithHost: blockedAccount.nameWithHost })
|
||||
)
|
||||
|
||||
this.loadData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
protected loadData () {
|
||||
return this.blocklistService.getInstanceAccountBlocklist({
|
||||
pagination: this.pagination,
|
||||
sort: this.sort,
|
||||
search: this.search
|
||||
})
|
||||
.subscribe(
|
||||
resultList => {
|
||||
this.blockedAccounts = resultList.data
|
||||
this.totalRecords = resultList.total
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,84 +1,15 @@
|
|||
import { Component, OnInit, ViewChild } from '@angular/core'
|
||||
import { Notifier } from '@app/core'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { RestPagination, RestTable } from '@app/shared'
|
||||
import { SortMeta } from 'primeng/api'
|
||||
import { BlocklistService } from '@app/shared/blocklist'
|
||||
import { ServerBlock } from '../../../../../../shared'
|
||||
import { BatchDomainsModalComponent } from '@app/+admin/config/shared/batch-domains-modal.component'
|
||||
import { Component } from '@angular/core'
|
||||
import { GenericServerBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist'
|
||||
|
||||
@Component({
|
||||
selector: 'my-instance-server-blocklist',
|
||||
styleUrls: [ '../moderation.component.scss', './instance-server-blocklist.component.scss' ],
|
||||
templateUrl: './instance-server-blocklist.component.html'
|
||||
styleUrls: [ '../../../shared/blocklist/server-blocklist.component.scss' ],
|
||||
templateUrl: '../../../shared/blocklist/server-blocklist.component.html'
|
||||
})
|
||||
export class InstanceServerBlocklistComponent extends RestTable implements OnInit {
|
||||
@ViewChild('batchDomainsModal') batchDomainsModal: BatchDomainsModalComponent
|
||||
|
||||
blockedServers: ServerBlock[] = []
|
||||
totalRecords = 0
|
||||
sort: SortMeta = { field: 'createdAt', order: -1 }
|
||||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||
|
||||
constructor (
|
||||
private notifier: Notifier,
|
||||
private blocklistService: BlocklistService,
|
||||
private i18n: I18n
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.initialize()
|
||||
}
|
||||
export class InstanceServerBlocklistComponent extends GenericServerBlocklistComponent {
|
||||
mode = BlocklistComponentType.Instance
|
||||
|
||||
getIdentifier () {
|
||||
return 'InstanceServerBlocklistComponent'
|
||||
}
|
||||
|
||||
unblockServer (serverBlock: ServerBlock) {
|
||||
const host = serverBlock.blockedServer.host
|
||||
|
||||
this.blocklistService.unblockServerByInstance(host)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Instance {{host}} unmuted by your instance.', { host }))
|
||||
|
||||
this.loadData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
addServersToBlock () {
|
||||
this.batchDomainsModal.openModal()
|
||||
}
|
||||
|
||||
onDomainsToBlock (domains: string[]) {
|
||||
domains.forEach(domain => {
|
||||
this.blocklistService.blockServerByInstance(domain)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Instance {{domain}} muted by your instance.', { domain }))
|
||||
|
||||
this.loadData()
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
protected loadData () {
|
||||
return this.blocklistService.getInstanceServerBlocklist({
|
||||
pagination: this.pagination,
|
||||
sort: this.sort,
|
||||
search: this.search
|
||||
})
|
||||
.subscribe(
|
||||
resultList => {
|
||||
this.blockedServers = resultList.data
|
||||
this.totalRecords = resultList.total
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.empty-table-message {
|
||||
@include empty-state;
|
||||
}
|
||||
|
||||
.moderation-expanded {
|
||||
font-size: 90%;
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
<ng-template pTemplate="emptymessage">
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div class="empty-table-message">
|
||||
<div class="no-results">
|
||||
<ng-container *ngIf="search" i18n>No video abuses found matching current filters.</ng-container>
|
||||
<ng-container *ngIf="!search" i18n>No video abuses found.</ng-container>
|
||||
</div>
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
<ng-template pTemplate="emptymessage">
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div class="empty-table-message">
|
||||
<div class="no-results">
|
||||
<ng-container *ngIf="search" i18n>No blocked video found matching current filters.</ng-container>
|
||||
<ng-container *ngIf="!search" i18n>No blocked video found.</ng-container>
|
||||
</div>
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
<div class="admin-sub-header">
|
||||
<h1 i18n class="form-sub-title">Muted accounts</h1>
|
||||
</div>
|
||||
|
||||
<p-table
|
||||
[value]="blockedAccounts" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage"
|
||||
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
|
||||
>
|
||||
|
||||
<ng-template pTemplate="header">
|
||||
<tr>
|
||||
<th i18n>Account</th>
|
||||
<th i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
|
||||
<th></th> <!-- column for action buttons -->
|
||||
</tr>
|
||||
</ng-template>
|
||||
|
||||
<ng-template pTemplate="body" let-accountBlock>
|
||||
<tr>
|
||||
<td>{{ accountBlock.blockedAccount.nameWithHost }}</td>
|
||||
<td>{{ accountBlock.createdAt }}</td>
|
||||
<td class="action-cell">
|
||||
<button class="unblock-button" (click)="unblockAccount(accountBlock)" i18n>Unmute</button>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</p-table>
|
|
@ -1,7 +0,0 @@
|
|||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
.unblock-button {
|
||||
@include peertube-button;
|
||||
@include grey-button;
|
||||
}
|
|
@ -1,59 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core'
|
||||
import { Notifier } from '@app/core'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { RestPagination, RestTable } from '@app/shared'
|
||||
import { SortMeta } from 'primeng/api'
|
||||
import { AccountBlock, BlocklistService } from '@app/shared/blocklist'
|
||||
import { Component } from '@angular/core'
|
||||
import { GenericAccountBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist'
|
||||
|
||||
@Component({
|
||||
selector: 'my-account-blocklist',
|
||||
styleUrls: [ './my-account-blocklist.component.scss' ],
|
||||
templateUrl: './my-account-blocklist.component.html'
|
||||
styleUrls: [ '../../shared/blocklist/account-blocklist.component.scss' ],
|
||||
templateUrl: '../../shared/blocklist/account-blocklist.component.html'
|
||||
})
|
||||
export class MyAccountBlocklistComponent extends RestTable implements OnInit {
|
||||
blockedAccounts: AccountBlock[] = []
|
||||
totalRecords = 0
|
||||
sort: SortMeta = { field: 'createdAt', order: -1 }
|
||||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||
|
||||
constructor (
|
||||
private notifier: Notifier,
|
||||
private blocklistService: BlocklistService,
|
||||
private i18n: I18n
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.initialize()
|
||||
}
|
||||
export class MyAccountBlocklistComponent extends GenericAccountBlocklistComponent {
|
||||
mode = BlocklistComponentType.Account
|
||||
|
||||
getIdentifier () {
|
||||
return 'MyAccountBlocklistComponent'
|
||||
}
|
||||
|
||||
unblockAccount (accountBlock: AccountBlock) {
|
||||
const blockedAccount = accountBlock.blockedAccount
|
||||
|
||||
this.blocklistService.unblockAccountByUser(blockedAccount)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Account {{nameWithHost}} unmuted.', { nameWithHost: blockedAccount.nameWithHost }))
|
||||
|
||||
this.loadData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
protected loadData () {
|
||||
return this.blocklistService.getUserAccountBlocklist(this.pagination, this.sort)
|
||||
.subscribe(
|
||||
resultList => {
|
||||
this.blockedAccounts = resultList.data
|
||||
this.totalRecords = resultList.total
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
<div class="admin-sub-header">
|
||||
<h1 i18n class="form-sub-title">Muted instances</h1>
|
||||
</div>
|
||||
|
||||
<p-table
|
||||
[value]="blockedServers" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage"
|
||||
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
|
||||
>
|
||||
|
||||
<ng-template pTemplate="header">
|
||||
<tr>
|
||||
<th i18n>Instance</th>
|
||||
<th i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
|
||||
<th></th> <!-- column for action buttons -->
|
||||
</tr>
|
||||
</ng-template>
|
||||
|
||||
<ng-template pTemplate="body" let-serverBlock>
|
||||
<tr>
|
||||
<td>{{ serverBlock.blockedServer.host }}</td>
|
||||
<td>{{ serverBlock.createdAt }}</td>
|
||||
<td class="action-cell">
|
||||
<button class="unblock-button" (click)="unblockServer(serverBlock)" i18n>Unmute</button>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</p-table>
|
|
@ -1,7 +0,0 @@
|
|||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
.unblock-button {
|
||||
@include peertube-button;
|
||||
@include grey-button;
|
||||
}
|
|
@ -1,60 +1,15 @@
|
|||
import { Component, OnInit } from '@angular/core'
|
||||
import { Notifier } from '@app/core'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { RestPagination, RestTable } from '@app/shared'
|
||||
import { SortMeta } from 'primeng/api'
|
||||
import { ServerBlock } from '../../../../../shared'
|
||||
import { BlocklistService } from '@app/shared/blocklist'
|
||||
import { Component } from '@angular/core'
|
||||
import { GenericServerBlocklistComponent, BlocklistComponentType } from '@app/shared/blocklist'
|
||||
|
||||
@Component({
|
||||
selector: 'my-account-server-blocklist',
|
||||
styleUrls: [ './my-account-server-blocklist.component.scss' ],
|
||||
templateUrl: './my-account-server-blocklist.component.html'
|
||||
styleUrls: [ '../../+admin/moderation/moderation.component.scss', '../../shared/blocklist/server-blocklist.component.scss' ],
|
||||
templateUrl: '../../shared/blocklist/server-blocklist.component.html'
|
||||
})
|
||||
export class MyAccountServerBlocklistComponent extends RestTable implements OnInit {
|
||||
blockedServers: ServerBlock[] = []
|
||||
totalRecords = 0
|
||||
sort: SortMeta = { field: 'createdAt', order: -1 }
|
||||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||
|
||||
constructor (
|
||||
private notifier: Notifier,
|
||||
private blocklistService: BlocklistService,
|
||||
private i18n: I18n
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.initialize()
|
||||
}
|
||||
export class MyAccountServerBlocklistComponent extends GenericServerBlocklistComponent {
|
||||
mode = BlocklistComponentType.Account
|
||||
|
||||
getIdentifier () {
|
||||
return 'MyAccountServerBlocklistComponent'
|
||||
}
|
||||
|
||||
unblockServer (serverBlock: ServerBlock) {
|
||||
const host = serverBlock.blockedServer.host
|
||||
|
||||
this.blocklistService.unblockServerByUser(host)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Instance {{host}} unmuted.', { host }))
|
||||
|
||||
this.loadData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
protected loadData () {
|
||||
return this.blocklistService.getUserServerBlocklist(this.pagination, this.sort)
|
||||
.subscribe(
|
||||
resultList => {
|
||||
this.blockedServers = resultList.data
|
||||
this.totalRecords = resultList.total
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ const myAccountRoutes: Routes = [
|
|||
component: MyAccountServerBlocklistComponent,
|
||||
data: {
|
||||
meta: {
|
||||
title: 'Muted instances'
|
||||
title: 'Muted servers'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -72,7 +72,7 @@ export class MyAccountComponent implements OnInit {
|
|||
iconName: 'user'
|
||||
},
|
||||
{
|
||||
label: this.i18n('Muted instances'),
|
||||
label: this.i18n('Muted servers'),
|
||||
routerLink: '/my-account/blocklist/servers',
|
||||
iconName: 'server'
|
||||
},
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
<p-table
|
||||
[value]="blockedAccounts" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
|
||||
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" (onPage)="onPage($event)"
|
||||
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
|
||||
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} muted accounts"
|
||||
>
|
||||
<ng-template pTemplate="caption">
|
||||
<div class="caption">
|
||||
<div class="ml-auto has-feedback has-clear">
|
||||
<input
|
||||
type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..."
|
||||
(keyup)="onSearch($event)"
|
||||
>
|
||||
<a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a>
|
||||
<span class="sr-only" i18n>Clear filters</span>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template pTemplate="header">
|
||||
<tr>
|
||||
<th style="width: 100%;" i18n>Account</th>
|
||||
<th style="width: 150px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th>
|
||||
<th style="width: 150px;"></th> <!-- column for action buttons -->
|
||||
</tr>
|
||||
</ng-template>
|
||||
|
||||
<ng-template pTemplate="body" let-accountBlock>
|
||||
<tr>
|
||||
<td>
|
||||
<a [href]="accountBlock.blockedAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer">
|
||||
<div class="chip two-lines">
|
||||
<img
|
||||
class="avatar"
|
||||
[src]="accountBlock.blockedAccount.avatar?.path"
|
||||
(error)="switchToDefaultAvatar($event)"
|
||||
alt="Avatar"
|
||||
>
|
||||
<div>
|
||||
{{ accountBlock.blockedAccount.displayName }}
|
||||
<span class="text-muted">{{ accountBlock.blockedAccount.nameWithHost }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td>{{ accountBlock.createdAt | date: 'short' }}</td>
|
||||
<td class="action-cell">
|
||||
<button class="unblock-button" (click)="unblockAccount(accountBlock)" i18n>Unmute</button>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
|
||||
<ng-template pTemplate="emptymessage">
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div class="no-results">
|
||||
<ng-container *ngIf="search" i18n>No account found matching current filters.</ng-container>
|
||||
<ng-container *ngIf="!search" i18n>No account found.</ng-container>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
</p-table>
|
|
@ -0,0 +1,16 @@
|
|||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
.caption {
|
||||
justify-content: flex-end;
|
||||
|
||||
input {
|
||||
@include peertube-input-text(250px);
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.unblock-button {
|
||||
@include peertube-button;
|
||||
@include grey-button;
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
import { OnInit } from '@angular/core'
|
||||
import { Notifier } from '@app/core'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { RestPagination, RestTable } from '@app/shared/rest'
|
||||
import { SortMeta } from 'primeng/api'
|
||||
import { AccountBlock } from './account-block.model'
|
||||
import { BlocklistService, BlocklistComponentType } from './blocklist.service'
|
||||
import { Actor } from '@app/shared/actor/actor.model'
|
||||
|
||||
export class GenericAccountBlocklistComponent extends RestTable implements OnInit {
|
||||
// @ts-ignore: "Abstract methods can only appear within an abstract class"
|
||||
abstract mode: BlocklistComponentType
|
||||
|
||||
blockedAccounts: AccountBlock[] = []
|
||||
totalRecords = 0
|
||||
sort: SortMeta = { field: 'createdAt', order: -1 }
|
||||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||
|
||||
constructor (
|
||||
private notifier: Notifier,
|
||||
private blocklistService: BlocklistService,
|
||||
private i18n: I18n
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
// @ts-ignore: "Abstract methods can only appear within an abstract class"
|
||||
abstract getIdentifier (): string
|
||||
|
||||
ngOnInit () {
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
switchToDefaultAvatar ($event: Event) {
|
||||
($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL()
|
||||
}
|
||||
|
||||
unblockAccount (accountBlock: AccountBlock) {
|
||||
const blockedAccount = accountBlock.blockedAccount
|
||||
const operation = this.mode === BlocklistComponentType.Account
|
||||
? this.blocklistService.unblockAccountByUser(blockedAccount)
|
||||
: this.blocklistService.unblockAccountByInstance(blockedAccount)
|
||||
|
||||
operation.subscribe(
|
||||
() => {
|
||||
this.notifier.success(
|
||||
this.mode === BlocklistComponentType.Account
|
||||
? this.i18n('Account {{nameWithHost}} unmuted.', { nameWithHost: blockedAccount.nameWithHost })
|
||||
: this.i18n('Account {{nameWithHost}} unmuted by your instance.', { nameWithHost: blockedAccount.nameWithHost })
|
||||
)
|
||||
|
||||
this.loadData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
protected loadData () {
|
||||
const operation = this.mode === BlocklistComponentType.Account
|
||||
? this.blocklistService.getUserAccountBlocklist({
|
||||
pagination: this.pagination,
|
||||
sort: this.sort,
|
||||
search: this.search
|
||||
})
|
||||
: this.blocklistService.getInstanceAccountBlocklist({
|
||||
pagination: this.pagination,
|
||||
sort: this.sort,
|
||||
search: this.search
|
||||
})
|
||||
|
||||
return operation.subscribe(
|
||||
resultList => {
|
||||
this.blockedAccounts = resultList.data
|
||||
this.totalRecords = resultList.total
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -8,6 +8,8 @@ import { AccountBlock as AccountBlockServer, ResultList, ServerBlock } from '../
|
|||
import { Account } from '@app/shared/account/account.model'
|
||||
import { AccountBlock } from '@app/shared/blocklist/account-block.model'
|
||||
|
||||
export enum BlocklistComponentType { Account, Instance }
|
||||
|
||||
@Injectable()
|
||||
export class BlocklistService {
|
||||
static BASE_USER_BLOCKLIST_URL = environment.apiUrl + '/api/v1/users/me/blocklist'
|
||||
|
@ -21,10 +23,14 @@ export class BlocklistService {
|
|||
|
||||
/*********************** User -> Account blocklist ***********************/
|
||||
|
||||
getUserAccountBlocklist (pagination: RestPagination, sort: SortMeta) {
|
||||
getUserAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) {
|
||||
const { pagination, sort, search } = options
|
||||
|
||||
let params = new HttpParams()
|
||||
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||
|
||||
if (search) params = params.append('search', search)
|
||||
|
||||
return this.authHttp.get<ResultList<AccountBlock>>(BlocklistService.BASE_USER_BLOCKLIST_URL + '/accounts', { params })
|
||||
.pipe(
|
||||
map(res => this.restExtractor.convertResultListDateToHuman(res)),
|
||||
|
@ -49,10 +55,14 @@ export class BlocklistService {
|
|||
|
||||
/*********************** User -> Server blocklist ***********************/
|
||||
|
||||
getUserServerBlocklist (pagination: RestPagination, sort: SortMeta) {
|
||||
getUserServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) {
|
||||
const { pagination, sort, search } = options
|
||||
|
||||
let params = new HttpParams()
|
||||
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||
|
||||
if (search) params = params.append('search', search)
|
||||
|
||||
return this.authHttp.get<ResultList<ServerBlock>>(BlocklistService.BASE_USER_BLOCKLIST_URL + '/servers', { params })
|
||||
.pipe(
|
||||
map(res => this.restExtractor.convertResultListDateToHuman(res)),
|
||||
|
@ -76,7 +86,7 @@ export class BlocklistService {
|
|||
|
||||
/*********************** Instance -> Account blocklist ***********************/
|
||||
|
||||
getInstanceAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search: string }) {
|
||||
getInstanceAccountBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) {
|
||||
const { pagination, sort, search } = options
|
||||
|
||||
let params = new HttpParams()
|
||||
|
@ -108,7 +118,7 @@ export class BlocklistService {
|
|||
|
||||
/*********************** Instance -> Server blocklist ***********************/
|
||||
|
||||
getInstanceServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search: string }) {
|
||||
getInstanceServerBlocklist (options: { pagination: RestPagination, sort: SortMeta, search?: string }) {
|
||||
const { pagination, sort, search } = options
|
||||
|
||||
let params = new HttpParams()
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
export * from './blocklist.service'
|
||||
export * from './account-block.model'
|
||||
export * from './server-blocklist.component'
|
||||
export * from './account-blocklist.component'
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
<ng-template pTemplate="emptymessage">
|
||||
<tr>
|
||||
<td colspan="6">
|
||||
<div class="empty-table-message">
|
||||
<div class="no-results">
|
||||
<ng-container *ngIf="search" i18n>No server found matching current filters.</ng-container>
|
||||
<ng-container *ngIf="!search" i18n>No server found.</ng-container>
|
||||
</div>
|
|
@ -15,6 +15,15 @@ a {
|
|||
}
|
||||
}
|
||||
|
||||
.caption {
|
||||
justify-content: flex-end;
|
||||
|
||||
input {
|
||||
@include peertube-input-text(250px);
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.unblock-button {
|
||||
@include peertube-button;
|
||||
@include grey-button;
|
|
@ -0,0 +1,101 @@
|
|||
import { OnInit, ViewChild } from '@angular/core'
|
||||
import { Notifier } from '@app/core'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { RestPagination, RestTable } from '@app/shared/rest'
|
||||
import { SortMeta } from 'primeng/api'
|
||||
import { BlocklistService, BlocklistComponentType } from './blocklist.service'
|
||||
import { ServerBlock } from '../../../../../shared/models/blocklist/server-block.model'
|
||||
import { BatchDomainsModalComponent } from '@app/+admin/config/shared/batch-domains-modal.component'
|
||||
|
||||
export class GenericServerBlocklistComponent extends RestTable implements OnInit {
|
||||
@ViewChild('batchDomainsModal') batchDomainsModal: BatchDomainsModalComponent
|
||||
|
||||
// @ts-ignore: "Abstract methods can only appear within an abstract class"
|
||||
public abstract mode: BlocklistComponentType
|
||||
|
||||
blockedServers: ServerBlock[] = []
|
||||
totalRecords = 0
|
||||
sort: SortMeta = { field: 'createdAt', order: -1 }
|
||||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||
|
||||
constructor (
|
||||
protected notifier: Notifier,
|
||||
protected blocklistService: BlocklistService,
|
||||
protected i18n: I18n
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
// @ts-ignore: "Abstract methods can only appear within an abstract class"
|
||||
public abstract getIdentifier (): string
|
||||
|
||||
unblockServer (serverBlock: ServerBlock) {
|
||||
const operation = (host: string) => this.mode === BlocklistComponentType.Account
|
||||
? this.blocklistService.unblockServerByUser(host)
|
||||
: this.blocklistService.unblockServerByInstance(host)
|
||||
const host = serverBlock.blockedServer.host
|
||||
|
||||
operation(host).subscribe(
|
||||
() => {
|
||||
this.notifier.success(
|
||||
this.mode === BlocklistComponentType.Account
|
||||
? this.i18n('Instance {{host}} unmuted.', { host })
|
||||
: this.i18n('Instance {{host}} unmuted by your instance.', { host })
|
||||
)
|
||||
|
||||
this.loadData()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
addServersToBlock () {
|
||||
this.batchDomainsModal.openModal()
|
||||
}
|
||||
|
||||
onDomainsToBlock (domains: string[]) {
|
||||
const operation = (domain: string) => this.mode === BlocklistComponentType.Account
|
||||
? this.blocklistService.blockServerByUser(domain)
|
||||
: this.blocklistService.blockServerByInstance(domain)
|
||||
|
||||
domains.forEach(domain => {
|
||||
operation(domain).subscribe(
|
||||
() => {
|
||||
this.notifier.success(
|
||||
this.mode === BlocklistComponentType.Account
|
||||
? this.i18n('Instance {{domain}} muted.', { domain })
|
||||
: this.i18n('Instance {{domain}} muted by your instance.', { domain })
|
||||
)
|
||||
|
||||
this.loadData()
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
protected loadData () {
|
||||
const operation = this.mode === BlocklistComponentType.Account
|
||||
? this.blocklistService.getUserServerBlocklist({
|
||||
pagination: this.pagination,
|
||||
sort: this.sort,
|
||||
search: this.search
|
||||
})
|
||||
: this.blocklistService.getInstanceServerBlocklist({
|
||||
pagination: this.pagination,
|
||||
sort: this.sort,
|
||||
search: this.search
|
||||
})
|
||||
|
||||
return operation.subscribe(
|
||||
resultList => {
|
||||
this.blockedServers = resultList.data
|
||||
this.totalRecords = resultList.total
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import { NgModule } from '@angular/core'
|
|||
import { FormsModule, ReactiveFormsModule } from '@angular/forms'
|
||||
import { RouterModule } from '@angular/router'
|
||||
import { BatchDomainsValidatorsService } from '@app/+admin/config/shared/batch-domains-validators.service'
|
||||
import { BatchDomainsModalComponent } from '@app/+admin/config/shared/batch-domains-modal.component'
|
||||
import { MyAccountInterfaceSettingsComponent } from '@app/+my-account/my-account-settings/my-account-interface'
|
||||
import { MyAccountVideoSettingsComponent } from '@app/+my-account/my-account-settings/my-account-video-settings'
|
||||
import { ActorAvatarInfoComponent } from '@app/+my-account/shared/actor-avatar-info.component'
|
||||
|
@ -192,7 +193,8 @@ import { VideoService } from './video/video.service'
|
|||
|
||||
MyAccountVideoSettingsComponent,
|
||||
MyAccountInterfaceSettingsComponent,
|
||||
ActorAvatarInfoComponent
|
||||
ActorAvatarInfoComponent,
|
||||
BatchDomainsModalComponent
|
||||
],
|
||||
|
||||
exports: [
|
||||
|
@ -274,7 +276,8 @@ import { VideoService } from './video/video.service'
|
|||
|
||||
MyAccountVideoSettingsComponent,
|
||||
MyAccountInterfaceSettingsComponent,
|
||||
ActorAvatarInfoComponent
|
||||
ActorAvatarInfoComponent,
|
||||
BatchDomainsModalComponent
|
||||
],
|
||||
|
||||
providers: [
|
||||
|
|
|
@ -258,6 +258,8 @@ table {
|
|||
|
||||
.no-results {
|
||||
height: 40vh;
|
||||
max-height: 500px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
|
|
@ -856,15 +856,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
@mixin empty-state {
|
||||
min-height: 40vh;
|
||||
max-height: 500px;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@mixin admin-sub-header-responsive ($horizontal-margins) {
|
||||
flex-direction: column;
|
||||
|
||||
|
|
Loading…
Reference in New Issue