Add ability to mute a user/instance by server in client
This commit is contained in:
parent
b44164bb56
commit
65b21c961c
|
@ -10,8 +10,10 @@
|
||||||
<div class="actor-name">{{ account.nameWithHost }}</div>
|
<div class="actor-name">{{ account.nameWithHost }}</div>
|
||||||
|
|
||||||
<span *ngIf="user?.blocked" [ngbTooltip]="user.blockedReason" class="badge badge-danger" i18n>Banned</span>
|
<span *ngIf="user?.blocked" [ngbTooltip]="user.blockedReason" class="badge badge-danger" i18n>Banned</span>
|
||||||
<span *ngIf="account.muted" class="badge badge-danger" i18n>Muted</span>
|
<span *ngIf="account.mutedByUser" class="badge badge-danger" i18n>Muted</span>
|
||||||
<span *ngIf="account.mutedServer" class="badge badge-danger" i18n>Instance muted</span>
|
<span *ngIf="account.mutedServerByUser" class="badge badge-danger" i18n>Muted by your instance</span>
|
||||||
|
<span *ngIf="account.mutedByInstance" class="badge badge-danger" i18n>Instance muted</span>
|
||||||
|
<span *ngIf="account.mutedServerByInstance" class="badge badge-danger" i18n>Instance muted by your instance</span>
|
||||||
|
|
||||||
<my-user-moderation-dropdown
|
<my-user-moderation-dropdown
|
||||||
buttonSize="small" [account]="account" [user]="user"
|
buttonSize="small" [account]="account" [user]="user"
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { ModerationCommentModalComponent, VideoAbuseListComponent, VideoBlacklis
|
||||||
import { ModerationComponent } from '@app/+admin/moderation/moderation.component'
|
import { ModerationComponent } from '@app/+admin/moderation/moderation.component'
|
||||||
import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component'
|
import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component'
|
||||||
import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service'
|
import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service'
|
||||||
|
import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist'
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -41,6 +42,8 @@ import { RedundancyService } from '@app/+admin/follows/shared/redundancy.service
|
||||||
VideoBlacklistListComponent,
|
VideoBlacklistListComponent,
|
||||||
VideoAbuseListComponent,
|
VideoAbuseListComponent,
|
||||||
ModerationCommentModalComponent,
|
ModerationCommentModalComponent,
|
||||||
|
InstanceServerBlocklistComponent,
|
||||||
|
InstanceAccountBlocklistComponent,
|
||||||
|
|
||||||
JobsComponent,
|
JobsComponent,
|
||||||
JobsListComponent,
|
JobsListComponent,
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './instance-account-blocklist.component'
|
||||||
|
export * from './instance-server-blocklist.component'
|
|
@ -0,0 +1,22 @@
|
||||||
|
<p-table
|
||||||
|
[value]="blockedAccounts" [lazy]="true" [paginator]="true" [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>
|
||||||
|
</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>
|
|
@ -0,0 +1,7 @@
|
||||||
|
@import '_variables';
|
||||||
|
@import '_mixins';
|
||||||
|
|
||||||
|
.unblock-button {
|
||||||
|
@include peertube-button;
|
||||||
|
@include grey-button;
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { Component, OnInit } from '@angular/core'
|
||||||
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
|
import { RestPagination, RestTable } from '@app/shared'
|
||||||
|
import { SortMeta } from 'primeng/components/common/sortmeta'
|
||||||
|
import { BlocklistService, AccountBlock } from '@app/shared/blocklist'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-instance-account-blocklist',
|
||||||
|
styleUrls: [ './instance-account-blocklist.component.scss' ],
|
||||||
|
templateUrl: './instance-account-blocklist.component.html'
|
||||||
|
})
|
||||||
|
export class InstanceAccountBlocklistComponent extends RestTable implements OnInit {
|
||||||
|
blockedAccounts: AccountBlock[] = []
|
||||||
|
totalRecords = 0
|
||||||
|
rowsPerPage = 10
|
||||||
|
sort: SortMeta = { field: 'createdAt', order: -1 }
|
||||||
|
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private notificationsService: NotificationsService,
|
||||||
|
private blocklistService: BlocklistService,
|
||||||
|
private i18n: I18n
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
unblockAccount (accountBlock: AccountBlock) {
|
||||||
|
const blockedAccount = accountBlock.blockedAccount
|
||||||
|
|
||||||
|
this.blocklistService.unblockAccountByInstance(blockedAccount)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.i18n('Success'),
|
||||||
|
this.i18n('Account {{nameWithHost}} unmuted by your instance.', { nameWithHost: blockedAccount.nameWithHost })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.loadData()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected loadData () {
|
||||||
|
return this.blocklistService.getInstanceAccountBlocklist(this.pagination, this.sort)
|
||||||
|
.subscribe(
|
||||||
|
resultList => {
|
||||||
|
this.blockedAccounts = resultList.data
|
||||||
|
this.totalRecords = resultList.total
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
<p-table
|
||||||
|
[value]="blockedAccounts" [lazy]="true" [paginator]="true" [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>
|
||||||
|
</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>
|
|
@ -0,0 +1,7 @@
|
||||||
|
@import '_variables';
|
||||||
|
@import '_mixins';
|
||||||
|
|
||||||
|
.unblock-button {
|
||||||
|
@include peertube-button;
|
||||||
|
@include grey-button;
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { Component, OnInit } from '@angular/core'
|
||||||
|
import { NotificationsService } from 'angular2-notifications'
|
||||||
|
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||||
|
import { RestPagination, RestTable } from '@app/shared'
|
||||||
|
import { SortMeta } from 'primeng/components/common/sortmeta'
|
||||||
|
import { BlocklistService } from '@app/shared/blocklist'
|
||||||
|
import { ServerBlock } from '../../../../../../shared'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-instance-server-blocklist',
|
||||||
|
styleUrls: [ './instance-server-blocklist.component.scss' ],
|
||||||
|
templateUrl: './instance-server-blocklist.component.html'
|
||||||
|
})
|
||||||
|
export class InstanceServerBlocklistComponent extends RestTable implements OnInit {
|
||||||
|
blockedAccounts: ServerBlock[] = []
|
||||||
|
totalRecords = 0
|
||||||
|
rowsPerPage = 10
|
||||||
|
sort: SortMeta = { field: 'createdAt', order: -1 }
|
||||||
|
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
private notificationsService: NotificationsService,
|
||||||
|
private blocklistService: BlocklistService,
|
||||||
|
private i18n: I18n
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit () {
|
||||||
|
this.initialize()
|
||||||
|
}
|
||||||
|
|
||||||
|
unblockServer (serverBlock: ServerBlock) {
|
||||||
|
const host = serverBlock.blockedServer.host
|
||||||
|
|
||||||
|
this.blocklistService.unblockServerByInstance(host)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.i18n('Success'),
|
||||||
|
this.i18n('Instance {{host}} unmuted by your instance.', { host })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.loadData()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected loadData () {
|
||||||
|
return this.blocklistService.getInstanceServerBlocklist(this.pagination, this.sort)
|
||||||
|
.subscribe(
|
||||||
|
resultList => {
|
||||||
|
this.blockedAccounts = resultList.data
|
||||||
|
this.totalRecords = resultList.total
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,10 @@
|
||||||
<a *ngIf="hasVideoAbusesRight()" i18n routerLink="video-abuses/list" routerLinkActive="active">Video abuses</a>
|
<a *ngIf="hasVideoAbusesRight()" i18n routerLink="video-abuses/list" routerLinkActive="active">Video abuses</a>
|
||||||
|
|
||||||
<a *ngIf="hasVideoBlacklistRight()" i18n routerLink="video-blacklist/list" routerLinkActive="active">Blacklisted videos</a>
|
<a *ngIf="hasVideoBlacklistRight()" i18n routerLink="video-blacklist/list" routerLinkActive="active">Blacklisted videos</a>
|
||||||
|
|
||||||
|
<a *ngIf="hasAccountsBlacklistRight()" i18n routerLink="blocklist/accounts" routerLinkActive="active">Muted accounts</a>
|
||||||
|
|
||||||
|
<a *ngIf="hasServersBlacklistRight()" i18n routerLink="blocklist/servers" routerLinkActive="active">Muted servers</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -16,4 +16,12 @@ export class ModerationComponent {
|
||||||
hasVideoBlacklistRight () {
|
hasVideoBlacklistRight () {
|
||||||
return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
|
return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasAccountsBlacklistRight () {
|
||||||
|
return this.auth.getUser().hasRight(UserRight.MANAGE_ACCOUNTS_BLOCKLIST)
|
||||||
|
}
|
||||||
|
|
||||||
|
hasServersBlacklistRight () {
|
||||||
|
return this.auth.getUser().hasRight(UserRight.MANAGE_SERVERS_BLOCKLIST)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { UserRightGuard } from '@app/core'
|
||||||
import { VideoAbuseListComponent } from '@app/+admin/moderation/video-abuse-list'
|
import { VideoAbuseListComponent } from '@app/+admin/moderation/video-abuse-list'
|
||||||
import { VideoBlacklistListComponent } from '@app/+admin/moderation/video-blacklist-list'
|
import { VideoBlacklistListComponent } from '@app/+admin/moderation/video-blacklist-list'
|
||||||
import { ModerationComponent } from '@app/+admin/moderation/moderation.component'
|
import { ModerationComponent } from '@app/+admin/moderation/moderation.component'
|
||||||
|
import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist'
|
||||||
|
|
||||||
export const ModerationRoutes: Routes = [
|
export const ModerationRoutes: Routes = [
|
||||||
{
|
{
|
||||||
|
@ -46,6 +47,28 @@ export const ModerationRoutes: Routes = [
|
||||||
title: 'Blacklisted videos'
|
title: 'Blacklisted videos'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'blocklist/accounts',
|
||||||
|
component: InstanceAccountBlocklistComponent,
|
||||||
|
canActivate: [ UserRightGuard ],
|
||||||
|
data: {
|
||||||
|
userRight: UserRight.MANAGE_ACCOUNTS_BLOCKLIST,
|
||||||
|
meta: {
|
||||||
|
title: 'Muted accounts'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'blocklist/servers',
|
||||||
|
component: InstanceServerBlocklistComponent,
|
||||||
|
canActivate: [ UserRightGuard ],
|
||||||
|
data: {
|
||||||
|
userRight: UserRight.MANAGE_SERVER_REDUNDANCY,
|
||||||
|
meta: {
|
||||||
|
title: 'Muted instances'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,10 @@ export class Account extends Actor implements ServerAccount {
|
||||||
displayName: string
|
displayName: string
|
||||||
description: string
|
description: string
|
||||||
nameWithHost: string
|
nameWithHost: string
|
||||||
muted: boolean
|
mutedByUser: boolean
|
||||||
mutedServer: boolean
|
mutedByInstance: boolean
|
||||||
|
mutedServerByUser: boolean
|
||||||
|
mutedServerByInstance: boolean
|
||||||
|
|
||||||
userId?: number
|
userId?: number
|
||||||
|
|
||||||
|
@ -18,7 +20,9 @@ export class Account extends Actor implements ServerAccount {
|
||||||
this.userId = hash.userId
|
this.userId = hash.userId
|
||||||
this.nameWithHost = Actor.CREATE_BY_STRING(this.name, this.host)
|
this.nameWithHost = Actor.CREATE_BY_STRING(this.name, this.host)
|
||||||
|
|
||||||
this.muted = false
|
this.mutedByUser = false
|
||||||
this.mutedServer = false
|
this.mutedByInstance = false
|
||||||
|
this.mutedServerByUser = false
|
||||||
|
this.mutedServerByInstance = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { AccountBlock } from '@app/shared/blocklist/account-block.model'
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BlocklistService {
|
export class BlocklistService {
|
||||||
static BASE_USER_BLOCKLIST_URL = environment.apiUrl + '/api/v1/users/me/blocklist'
|
static BASE_USER_BLOCKLIST_URL = environment.apiUrl + '/api/v1/users/me/blocklist'
|
||||||
|
static BASE_SERVER_BLOCKLIST_URL = environment.apiUrl + '/api/v1/server/blocklist'
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authHttp: HttpClient,
|
private authHttp: HttpClient,
|
||||||
|
@ -73,6 +74,61 @@ export class BlocklistService {
|
||||||
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************** Instance -> Account blocklist ***********************/
|
||||||
|
|
||||||
|
getInstanceAccountBlocklist (pagination: RestPagination, sort: SortMeta) {
|
||||||
|
let params = new HttpParams()
|
||||||
|
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||||
|
|
||||||
|
return this.authHttp.get<ResultList<AccountBlock>>(BlocklistService.BASE_SERVER_BLOCKLIST_URL + '/accounts', { params })
|
||||||
|
.pipe(
|
||||||
|
map(res => this.restExtractor.convertResultListDateToHuman(res)),
|
||||||
|
map(res => this.restExtractor.applyToResultListData(res, this.formatAccountBlock.bind(this))),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
blockAccountByInstance (account: Account) {
|
||||||
|
const body = { accountName: account.nameWithHost }
|
||||||
|
|
||||||
|
return this.authHttp.post(BlocklistService.BASE_SERVER_BLOCKLIST_URL + '/accounts', body)
|
||||||
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
unblockAccountByInstance (account: Account) {
|
||||||
|
const path = BlocklistService.BASE_SERVER_BLOCKLIST_URL + '/accounts/' + account.nameWithHost
|
||||||
|
|
||||||
|
return this.authHttp.delete(path)
|
||||||
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************** Instance -> Server blocklist ***********************/
|
||||||
|
|
||||||
|
getInstanceServerBlocklist (pagination: RestPagination, sort: SortMeta) {
|
||||||
|
let params = new HttpParams()
|
||||||
|
params = this.restService.addRestGetParams(params, pagination, sort)
|
||||||
|
|
||||||
|
return this.authHttp.get<ResultList<ServerBlock>>(BlocklistService.BASE_SERVER_BLOCKLIST_URL + '/servers', { params })
|
||||||
|
.pipe(
|
||||||
|
map(res => this.restExtractor.convertResultListDateToHuman(res)),
|
||||||
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
blockServerByInstance (host: string) {
|
||||||
|
const body = { host }
|
||||||
|
|
||||||
|
return this.authHttp.post(BlocklistService.BASE_SERVER_BLOCKLIST_URL + '/servers', body)
|
||||||
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
|
unblockServerByInstance (host: string) {
|
||||||
|
const path = BlocklistService.BASE_SERVER_BLOCKLIST_URL + '/servers/' + host
|
||||||
|
|
||||||
|
return this.authHttp.delete(path)
|
||||||
|
.pipe(catchError(err => this.restExtractor.handleError(err)))
|
||||||
|
}
|
||||||
|
|
||||||
private formatAccountBlock (accountBlock: AccountBlockServer) {
|
private formatAccountBlock (accountBlock: AccountBlockServer) {
|
||||||
return new AccountBlock(accountBlock)
|
return new AccountBlock(accountBlock)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ export class UserModerationDropdownComponent implements OnChanges {
|
||||||
@Output() userChanged = new EventEmitter()
|
@Output() userChanged = new EventEmitter()
|
||||||
@Output() userDeleted = new EventEmitter()
|
@Output() userDeleted = new EventEmitter()
|
||||||
|
|
||||||
userActions: DropdownAction<User>[] = []
|
userActions: DropdownAction<{ user: User, account: Account }>[] = []
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
|
@ -106,7 +106,7 @@ export class UserModerationDropdownComponent implements OnChanges {
|
||||||
this.i18n('Account {{nameWithHost}} muted.', { nameWithHost: account.nameWithHost })
|
this.i18n('Account {{nameWithHost}} muted.', { nameWithHost: account.nameWithHost })
|
||||||
)
|
)
|
||||||
|
|
||||||
this.account.muted = true
|
this.account.mutedByUser = true
|
||||||
this.userChanged.emit()
|
this.userChanged.emit()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ export class UserModerationDropdownComponent implements OnChanges {
|
||||||
this.i18n('Account {{nameWithHost}} unmuted.', { nameWithHost: account.nameWithHost })
|
this.i18n('Account {{nameWithHost}} unmuted.', { nameWithHost: account.nameWithHost })
|
||||||
)
|
)
|
||||||
|
|
||||||
this.account.muted = false
|
this.account.mutedByUser = false
|
||||||
this.userChanged.emit()
|
this.userChanged.emit()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -140,7 +140,7 @@ export class UserModerationDropdownComponent implements OnChanges {
|
||||||
this.i18n('Instance {{host}} muted.', { host })
|
this.i18n('Instance {{host}} muted.', { host })
|
||||||
)
|
)
|
||||||
|
|
||||||
this.account.mutedServer = true
|
this.account.mutedServerByUser = true
|
||||||
this.userChanged.emit()
|
this.userChanged.emit()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -157,7 +157,75 @@ export class UserModerationDropdownComponent implements OnChanges {
|
||||||
this.i18n('Instance {{host}} unmuted.', { host })
|
this.i18n('Instance {{host}} unmuted.', { host })
|
||||||
)
|
)
|
||||||
|
|
||||||
this.account.mutedServer = false
|
this.account.mutedServerByUser = false
|
||||||
|
this.userChanged.emit()
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
blockAccountByInstance (account: Account) {
|
||||||
|
this.blocklistService.blockAccountByInstance(account)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.i18n('Success'),
|
||||||
|
this.i18n('Account {{nameWithHost}} muted by the instance.', { nameWithHost: account.nameWithHost })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.account.mutedByInstance = true
|
||||||
|
this.userChanged.emit()
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
unblockAccountByInstance (account: Account) {
|
||||||
|
this.blocklistService.unblockAccountByInstance(account)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.i18n('Success'),
|
||||||
|
this.i18n('Account {{nameWithHost}} unmuted by the instance.', { nameWithHost: account.nameWithHost })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.account.mutedByInstance = false
|
||||||
|
this.userChanged.emit()
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
blockServerByInstance (host: string) {
|
||||||
|
this.blocklistService.blockServerByInstance(host)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.i18n('Success'),
|
||||||
|
this.i18n('Instance {{host}} muted by the instance.', { host })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.account.mutedServerByInstance = true
|
||||||
|
this.userChanged.emit()
|
||||||
|
},
|
||||||
|
|
||||||
|
err => this.notificationsService.error(this.i18n('Error'), err.message)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
unblockServerByInstance (host: string) {
|
||||||
|
this.blocklistService.unblockServerByInstance(host)
|
||||||
|
.subscribe(
|
||||||
|
() => {
|
||||||
|
this.notificationsService.success(
|
||||||
|
this.i18n('Success'),
|
||||||
|
this.i18n('Instance {{host}} unmuted by the instance.', { host })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.account.mutedServerByInstance = false
|
||||||
this.userChanged.emit()
|
this.userChanged.emit()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -189,41 +257,74 @@ export class UserModerationDropdownComponent implements OnChanges {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.i18n('Ban'),
|
label: this.i18n('Ban'),
|
||||||
handler: ({ user }) => this.openBanUserModal(user),
|
handler: ({ user }: { user: User }) => this.openBanUserModal(user),
|
||||||
isDisplayed: ({ user }) => !user.muted
|
isDisplayed: ({ user }: { user: User }) => !user.blocked
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.i18n('Unban'),
|
label: this.i18n('Unban'),
|
||||||
handler: ({ user }) => this.unbanUser(user),
|
handler: ({ user }: { user: User }) => this.unbanUser(user),
|
||||||
isDisplayed: ({ user }) => user.muted
|
isDisplayed: ({ user }: { user: User }) => user.blocked
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
// User actions on accounts/servers
|
// Actions on accounts/servers
|
||||||
if (this.account) {
|
if (this.account) {
|
||||||
|
// User actions
|
||||||
this.userActions = this.userActions.concat([
|
this.userActions = this.userActions.concat([
|
||||||
{
|
{
|
||||||
label: this.i18n('Mute this account'),
|
label: this.i18n('Mute this account'),
|
||||||
isDisplayed: ({ account }) => account.muted === false,
|
isDisplayed: ({ account }: { account: Account }) => account.mutedByUser === false,
|
||||||
handler: ({ account }) => this.blockAccountByUser(account)
|
handler: ({ account }: { account: Account }) => this.blockAccountByUser(account)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.i18n('Unmute this account'),
|
label: this.i18n('Unmute this account'),
|
||||||
isDisplayed: ({ account }) => account.muted === true,
|
isDisplayed: ({ account }: { account: Account }) => account.mutedByUser === true,
|
||||||
handler: ({ account }) => this.unblockAccountByUser(account)
|
handler: ({ account }: { account: Account }) => this.unblockAccountByUser(account)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.i18n('Mute the instance'),
|
label: this.i18n('Mute the instance'),
|
||||||
isDisplayed: ({ account }) => !account.userId && account.mutedServer === false,
|
isDisplayed: ({ account }: { account: Account }) => !account.userId && account.mutedServerByInstance === false,
|
||||||
handler: ({ account }) => this.blockServerByUser(account.host)
|
handler: ({ account }: { account: Account }) => this.blockServerByUser(account.host)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: this.i18n('Unmute the instance'),
|
label: this.i18n('Unmute the instance'),
|
||||||
isDisplayed: ({ account }) => !account.userId && account.mutedServer === true,
|
isDisplayed: ({ account }: { account: Account }) => !account.userId && account.mutedServerByInstance === true,
|
||||||
handler: ({ account }) => this.unblockServerByUser(account.host)
|
handler: ({ account }: { account: Account }) => this.unblockServerByUser(account.host)
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
// Instance actions
|
||||||
|
if (authUser.hasRight(UserRight.MANAGE_ACCOUNTS_BLOCKLIST)) {
|
||||||
|
this.userActions = this.userActions.concat([
|
||||||
|
{
|
||||||
|
label: this.i18n('Mute this account by your instance'),
|
||||||
|
isDisplayed: ({ account }: { account: Account }) => account.mutedByInstance === false,
|
||||||
|
handler: ({ account }: { account: Account }) => this.blockAccountByInstance(account)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n('Unmute this account by your instance'),
|
||||||
|
isDisplayed: ({ account }: { account: Account }) => account.mutedByInstance === true,
|
||||||
|
handler: ({ account }: { account: Account }) => this.unblockAccountByInstance(account)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instance actions
|
||||||
|
if (authUser.hasRight(UserRight.MANAGE_SERVERS_BLOCKLIST)) {
|
||||||
|
this.userActions = this.userActions.concat([
|
||||||
|
{
|
||||||
|
label: this.i18n('Mute the instance by your instance'),
|
||||||
|
isDisplayed: ({ account }: { account: Account }) => !account.userId && account.mutedServerByInstance === false,
|
||||||
|
handler: ({ account }: { account: Account }) => this.blockServerByInstance(account.host)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: this.i18n('Unmute the instance by your instance'),
|
||||||
|
isDisplayed: ({ account }: { account: Account }) => !account.userId && account.mutedServerByInstance === true,
|
||||||
|
handler: ({ account }: { account: Account }) => this.unblockServerByInstance(account.host)
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,3 +30,5 @@ $input-focus-border-color: #ced4da;
|
||||||
|
|
||||||
$nav-pills-link-active-bg: #F0F0F0;
|
$nav-pills-link-active-bg: #F0F0F0;
|
||||||
$nav-pills-link-active-color: #000;
|
$nav-pills-link-active-color: #000;
|
||||||
|
|
||||||
|
$zindex-dropdown: 10000;
|
|
@ -294,7 +294,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
|
||||||
static async listThreadsForApi (videoId: number, start: number, count: number, sort: string, user?: UserModel) {
|
static async listThreadsForApi (videoId: number, start: number, count: number, sort: string, user?: UserModel) {
|
||||||
const serverActor = await getServerActor()
|
const serverActor = await getServerActor()
|
||||||
const serverAccountId = serverActor.Account.id
|
const serverAccountId = serverActor.Account.id
|
||||||
const userAccountId = user.Account.id
|
const userAccountId = user ? user.Account.id : undefined
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
offset: start,
|
offset: start,
|
||||||
|
@ -330,7 +330,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
|
||||||
static async listThreadCommentsForApi (videoId: number, threadId: number, user?: UserModel) {
|
static async listThreadCommentsForApi (videoId: number, threadId: number, user?: UserModel) {
|
||||||
const serverActor = await getServerActor()
|
const serverActor = await getServerActor()
|
||||||
const serverAccountId = serverActor.Account.id
|
const serverAccountId = serverActor.Account.id
|
||||||
const userAccountId = user.Account.id
|
const userAccountId = user ? user.Account.id : undefined
|
||||||
|
|
||||||
const query = {
|
const query = {
|
||||||
order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ],
|
order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ],
|
||||||
|
|
|
@ -1255,9 +1255,11 @@ export class VideoModel extends Model<VideoModel> {
|
||||||
|
|
||||||
// threshold corresponds to how many video the field should have to be returned
|
// threshold corresponds to how many video the field should have to be returned
|
||||||
static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) {
|
static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) {
|
||||||
const actorId = (await getServerActor()).id
|
const serverActor = await getServerActor()
|
||||||
|
const actorId = serverActor.id
|
||||||
|
|
||||||
const scopeOptions = {
|
const scopeOptions: AvailableForListIDsOptions = {
|
||||||
|
serverAccountId: serverActor.Account.id,
|
||||||
actorId,
|
actorId,
|
||||||
includeLocalVideos: true
|
includeLocalVideos: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
userLogin
|
userLogin
|
||||||
} from '../../utils/index'
|
} from '../../utils/index'
|
||||||
import { setAccessTokensToServers } from '../../utils/users/login'
|
import { setAccessTokensToServers } from '../../utils/users/login'
|
||||||
import { getVideosListWithToken } from '../../utils/videos/videos'
|
import { getVideosListWithToken, getVideosList } from '../../utils/videos/videos'
|
||||||
import {
|
import {
|
||||||
addVideoCommentReply,
|
addVideoCommentReply,
|
||||||
addVideoCommentThread,
|
addVideoCommentThread,
|
||||||
|
@ -41,9 +41,17 @@ import {
|
||||||
const expect = chai.expect
|
const expect = chai.expect
|
||||||
|
|
||||||
async function checkAllVideos (url: string, token: string) {
|
async function checkAllVideos (url: string, token: string) {
|
||||||
const res = await getVideosListWithToken(url, token)
|
{
|
||||||
|
const res = await getVideosListWithToken(url, token)
|
||||||
|
|
||||||
expect(res.body.data).to.have.lengthOf(4)
|
expect(res.body.data).to.have.lengthOf(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const res = await getVideosList(url)
|
||||||
|
|
||||||
|
expect(res.body.data).to.have.lengthOf(4)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkAllComments (url: string, token: string, videoUUID: string) {
|
async function checkAllComments (url: string, token: string, videoUUID: string) {
|
||||||
|
@ -444,16 +452,19 @@ describe('Test blocklist', function () {
|
||||||
|
|
||||||
it('Should hide its videos', async function () {
|
it('Should hide its videos', async function () {
|
||||||
for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
|
for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
|
||||||
const res = await getVideosListWithToken(servers[ 0 ].url, token)
|
const res1 = await getVideosList(servers[ 0 ].url)
|
||||||
|
const res2 = await getVideosListWithToken(servers[ 0 ].url, token)
|
||||||
|
|
||||||
const videos: Video[] = res.body.data
|
for (const res of [ res1, res2 ]) {
|
||||||
expect(videos).to.have.lengthOf(2)
|
const videos: Video[] = res.body.data
|
||||||
|
expect(videos).to.have.lengthOf(2)
|
||||||
|
|
||||||
const v1 = videos.find(v => v.name === 'video user 2')
|
const v1 = videos.find(v => v.name === 'video user 2')
|
||||||
const v2 = videos.find(v => v.name === 'video server 2')
|
const v2 = videos.find(v => v.name === 'video server 2')
|
||||||
|
|
||||||
expect(v1).to.be.undefined
|
expect(v1).to.be.undefined
|
||||||
expect(v2).to.be.undefined
|
expect(v2).to.be.undefined
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue