ngOnInit () {
if (this.hasUsersRight()) this.items.push({ label: this.i18n('Users'), routerLink: '/admin/users' })
if (this.hasServerFollowRight()) this.items.push({ label: this.i18n('Follows & redundancies'), routerLink: '/admin/follows' })
- if (this.hasVideoAbusesRight() || this.hasVideoBlacklistRight()) this.items.push({ label: this.i18n('Moderation'), routerLink: '/admin/moderation' })
+ if (this.hasVideoAbusesRight() || this.hasVideoBlocklistRight()) this.items.push({ label: this.i18n('Moderation'), routerLink: '/admin/moderation' })
if (this.hasConfigRight()) this.items.push({ label: this.i18n('Configuration'), routerLink: '/admin/config' })
if (this.hasPluginsRight()) this.items.push({ label: this.i18n('Plugins/Themes'), routerLink: '/admin/plugins' })
if (this.hasJobsRight() || this.hasLogsRight() || this.hasDebugRight()) this.items.push({ label: this.i18n('System'), routerLink: '/admin/system' })
return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES)
}
- hasVideoBlacklistRight () {
- return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
+ hasVideoBlocklistRight () {
+ return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLOCKS)
}
hasConfigRight () {
import {
ModerationCommentModalComponent,
VideoAbuseListComponent,
- VideoAutoBlacklistListComponent,
- VideoBlacklistListComponent
+ VideoBlockListComponent
} from './moderation'
import { ModerationComponent } from '@app/+admin/moderation/moderation.component'
import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component'
UserListComponent,
ModerationComponent,
- VideoBlacklistListComponent,
+ VideoBlockListComponent,
VideoAbuseListComponent,
VideoAbuseDetailsComponent,
- VideoAutoBlacklistListComponent,
ModerationCommentModalComponent,
InstanceServerBlocklistComponent,
InstanceAccountBlocklistComponent,
<div class="form-group">
<my-peertube-checkbox
inputName="autoBlacklistVideosOfUsersEnabled" formControlName="enabled"
- i18n-labelText labelText="Blacklist new videos automatically"
+ i18n-labelText labelText="Block new videos automatically"
>
<ng-container ngProjectAs="description">
<span i18n>Unless a user is marked as trusted, their videos will stay private until a moderator reviews them.</span>
<div class="form-group">
<my-peertube-checkbox inputName="servicesTwitterWhitelisted" formControlName="whitelisted">
<ng-template ptTemplate="label">
- <ng-container i18n>Instance whitelisted by Twitter</ng-container>
+ <ng-container i18n>Instance allowed by Twitter</ng-container>
</ng-template>
<ng-template ptTemplate="help">
<ng-container i18n>
- If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
- If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br />
+ If your instance is explicitly allowed by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br />
+ If the instance is not, we use an image link card that will redirect on your PeerTube instance.<br /><br />
Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on
<a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a>
- to see if you instance is whitelisted.
+ to see if you instance is allowed.
</ng-container>
</ng-template>
</my-peertube-checkbox>
export * from './video-abuse-list'
-export * from './video-auto-blacklist-list'
-export * from './video-blacklist-list'
+export * from './video-block-list'
export * from './moderation.component'
export * from './moderation.routes'
<div i18n class="form-sub-title">Moderation</div>
<div class="admin-sub-nav">
- <a *ngIf="hasVideoAbusesRight()" i18n routerLink="video-abuses/list" routerLinkActive="active">Video abuses</a>
+ <a *ngIf="hasVideoAbusesRight()" i18n routerLink="video-abuses/list" routerLinkActive="active">Video reports</a>
- <a *ngIf="hasVideoBlacklistRight()" i18n routerLink="video-blacklist/list" routerLinkActive="active">{{ autoBlacklistVideosEnabled ? 'Manually blacklisted videos' : 'Blacklisted videos' }}</a>
-
- <a *ngIf="autoBlacklistVideosEnabled && hasVideoBlacklistRight()" i18n routerLink="video-auto-blacklist/list" routerLinkActive="active">Auto-blacklisted videos</a>
+ <a *ngIf="hasVideoBlocklistRight()" i18n routerLink="video-blocks/list" routerLinkActive="active">Video blocks</a>
<a *ngIf="hasAccountsBlocklistRight()" i18n routerLink="blocklist/accounts" routerLinkActive="active">Muted accounts</a>
styleUrls: [ './moderation.component.scss' ]
})
export class ModerationComponent implements OnInit {
- autoBlacklistVideosEnabled = false
+ autoBlockVideosEnabled = false
constructor (
private auth: AuthService,
ngOnInit (): void {
this.serverService.getConfig()
- .subscribe(config => this.autoBlacklistVideosEnabled = config.autoBlacklist.videos.ofUsers.enabled)
+ .subscribe(config => this.autoBlockVideosEnabled = config.autoBlacklist.videos.ofUsers.enabled)
}
return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES)
}
- hasVideoBlacklistRight () {
- return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
+ hasVideoBlocklistRight () {
+ return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLOCKS)
}
hasAccountsBlocklistRight () {
import { UserRight } from '../../../../../shared'
import { UserRightGuard } from '@app/core'
import { VideoAbuseListComponent } from '@app/+admin/moderation/video-abuse-list'
-import { VideoBlacklistListComponent } from '@app/+admin/moderation/video-blacklist-list'
-import { VideoAutoBlacklistListComponent } from '@app/+admin/moderation/video-auto-blacklist-list'
+import { VideoBlockListComponent } from '@app/+admin/moderation/video-block-list'
import { ModerationComponent } from '@app/+admin/moderation/moderation.component'
import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist'
redirectTo: 'video-abuses/list',
pathMatch: 'full'
},
- {
- path: 'video-blacklist',
- redirectTo: 'video-blacklist/list',
- pathMatch: 'full'
- },
- {
- path: 'video-auto-blacklist',
- redirectTo: 'video-auto-blacklist/list',
- pathMatch: 'full'
- },
{
path: 'video-abuses/list',
component: VideoAbuseListComponent,
data: {
userRight: UserRight.MANAGE_VIDEO_ABUSES,
meta: {
- title: 'Video abuses list'
+ title: 'Video reports'
}
}
},
+ {
+ path: 'video-blacklist',
+ redirectTo: 'video-blocks/list',
+ pathMatch: 'full'
+ },
+ {
+ path: 'video-auto-blacklist',
+ redirectTo: 'video-blocks/list',
+ pathMatch: 'full'
+ },
{
path: 'video-auto-blacklist/list',
- component: VideoAutoBlacklistListComponent,
- canActivate: [ UserRightGuard ],
- data: {
- userRight: UserRight.MANAGE_VIDEO_BLACKLIST,
- meta: {
- title: 'Auto-blacklisted videos'
- }
- }
+ redirectTo: 'video-blocks/list',
+ pathMatch: 'full'
+ },
+ {
+ path: 'video-blacklist',
+ redirectTo: 'video-blocks/list',
+ pathMatch: 'full'
},
{
- path: 'video-blacklist/list',
- component: VideoBlacklistListComponent,
+ path: 'video-blocks/list',
+ component: VideoBlockListComponent,
canActivate: [ UserRightGuard ],
data: {
- userRight: UserRight.MANAGE_VIDEO_BLACKLIST,
+ userRight: UserRight.MANAGE_VIDEO_BLOCKS,
meta: {
- title: 'Blacklisted videos'
+ title: 'Videos blocked'
}
}
},
<div class="screenratio">
<div *ngIf="videoAbuse.video.deleted || videoAbuse.video.blacklisted">
<span i18n *ngIf="videoAbuse.video.deleted">The video was deleted</span>
- <span i18n *ngIf="!videoAbuse.video.deleted">The video was blacklisted</span>
+ <span i18n *ngIf="!videoAbuse.video.deleted">The video was blocked</span>
</div>
<div *ngIf="!videoAbuse.video.deleted && !videoAbuse.video.blacklisted" [innerHTML]="videoAbuse.embedHtml"></div>
</div>
<a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:pending' }" class="dropdown-item" i18n>Unsolved reports</a>
<a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:accepted' }" class="dropdown-item" i18n>Accepted reports</a>
<a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:rejected' }" class="dropdown-item" i18n>Refused reports</a>
- <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'videoIs:blacklisted' }" class="dropdown-item" i18n>Reports with blacklisted videos</a>
+ <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'videoIs:blacklisted' }" class="dropdown-item" i18n>Reports with blocked videos</a>
<a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'videoIs:deleted' }" class="dropdown-item" i18n>Reports with deleted videos</a>
</div>
</div>
</div>
<div class="video-table-video-text">
<div>
- {{ videoAbuse.video.name }}
<span *ngIf="!videoAbuse.video.blacklisted" class="glyphicon glyphicon-new-window"></span>
- <span *ngIf="videoAbuse.video.blacklisted" i18n-title title="Video was blacklisted" class="glyphicon glyphicon-ban-circle"></span>
+ <span *ngIf="videoAbuse.video.blacklisted" i18n-title title="The video was blocked" class="glyphicon glyphicon-ban-circle"></span>
+ {{ videoAbuse.video.name }}
</div>
<div class="text-muted" i18n>by {{ videoAbuse.video.channel?.displayName }} on {{ videoAbuse.video.channel?.host }} </div>
</div>
import { Notifier } from '@app/core'
import { SortMeta } from 'primeng/api'
import { VideoAbuse, VideoAbuseState } from '../../../../../../shared'
-import { RestPagination, RestTable, VideoAbuseService, VideoBlacklistService } from '../../../shared'
+import { RestPagination, RestTable, VideoAbuseService, VideoBlockService } from '../../../shared'
import { I18n } from '@ngx-translate/i18n-polyfill'
import { DropdownAction } from '../../../shared/buttons/action-dropdown.component'
import { ConfirmService } from '../../../core/index'
private videoAbuseService: VideoAbuseService,
private blocklistService: BlocklistService,
private videoService: VideoService,
- private videoBlacklistService: VideoBlacklistService,
+ private videoBlocklistService: VideoBlockService,
private confirmService: ConfirmService,
private i18n: I18n,
private markdownRenderer: MarkdownService,
isDisplayed: videoAbuse => !videoAbuse.video.deleted
},
{
- label: this.i18n('Blacklist video'),
+ label: this.i18n('Block video'),
isDisplayed: videoAbuse => !videoAbuse.video.deleted && !videoAbuse.video.blacklisted,
handler: videoAbuse => {
- this.videoBlacklistService.blacklistVideo(videoAbuse.video.id, undefined, true)
+ this.videoBlocklistService.blockVideo(videoAbuse.video.id, undefined, true)
.subscribe(
() => {
- this.notifier.success(this.i18n('Video blacklisted.'))
+ this.notifier.success(this.i18n('Video blocklisted.'))
this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED)
},
}
},
{
- label: this.i18n('Unblacklist video'),
+ label: this.i18n('Unblock video'),
isDisplayed: videoAbuse => !videoAbuse.video.deleted && videoAbuse.video.blacklisted,
handler: videoAbuse => {
- this.videoBlacklistService.removeVideoFromBlacklist(videoAbuse.video.id)
+ this.videoBlocklistService.unblockVideo(videoAbuse.video.id)
.subscribe(
() => {
- this.notifier.success(this.i18n('Video unblacklisted.'))
+ this.notifier.success(this.i18n('Video unblocklisted.'))
this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED)
},
err => this.notifier.error(err.message)
)
-
}
protected loadData () {
+++ /dev/null
-export * from './video-auto-blacklist-list.component'
+++ /dev/null
-<my-videos-selection
- [pagination]="pagination"
- [(selection)]="selection"
- [(videosModel)]="videos"
- [miniatureDisplayOptions]="miniatureDisplayOptions"
- [titlePage]="titlePage"
- [getVideosObservableFunction]="getVideosObservableFunction"
->
- <ng-template ptTemplate="globalButtons">
- <span class="action-button action-button-unblacklist-selection" (click)="removeSelectedVideosFromBlacklist()">
- <my-global-icon iconName="tick"></my-global-icon>
- <ng-container i18n>Unblacklist</ng-container>
- </span>
- </ng-template>
-
- <ng-template ptTemplate="rowButtons" let-video>
- <my-button i18n-label label="Unblacklist" icon="tick" (click)="removeVideoFromBlacklist(video)"></my-button>
- </ng-template>
-
-</my-videos-selection>
+++ /dev/null
-@import '_variables';
-@import '_mixins';
-
-.action-button-unblacklist-selection {
- display: inline-block;
-
- @include peertube-button;
- @include orange-button;
- @include button-with-icon(21px);
-
- my-global-icon {
- @include apply-svg-color(#fff);
- }
-}
+++ /dev/null
-import { Component } from '@angular/core'
-import { I18n } from '@ngx-translate/i18n-polyfill'
-import { ActivatedRoute, Router } from '@angular/router'
-import { ComponentPagination } from '@app/shared/rest/component-pagination.model'
-import { AuthService, Notifier, ServerService } from '@app/core'
-import { VideoBlacklistService } from '@app/shared'
-import { immutableAssign } from '@app/shared/misc/utils'
-import { ScreenService } from '@app/shared/misc/screen.service'
-import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component'
-import { SelectionType } from '@app/shared/video/videos-selection.component'
-import { Video } from '@app/shared/video/video.model'
-
-@Component({
- selector: 'my-video-auto-blacklist-list',
- templateUrl: './video-auto-blacklist-list.component.html',
- styleUrls: [ './video-auto-blacklist-list.component.scss' ]
-})
-export class VideoAutoBlacklistListComponent {
- titlePage: string
- selection: SelectionType = {}
- miniatureDisplayOptions: MiniatureDisplayOptions = {
- date: true,
- views: false,
- by: true,
- privacyLabel: false,
- privacyText: true,
- state: false,
- blacklistInfo: false,
- nsfw: true
- }
- pagination: ComponentPagination = {
- currentPage: 1,
- itemsPerPage: 5,
- totalItems: null
- }
- videos: Video[] = []
- getVideosObservableFunction = this.getVideosObservable.bind(this)
-
- constructor (
- protected router: Router,
- protected route: ActivatedRoute,
- protected notifier: Notifier,
- protected authService: AuthService,
- protected screenService: ScreenService,
- protected serverService: ServerService,
- private i18n: I18n,
- private videoBlacklistService: VideoBlacklistService
- ) {
- this.titlePage = this.i18n('Auto-blacklisted videos')
- }
-
- getVideosObservable (page: number) {
- const newPagination = immutableAssign(this.pagination, { currentPage: page })
-
- return this.videoBlacklistService.getAutoBlacklistedAsVideoList(newPagination)
- }
-
- removeVideoFromBlacklist (entry: Video) {
- this.videoBlacklistService.removeVideoFromBlacklist(entry.id).subscribe(
- () => {
- this.notifier.success(this.i18n('Video {{name}} removed from blacklist.', { name: entry.name }))
-
- this.videos = this.videos.filter(v => v.id !== entry.id)
- },
-
- error => this.notifier.error(error.message)
- )
- }
-
- removeSelectedVideosFromBlacklist () {
- const toReleaseVideosIds = Object.keys(this.selection)
- .filter(k => this.selection[ k ] === true)
- .map(k => parseInt(k, 10))
-
- this.videoBlacklistService.removeVideoFromBlacklist(toReleaseVideosIds).subscribe(
- () => {
- this.notifier.success(this.i18n('{{num}} videos removed from blacklist.', { num: toReleaseVideosIds.length }))
-
- this.selection = {}
- this.videos = this.videos.filter(v => toReleaseVideosIds.includes(v.id) === false)
- },
-
- error => this.notifier.error(error.message)
- )
- }
-}
+++ /dev/null
-export * from './video-blacklist-list.component'
+++ /dev/null
-<p-table
- [value]="blacklist" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
- [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id"
- [showCurrentPageReport]="true" i18n-currentPageReportTemplate
- currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} blacklisted videos"
- (onPage)="onPage($event)" [expandedRowKeys]="expandedRows"
->
- <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: 40px"></th>
- <th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th>
- <th style="width: 100px;" i18n>Sensitive</th>
- <th style="width: 120px;" i18n>Unfederated</th>
- <th style="width: 150px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th>
- <th style="width: 150px;"></th>
- </tr>
- </ng-template>
-
- <ng-template pTemplate="body" let-videoBlacklist let-expanded="expanded">
- <tr>
- <td *ngIf="!videoBlacklist.reason"></td>
- <td *ngIf="videoBlacklist.reason" class="expand-cell c-hand" [pRowToggler]="videoBlacklist" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body">
- <span class="expander">
- <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i>
- </span>
- </td>
-
- <td>
- <a [href]="getVideoUrl(videoBlacklist)" class="video-table-video-link" i18n-title title="Open video in a new tab" target="_blank" rel="noopener noreferrer">
- <div class="video-table-video">
- <div class="video-table-video-image">
- <img [src]="videoBlacklist.video.thumbnailPath">
- </div>
- <div class="video-table-video-text">
- <div>
- {{ videoBlacklist.video.name }}
- <span i18n-title title="Video was blacklisted" class="glyphicon glyphicon-ban-circle"></span>
- </div>
- <div class="text-muted">by {{ videoBlacklist.video.channel?.displayName }} on {{ videoBlacklist.video.channel?.host }} </div>
- </div>
- </div>
- </a>
- </td>
-
- <ng-container *ngIf="videoBlacklist.reason">
- <td class="c-hand" [pRowToggler]="videoBlacklist">{{ booleanToText(videoBlacklist.video.nsfw) }}</td>
- <td class="c-hand" [pRowToggler]="videoBlacklist">{{ booleanToText(videoBlacklist.unfederated) }}</td>
- <td class="c-hand" [pRowToggler]="videoBlacklist">{{ videoBlacklist.createdAt | date: 'short' }}</td>
- </ng-container>
- <ng-container *ngIf="!videoBlacklist.reason">
- <td>{{ booleanToText(videoBlacklist.video.nsfw) }}</td>
- <td>{{ booleanToText(videoBlacklist.unfederated) }}</td>
- <td>{{ videoBlacklist.createdAt | date: 'short' }}</td>
- </ng-container>
-
- <td class="action-cell">
- <my-action-dropdown
- [ngClass]="{ 'show': expanded }" placement="bottom-right" container="body"
- i18n-label label="Actions" [actions]="videoBlacklistActions" [entry]="videoBlacklist"
- ></my-action-dropdown>
- </td>
- </tr>
- </ng-template>
-
- <ng-template pTemplate="rowexpansion" let-videoBlacklist>
- <tr>
- <td class="expand-cell" colspan="6">
- <div class="d-flex moderation-expanded">
- <span class="col-2 moderation-expanded-label" i18n>Blacklist reason:</span>
- <span class="col-9 moderation-expanded-text" [innerHTML]="videoBlacklist.reasonHtml"></span>
- </div>
- </td>
- </tr>
- </ng-template>
-
- <ng-template pTemplate="emptymessage">
- <tr>
- <td colspan="6">
- <div class="empty-table-message">
- <ng-container *ngIf="search" i18n>No blacklisted video found matching current filters.</ng-container>
- <ng-container *ngIf="!search" i18n>No blacklisted video found.</ng-container>
- </div>
- </td>
- </tr>
- </ng-template>
-</p-table>
-
+++ /dev/null
-import { Component, OnInit } from '@angular/core'
-import { SortMeta } from 'primeng/api'
-import { Notifier, ServerService } from '@app/core'
-import { ConfirmService } from '../../../core'
-import { RestPagination, RestTable, VideoBlacklistService } from '../../../shared'
-import { VideoBlacklist, VideoBlacklistType } from '../../../../../../shared'
-import { I18n } from '@ngx-translate/i18n-polyfill'
-import { DropdownAction } from '../../../shared/buttons/action-dropdown.component'
-import { Video } from '../../../shared/video/video.model'
-import { MarkdownService } from '@app/shared/renderer'
-
-@Component({
- selector: 'my-video-blacklist-list',
- templateUrl: './video-blacklist-list.component.html',
- styleUrls: [ '../moderation.component.scss' ]
-})
-export class VideoBlacklistListComponent extends RestTable implements OnInit {
- blacklist: (VideoBlacklist & { reasonHtml?: string })[] = []
- totalRecords = 0
- sort: SortMeta = { field: 'createdAt', order: -1 }
- pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
- listBlacklistTypeFilter: VideoBlacklistType = undefined
-
- videoBlacklistActions: DropdownAction<VideoBlacklist>[] = []
-
- constructor (
- private notifier: Notifier,
- private serverService: ServerService,
- private confirmService: ConfirmService,
- private videoBlacklistService: VideoBlacklistService,
- private markdownRenderer: MarkdownService,
- private i18n: I18n
- ) {
- super()
- }
-
- ngOnInit () {
- this.serverService.getConfig()
- .subscribe(config => {
- // don't filter if auto-blacklist is not enabled as this will be the only list
- if (config.autoBlacklist.videos.ofUsers.enabled) {
- this.listBlacklistTypeFilter = VideoBlacklistType.MANUAL
- }
- })
-
- this.initialize()
-
- this.videoBlacklistActions = [
- {
- label: this.i18n('Unblacklist'),
- handler: videoBlacklist => this.removeVideoFromBlacklist(videoBlacklist)
- }
- ]
- }
-
- getIdentifier () {
- return 'VideoBlacklistListComponent'
- }
-
- getVideoUrl (videoBlacklist: VideoBlacklist) {
- return Video.buildClientUrl(videoBlacklist.video.uuid)
- }
-
- booleanToText (value: boolean) {
- if (value === true) return this.i18n('yes')
-
- return this.i18n('no')
- }
-
- toHtml (text: string) {
- return this.markdownRenderer.textMarkdownToHTML(text)
- }
-
- async removeVideoFromBlacklist (entry: VideoBlacklist) {
- const confirmMessage = this.i18n(
- 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.'
- )
-
- const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblacklist'))
- if (res === false) return
-
- this.videoBlacklistService.removeVideoFromBlacklist(entry.video.id).subscribe(
- () => {
- this.notifier.success(this.i18n('Video {{name}} removed from the blacklist.', { name: entry.video.name }))
- this.loadData()
- },
-
- err => this.notifier.error(err.message)
- )
- }
-
- protected loadData () {
- this.videoBlacklistService.listBlacklist({
- pagination: this.pagination,
- sort: this.sort,
- search: this.search,
- type: this.listBlacklistTypeFilter
- })
- .subscribe(
- async resultList => {
- this.totalRecords = resultList.total
-
- this.blacklist = resultList.data
-
- for (const element of this.blacklist) {
- Object.assign(element, { reasonHtml: await this.toHtml(element.reason) })
- }
- },
-
- err => this.notifier.error(err.message)
- )
- }
-}
--- /dev/null
+export * from './video-block-list.component'
--- /dev/null
+<p-table
+ [value]="blocklist" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
+ [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id"
+ [showCurrentPageReport]="true" i18n-currentPageReportTemplate
+ currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} blocked videos"
+ (onPage)="onPage($event)" [expandedRowKeys]="expandedRows"
+>
+ <ng-template pTemplate="caption">
+ <div class="caption">
+ <div class="ml-auto">
+ <div class="input-group has-feedback has-clear">
+ <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body">
+ <div class="input-group-text" ngbDropdownToggle>
+ <span class="caret" aria-haspopup="menu" role="button"></span>
+ </div>
+
+ <div role="menu" ngbDropdownMenu>
+ <h6 class="dropdown-header" i18n>Advanced block filters</h6>
+ <a [routerLink]="[ '/admin/moderation/video-blocks/list' ]" [queryParams]="{ 'search': 'type:auto' }" class="dropdown-item" i18n>Automatic blocks</a>
+ <a [routerLink]="[ '/admin/moderation/video-blocks/list' ]" [queryParams]="{ 'search': 'type:manual' }" class="dropdown-item" i18n>Manual blocks</a>
+ </div>
+ </div>
+ <input
+ type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..."
+ (keyup)="onBlockSearch($event)"
+ >
+ <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetTableFilter()"></a>
+ <span class="sr-only" i18n>Clear filters</span>
+ </div>
+ </div>
+ </div>
+ </ng-template>
+
+ <ng-template pTemplate="header">
+ <tr>
+ <th style="width: 40px"></th>
+ <th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th>
+ <th style="width: 100px;" i18n>Sensitive</th>
+ <th style="width: 120px;" i18n>Unfederated</th>
+ <th style="width: 150px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th>
+ <th style="width: 150px;"></th>
+ </tr>
+ </ng-template>
+
+ <ng-template pTemplate="body" let-videoBlock let-expanded="expanded">
+ <tr>
+ <td *ngIf="!videoBlock.reason"></td>
+ <td *ngIf="videoBlock.reason" class="expand-cell c-hand" [pRowToggler]="videoBlock" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body">
+ <span class="expander">
+ <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i>
+ </span>
+ </td>
+
+ <td>
+ <a [href]="getVideoUrl(videoBlock)" class="video-table-video-link" i18n-title title="Open video in a new tab" target="_blank" rel="noopener noreferrer">
+ <div class="video-table-video">
+ <div class="video-table-video-image">
+ <img [src]="videoBlock.video.thumbnailPath">
+ </div>
+ <div class="video-table-video-text">
+ <div>
+ <my-global-icon i18n-title title="The video was blocked due to automatic blocking of new videos" *ngIf="videoBlock.type == 2" iconName="robot"></my-global-icon>
+ {{ videoBlock.video.name }}
+ </div>
+ <div class="text-muted">by {{ videoBlock.video.channel?.displayName }} on {{ videoBlock.video.channel?.host }} </div>
+ </div>
+ </div>
+ </a>
+ </td>
+
+ <ng-container *ngIf="videoBlock.reason">
+ <td class="c-hand" [pRowToggler]="videoBlock">{{ booleanToText(videoBlock.video.nsfw) }}</td>
+ <td class="c-hand" [pRowToggler]="videoBlock">{{ booleanToText(videoBlock.unfederated) }}</td>
+ <td class="c-hand" [pRowToggler]="videoBlock">{{ videoBlock.createdAt | date: 'short' }}</td>
+ </ng-container>
+ <ng-container *ngIf="!videoBlock.reason">
+ <td>{{ booleanToText(videoBlock.video.nsfw) }}</td>
+ <td>{{ booleanToText(videoBlock.unfederated) }}</td>
+ <td>{{ videoBlock.createdAt | date: 'short' }}</td>
+ </ng-container>
+
+ <td class="action-cell">
+ <my-action-dropdown
+ [ngClass]="{ 'show': expanded }" placement="bottom-right" container="body"
+ i18n-label label="Actions" [actions]="videoBlocklistActions" [entry]="videoBlock"
+ ></my-action-dropdown>
+ </td>
+ </tr>
+ </ng-template>
+
+ <ng-template pTemplate="rowexpansion" let-videoBlock>
+ <tr>
+ <td class="expand-cell" colspan="6">
+ <div class="d-flex moderation-expanded">
+ <span class="col-2 moderation-expanded-label" i18n>Block reason:</span>
+ <span class="col-9 moderation-expanded-text" [innerHTML]="videoBlock.reasonHtml"></span>
+ </div>
+ </td>
+ </tr>
+ </ng-template>
+
+ <ng-template pTemplate="emptymessage">
+ <tr>
+ <td colspan="6">
+ <div class="empty-table-message">
+ <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>
+ </td>
+ </tr>
+ </ng-template>
+</p-table>
+
--- /dev/null
+@import 'mixins';
+
+my-global-icon {
+ @include apply-svg-color(#7d7d7d);
+
+ width: 12px;
+ height: 12px;
+ position: relative;
+ top: -1px;
+}
+
+.input-group {
+ @include peertube-input-group(300px);
+
+ .dropdown-toggle::after {
+ margin-left: 0;
+ }
+}
--- /dev/null
+import { Component, OnInit } from '@angular/core'
+import { SortMeta } from 'primeng/api'
+import { Notifier, ServerService } from '@app/core'
+import { ConfirmService } from '../../../core'
+import { RestPagination, RestTable, VideoBlockService } from '../../../shared'
+import { VideoBlocklist, VideoBlockType } from '../../../../../../shared'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { DropdownAction } from '../../../shared/buttons/action-dropdown.component'
+import { Video } from '../../../shared/video/video.model'
+import { MarkdownService } from '@app/shared/renderer'
+import { Params, ActivatedRoute, Router } from '@angular/router'
+import { filter, switchMap } from 'rxjs/operators'
+import { VideoService } from '@app/shared/video/video.service'
+
+@Component({
+ selector: 'my-video-block-list',
+ templateUrl: './video-block-list.component.html',
+ styleUrls: [ '../moderation.component.scss', './video-block-list.component.scss' ]
+})
+export class VideoBlockListComponent extends RestTable implements OnInit {
+ blocklist: (VideoBlocklist & { reasonHtml?: string })[] = []
+ totalRecords = 0
+ sort: SortMeta = { field: 'createdAt', order: -1 }
+ pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
+ listBlockTypeFilter: VideoBlockType = undefined
+
+ videoBlocklistActions: DropdownAction<VideoBlocklist>[][] = []
+
+ constructor (
+ private notifier: Notifier,
+ private serverService: ServerService,
+ private confirmService: ConfirmService,
+ private videoBlocklistService: VideoBlockService,
+ private markdownRenderer: MarkdownService,
+ private videoService: VideoService,
+ private route: ActivatedRoute,
+ private router: Router,
+ private i18n: I18n
+ ) {
+ super()
+
+ this.videoBlocklistActions = [
+ [
+ {
+ label: this.i18n('Internal actions'),
+ isHeader: true
+ },
+ {
+ label: this.i18n('Switch video block to manual'),
+ handler: videoBlock => {
+ this.videoBlocklistService.unblockVideo(videoBlock.video.id).pipe(
+ switchMap(_ => this.videoBlocklistService.blockVideo(videoBlock.video.id, undefined, true))
+ ).subscribe(
+ () => {
+ this.notifier.success(this.i18n('Video {{name}} switched to manual block.', { name: videoBlock.video.name }))
+ this.loadData()
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+ }
+ ],
+ [
+ {
+ label: this.i18n('Actions for the video'),
+ isHeader: true,
+ },
+ {
+ label: this.i18n('Unblock video'),
+ handler: videoBlock => this.unblockVideo(videoBlock)
+ },
+
+ {
+ label: this.i18n('Delete video'),
+ handler: async videoBlock => {
+ const res = await this.confirmService.confirm(
+ this.i18n('Do you really want to delete this video?'),
+ this.i18n('Delete')
+ )
+ if (res === false) return
+
+ this.videoService.removeVideo(videoBlock.video.id)
+ .subscribe(
+ () => {
+ this.notifier.success(this.i18n('Video deleted.'))
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+ }
+ ]
+ ]
+ }
+
+ ngOnInit () {
+ this.serverService.getConfig()
+ .subscribe(config => {
+ // don't filter if auto-blacklist is not enabled as this will be the only list
+ if (config.autoBlacklist.videos.ofUsers.enabled) {
+ this.listBlockTypeFilter = VideoBlockType.MANUAL
+ }
+ })
+
+ this.initialize()
+
+ this.route.queryParams
+ .pipe(filter(params => params.search !== undefined && params.search !== null))
+ .subscribe(params => {
+ this.search = params.search
+ this.setTableFilter(params.search)
+ this.loadData()
+ })
+ }
+
+ ngAfterViewInit () {
+ if (this.search) this.setTableFilter(this.search)
+ }
+
+ /* Table filter functions */
+ onBlockSearch (event: Event) {
+ this.onSearch(event)
+ this.setQueryParams((event.target as HTMLInputElement).value)
+ }
+
+ setQueryParams (search: string) {
+ const queryParams: Params = {}
+ if (search) Object.assign(queryParams, { search })
+ this.router.navigate([ '/admin/moderation/video-blocks/list' ], { queryParams })
+ }
+
+ resetTableFilter () {
+ this.setTableFilter('')
+ this.setQueryParams('')
+ this.resetSearch()
+ }
+ /* END Table filter functions */
+
+ getIdentifier () {
+ return 'VideoBlockListComponent'
+ }
+
+ getVideoUrl (videoBlock: VideoBlocklist) {
+ return Video.buildClientUrl(videoBlock.video.uuid)
+ }
+
+ booleanToText (value: boolean) {
+ if (value === true) return this.i18n('yes')
+
+ return this.i18n('no')
+ }
+
+ toHtml (text: string) {
+ return this.markdownRenderer.textMarkdownToHTML(text)
+ }
+
+ async unblockVideo (entry: VideoBlocklist) {
+ const confirmMessage = this.i18n(
+ 'Do you really want to unblock this video? It will be available again in the videos list.'
+ )
+
+ const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblock'))
+ if (res === false) return
+
+ this.videoBlocklistService.unblockVideo(entry.video.id).subscribe(
+ () => {
+ this.notifier.success(this.i18n('Video {{name}} unblocked.', { name: entry.video.name }))
+ this.loadData()
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+
+ protected loadData () {
+ this.videoBlocklistService.listBlocks({
+ pagination: this.pagination,
+ sort: this.sort,
+ search: this.search,
+ })
+ .subscribe(
+ async resultList => {
+ this.totalRecords = resultList.total
+
+ this.blocklist = resultList.data
+
+ for (const element of this.blocklist) {
+ Object.assign(element, { reasonHtml: await this.toHtml(element.reason) })
+ }
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+}
}
protected buildAdminFlags (formValue: any) {
- return formValue.byPassAutoBlacklist ? UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST : UserAdminFlag.NONE
+ return formValue.byPassAutoBlacklist ? UserAdminFlag.BYPASS_VIDEO_AUTO_BLOCK : UserAdminFlag.NONE
}
protected buildQuotaOptions () {
role: userJson.role.toString(),
videoQuota: userJson.videoQuota,
videoQuotaDaily: userJson.videoQuotaDaily,
- byPassAutoBlacklist: userJson.adminFlags & UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST
+ byPassAutoBlacklist: userJson.adminFlags & UserAdminFlag.BYPASS_VIDEO_AUTO_BLOCK
})
}
}
<div class="video" *ngFor="let video of videos">
<my-video-miniature
[video]="video" [displayAsRow]="true"
- (videoRemoved)="removeVideoFromArray(video)" (videoBlacklisted)="removeVideoFromArray(video)"></my-video-miniature>
+ (videoRemoved)="removeVideoFromArray(video)" (videoBlocked)="removeVideoFromArray(video)"></my-video-miniature>
</div>
</div>
newVideoFromSubscription: this.i18n('New video from your subscriptions'),
newCommentOnMyVideo: this.i18n('New comment on your video'),
videoAbuseAsModerator: this.i18n('New video abuse'),
- videoAutoBlacklistAsModerator: this.i18n('Video auto-blacklisted waiting review'),
- blacklistOnMyVideo: this.i18n('One of your video is blacklisted/unblacklisted'),
+ videoAutoBlacklistAsModerator: this.i18n('Video blocked automatically waiting review'),
+ blacklistOnMyVideo: this.i18n('One of your video is blocked/unblocked'),
myVideoPublished: this.i18n('Video published (after transcoding/scheduled update)'),
myVideoImportFinished: this.i18n('Video import finished'),
newUserRegistration: this.i18n('A new user registered on your instance'),
this.rightNotifications = {
videoAbuseAsModerator: UserRight.MANAGE_VIDEO_ABUSES,
- videoAutoBlacklistAsModerator: UserRight.MANAGE_VIDEO_BLACKLIST,
+ videoAutoBlacklistAsModerator: UserRight.MANAGE_VIDEO_BLOCKS,
newUserRegistration: UserRight.MANAGE_USERS,
newInstanceFollower: UserRight.MANAGE_SERVER_FOLLOW,
autoInstanceFollowing: UserRight.MANAGE_CONFIGURATION
[UserRight.MANAGE_USERS]: '/admin/users',
[UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
[UserRight.MANAGE_VIDEO_ABUSES]: '/admin/moderation/video-abuses',
- [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/moderation/video-blacklist',
+ [UserRight.MANAGE_VIDEO_BLOCKS]: '/admin/moderation/video-blocks',
[UserRight.MANAGE_JOBS]: '/admin/jobs',
[UserRight.MANAGE_CONFIGURATION]: '/admin/config'
}
UserRight.MANAGE_USERS,
UserRight.MANAGE_SERVER_FOLLOW,
UserRight.MANAGE_VIDEO_ABUSES,
- UserRight.MANAGE_VIDEO_BLACKLIST,
+ UserRight.MANAGE_VIDEO_BLOCKS,
UserRight.MANAGE_JOBS,
UserRight.MANAGE_CONFIGURATION
]
<my-video-miniature
[video]="result" [user]="user" [displayAsRow]="true" [displayVideoActions]="!hideActions()"
[useLazyLoadUrl]="advancedSearch.searchTarget === 'search-index'"
- (videoBlacklisted)="removeVideoFromArray(result)" (videoRemoved)="removeVideoFromArray(result)"
+ (videoBlocked)="removeVideoFromArray(result)" (videoRemoved)="removeVideoFromArray(result)"
></my-video-miniature>
</div>
</ng-container>
export * from './reset-password-validators.service'
export * from './user-validators.service'
export * from './video-abuse-validators.service'
-export * from './video-blacklist-validators.service'
+export * from './video-block-validators.service'
export * from './video-channel-validators.service'
export * from './video-comment-validators.service'
export * from './video-validators.service'
+++ /dev/null
-import { I18n } from '@ngx-translate/i18n-polyfill'
-import { Validators } from '@angular/forms'
-import { Injectable } from '@angular/core'
-import { BuildFormValidator } from '@app/shared'
-
-@Injectable()
-export class VideoBlacklistValidatorsService {
- readonly VIDEO_BLACKLIST_REASON: BuildFormValidator
-
- constructor (private i18n: I18n) {
- this.VIDEO_BLACKLIST_REASON = {
- VALIDATORS: [ Validators.minLength(2), Validators.maxLength(300) ],
- MESSAGES: {
- 'minlength': this.i18n('Blacklist reason must be at least 2 characters long.'),
- 'maxlength': this.i18n('Blacklist reason cannot be more than 300 characters long.')
- }
- }
- }
-}
--- /dev/null
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { Validators } from '@angular/forms'
+import { Injectable } from '@angular/core'
+import { BuildFormValidator } from '@app/shared'
+
+@Injectable()
+export class VideoBlockValidatorsService {
+ readonly VIDEO_BLOCK_REASON: BuildFormValidator
+
+ constructor (private i18n: I18n) {
+ this.VIDEO_BLOCK_REASON = {
+ VALIDATORS: [ Validators.minLength(2), Validators.maxLength(300) ],
+ MESSAGES: {
+ 'minlength': this.i18n('Block reason must be at least 2 characters long.'),
+ 'maxlength': this.i18n('Block reason cannot be more than 300 characters long.')
+ }
+ }
+ }
+}
'refresh': require('!!raw-loader?!../../../assets/images/global/refresh.svg').default,
'npm': require('!!raw-loader?!../../../assets/images/global/npm.svg').default,
'fullscreen': require('!!raw-loader?!../../../assets/images/global/fullscreen.svg').default,
- 'exit-fullscreen': require('!!raw-loader?!../../../assets/images/global/exit-fullscreen.svg').default
+ 'exit-fullscreen': require('!!raw-loader?!../../../assets/images/global/exit-fullscreen.svg').default,
+ 'robot': require('!!raw-loader?!../../../assets/images/global/robot.svg').default
}
export type GlobalIconName = keyof typeof icons
export * from './rest'
export * from './users'
export * from './video-abuse'
-export * from './video-blacklist'
+export * from './video-block'
export * from './shared.module'
UserValidatorsService,
VideoAbuseValidatorsService,
VideoAcceptOwnershipValidatorsService,
- VideoBlacklistValidatorsService,
+ VideoBlockValidatorsService,
VideoChangeOwnershipValidatorsService,
VideoChannelValidatorsService,
VideoCommentValidatorsService,
import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component'
import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service'
import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive'
-import { VideoBlacklistComponent } from '@app/shared/video/modals/video-blacklist.component'
+import { VideoBlockComponent } from '@app/shared/video/modals/video-block.component'
import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component'
import { VideoReportComponent } from '@app/shared/video/modals/video-report.component'
import { RedundancyService } from '@app/shared/video/redundancy.service'
import { RestExtractor, RestService } from './rest'
import { UserService } from './users'
import { VideoAbuseService } from './video-abuse'
-import { VideoBlacklistService } from './video-blacklist'
+import { VideoBlockService } from './video-block'
import { VideoOwnershipService } from './video-ownership'
import { FeedComponent } from './video/feed.component'
import { VideoMiniatureComponent } from './video/video-miniature.component'
VideoDownloadComponent,
VideoReportComponent,
- VideoBlacklistComponent,
+ VideoBlockComponent,
FeedComponent,
VideoDownloadComponent,
VideoReportComponent,
- VideoBlacklistComponent,
+ VideoBlockComponent,
FeedComponent,
RestExtractor,
RestService,
VideoAbuseService,
- VideoBlacklistService,
+ VideoBlockService,
VideoOwnershipService,
UserService,
VideoService,
VideoCommentValidatorsService,
VideoValidatorsService,
VideoCaptionsValidatorsService,
- VideoBlacklistValidatorsService,
+ VideoBlockValidatorsService,
OverviewService,
VideoChangeOwnershipValidatorsService,
VideoAcceptOwnershipValidatorsService,
this.videoUrl = this.buildVideoUrl(this.video)
break
- case UserNotificationType.UNBLACKLIST_ON_MY_VIDEO:
+ case UserNotificationType.UNBLOCK_ON_MY_VIDEO:
this.videoUrl = this.buildVideoUrl(this.video)
break
this.videoUrl = this.buildVideoUrl(this.videoAbuse.video)
break
- case UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS:
+ case UserNotificationType.VIDEO_AUTO_BLOCK_FOR_MODERATORS:
this.videoAutoBlacklistUrl = '/admin/moderation/video-auto-blacklist/list'
// Backward compatibility where we did not assign videoBlacklist to this type of notification before
if (!this.videoBlacklist) this.videoBlacklist = { id: null, video: this.video }
this.videoUrl = this.buildVideoUrl(this.videoBlacklist.video)
break
- case UserNotificationType.BLACKLIST_ON_MY_VIDEO:
+ case UserNotificationType.BLOCK_ON_MY_VIDEO:
this.videoUrl = this.buildVideoUrl(this.videoBlacklist.video)
break
</ng-template>
</ng-container>
- <ng-container *ngSwitchCase="UserNotificationType.UNBLACKLIST_ON_MY_VIDEO">
+ <ng-container *ngSwitchCase="UserNotificationType.UNBLOCK_ON_MY_VIDEO">
<my-global-icon iconName="undo"></my-global-icon>
<div class="message" i18n>
- Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.video.name }}</a> has been unblacklisted
+ Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.video.name }}</a> has been unblocked
</div>
</ng-container>
- <ng-container *ngSwitchCase="UserNotificationType.BLACKLIST_ON_MY_VIDEO">
+ <ng-container *ngSwitchCase="UserNotificationType.BLOCK_ON_MY_VIDEO">
<my-global-icon iconName="no"></my-global-icon>
<div class="message" i18n>
- Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.videoBlacklist.video.name }}</a> has been blacklisted
+ Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.videoBlacklist.video.name }}</a> has been blocked
</div>
</ng-container>
</div>
</ng-container>
- <ng-container *ngSwitchCase="UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS">
+ <ng-container *ngSwitchCase="UserNotificationType.VIDEO_AUTO_BLOCK_FOR_MODERATORS">
<my-global-icon iconName="no"></my-global-icon>
<div class="message" i18n>
- The recently added video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.videoBlacklist.video.name }}</a> has been <a (click)="markAsRead(notification)" [routerLink]="notification.videoAutoBlacklistUrl">auto-blacklisted</a>
+ The recently added video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.videoBlacklist.video.name }}</a> has been <a (click)="markAsRead(notification)" [routerLink]="notification.videoAutoBlacklistUrl">auto-blocked</a>
</div>
</ng-container>
+++ /dev/null
-export * from './video-blacklist.service'
+++ /dev/null
-import { catchError, map, concatMap, toArray } from 'rxjs/operators'
-import { HttpClient, HttpParams } from '@angular/common/http'
-import { Injectable } from '@angular/core'
-import { SortMeta } from 'primeng/api'
-import { from as observableFrom, Observable } from 'rxjs'
-import { VideoBlacklist, VideoBlacklistType, ResultList } from '../../../../../shared'
-import { Video } from '../video/video.model'
-import { environment } from '../../../environments/environment'
-import { RestExtractor, RestPagination, RestService } from '../rest'
-import { ComponentPaginationLight } from '../rest/component-pagination.model'
-
-@Injectable()
-export class VideoBlacklistService {
- private static BASE_VIDEOS_URL = environment.apiUrl + '/api/v1/videos/'
-
- constructor (
- private authHttp: HttpClient,
- private restService: RestService,
- private restExtractor: RestExtractor
- ) {}
-
- listBlacklist (options: {
- pagination: RestPagination,
- sort: SortMeta,
- search?: string
- type?: VideoBlacklistType
- }): Observable<ResultList<VideoBlacklist>> {
- const { pagination, sort, search, type } = options
-
- let params = new HttpParams()
- params = this.restService.addRestGetParams(params, pagination, sort)
-
- if (search) params = params.append('search', search)
- if (type) params = params.append('type', type.toString())
-
- return this.authHttp.get<ResultList<VideoBlacklist>>(VideoBlacklistService.BASE_VIDEOS_URL + 'blacklist', { params })
- .pipe(
- map(res => this.restExtractor.convertResultListDateToHuman(res)),
- catchError(res => this.restExtractor.handleError(res))
- )
- }
-
- getAutoBlacklistedAsVideoList (videoPagination: ComponentPaginationLight): Observable<ResultList<Video>> {
- const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
-
- // prioritize first created since waiting longest
- const AUTO_BLACKLIST_SORT = 'createdAt'
-
- let params = new HttpParams()
- params = this.restService.addRestGetParams(params, pagination, AUTO_BLACKLIST_SORT)
-
- params = params.set('type', VideoBlacklistType.AUTO_BEFORE_PUBLISHED.toString())
-
- return this.authHttp.get<ResultList<VideoBlacklist>>(VideoBlacklistService.BASE_VIDEOS_URL + 'blacklist', { params })
- .pipe(
- map(res => {
- return {
- total: res.total,
- data: res.data.map(videoBlacklist => new Video(videoBlacklist.video))
- }
- }),
- catchError(res => this.restExtractor.handleError(res))
- )
- }
-
- removeVideoFromBlacklist (videoIdArgs: number | number[]) {
- const videoIds = Array.isArray(videoIdArgs) ? videoIdArgs : [ videoIdArgs ]
-
- return observableFrom(videoIds)
- .pipe(
- concatMap(id => this.authHttp.delete(VideoBlacklistService.BASE_VIDEOS_URL + id + '/blacklist')),
- toArray(),
- catchError(err => this.restExtractor.handleError(err))
- )
- }
-
- blacklistVideo (videoId: number, reason: string, unfederate: boolean) {
- const body = {
- unfederate,
- reason
- }
-
- return this.authHttp.post(VideoBlacklistService.BASE_VIDEOS_URL + videoId + '/blacklist', body)
- .pipe(
- map(this.restExtractor.extractDataBool),
- catchError(res => this.restExtractor.handleError(res))
- )
- }
-}
--- /dev/null
+export * from './video-block.service'
--- /dev/null
+import { catchError, map, concatMap, toArray } from 'rxjs/operators'
+import { HttpClient, HttpParams } from '@angular/common/http'
+import { Injectable } from '@angular/core'
+import { SortMeta } from 'primeng/api'
+import { from as observableFrom, Observable } from 'rxjs'
+import { VideoBlocklist, VideoBlockType, ResultList } from '../../../../../shared'
+import { environment } from '../../../environments/environment'
+import { RestExtractor, RestPagination, RestService } from '../rest'
+
+@Injectable()
+export class VideoBlockService {
+ private static BASE_VIDEOS_URL = environment.apiUrl + '/api/v1/videos/'
+
+ constructor (
+ private authHttp: HttpClient,
+ private restService: RestService,
+ private restExtractor: RestExtractor
+ ) {}
+
+ listBlocks (options: {
+ pagination: RestPagination
+ sort: SortMeta
+ search?: string
+ type?: VideoBlockType
+ }): Observable<ResultList<VideoBlocklist>> {
+ const { pagination, sort, search, type } = options
+
+ let params = new HttpParams()
+ params = this.restService.addRestGetParams(params, pagination, sort)
+
+ if (search) {
+ const filters = this.restService.parseQueryStringFilter(search, {
+ type: {
+ prefix: 'type:',
+ handler: v => {
+ if (v === 'manual') return VideoBlockType.MANUAL
+ if (v === 'auto') return VideoBlockType.AUTO_BEFORE_PUBLISHED
+
+ return undefined
+ }
+ }
+ })
+
+ params = this.restService.addObjectParams(params, filters)
+ }
+
+ return this.authHttp.get<ResultList<VideoBlocklist>>(VideoBlockService.BASE_VIDEOS_URL + 'blacklist', { params })
+ .pipe(
+ map(res => this.restExtractor.convertResultListDateToHuman(res)),
+ catchError(res => this.restExtractor.handleError(res))
+ )
+ }
+
+ unblockVideo (videoIdArgs: number | number[]) {
+ const videoIds = Array.isArray(videoIdArgs) ? videoIdArgs : [ videoIdArgs ]
+
+ return observableFrom(videoIds)
+ .pipe(
+ concatMap(id => this.authHttp.delete(VideoBlockService.BASE_VIDEOS_URL + id + '/blacklist')),
+ toArray(),
+ catchError(err => this.restExtractor.handleError(err))
+ )
+ }
+
+ blockVideo (videoId: number, reason: string, unfederate: boolean) {
+ const body = {
+ unfederate,
+ reason
+ }
+
+ return this.authHttp.post(VideoBlockService.BASE_VIDEOS_URL + videoId + '/blacklist', body)
+ .pipe(
+ map(this.restExtractor.extractDataBool),
+ catchError(res => this.restExtractor.handleError(res))
+ )
+ }
+}
[fitWidth]="true"
[video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType"
[displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions"
- (videoBlacklisted)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)"
+ (videoBlocked)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)"
>
</my-video-miniature>
</ng-container>
+++ /dev/null
-<ng-template #modal>
- <div class="modal-header">
- <h4 i18n class="modal-title">Blacklist video</h4>
- <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
- </div>
-
- <div class="modal-body">
-
- <form novalidate [formGroup]="form" (ngSubmit)="blacklist()">
- <div class="form-group">
- <textarea
- i18n-placeholder placeholder="Reason..." formControlName="reason"
- [ngClass]="{ 'input-error': formErrors['reason'] }" class="form-control"
- ></textarea>
- <div *ngIf="formErrors.reason" class="form-error">
- {{ formErrors.reason }}
- </div>
- </div>
-
- <div class="form-group" *ngIf="video.isLocal">
- <my-peertube-checkbox
- inputName="unfederate" formControlName="unfederate"
- i18n-labelText labelText="Unfederate the video"
- >
- <ng-container ngProjectAs="description">
- <span i18n>This will ask remote instances to delete it</span>
- </ng-container>
- </my-peertube-checkbox>
- </div>
-
- <div class="form-group inputs">
- <input
- type="button" role="button" i18n-value value="Cancel" class="action-button action-button-cancel"
- (click)="hide()" (key.enter)="hide()"
- >
-
- <input
- type="submit" i18n-value value="Submit" class="action-button-submit"
- [disabled]="!form.valid"
- >
- </div>
- </form>
-
- </div>
-</ng-template>
+++ /dev/null
-@import 'variables';
-@import 'mixins';
-
-textarea {
- @include peertube-textarea(100%, 100px);
-}
+++ /dev/null
-import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
-import { Notifier, RedirectService } from '@app/core'
-import { VideoBlacklistService } from '../../../shared/video-blacklist'
-import { I18n } from '@ngx-translate/i18n-polyfill'
-import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
-import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
-import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
-import { FormReactive, VideoBlacklistValidatorsService } from '@app/shared/forms'
-import { Video } from '@app/shared/video/video.model'
-
-@Component({
- selector: 'my-video-blacklist',
- templateUrl: './video-blacklist.component.html',
- styleUrls: [ './video-blacklist.component.scss' ]
-})
-export class VideoBlacklistComponent extends FormReactive implements OnInit {
- @Input() video: Video = null
-
- @ViewChild('modal', { static: true }) modal: NgbModal
-
- @Output() videoBlacklisted = new EventEmitter()
-
- error: string = null
-
- private openedModal: NgbModalRef
-
- constructor (
- protected formValidatorService: FormValidatorService,
- private modalService: NgbModal,
- private videoBlacklistValidatorsService: VideoBlacklistValidatorsService,
- private videoBlacklistService: VideoBlacklistService,
- private notifier: Notifier,
- private redirectService: RedirectService,
- private i18n: I18n
- ) {
- super()
- }
-
- ngOnInit () {
- const defaultValues = { unfederate: 'true' }
-
- this.buildForm({
- reason: this.videoBlacklistValidatorsService.VIDEO_BLACKLIST_REASON,
- unfederate: null
- }, defaultValues)
- }
-
- show () {
- this.openedModal = this.modalService.open(this.modal, { centered: true, keyboard: false })
- }
-
- hide () {
- this.openedModal.close()
- this.openedModal = null
- }
-
- blacklist () {
- const reason = this.form.value[ 'reason' ] || undefined
- const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined
-
- this.videoBlacklistService.blacklistVideo(this.video.id, reason, unfederate)
- .subscribe(
- () => {
- this.notifier.success(this.i18n('Video blacklisted.'))
- this.hide()
-
- this.video.blacklisted = true
- this.video.blacklistedReason = reason
-
- this.videoBlacklisted.emit()
- },
-
- err => this.notifier.error(err.message)
- )
- }
-}
--- /dev/null
+<ng-template #modal>
+ <div class="modal-header">
+ <h4 i18n class="modal-title">Blocklist video</h4>
+ <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
+ </div>
+
+ <div class="modal-body">
+
+ <form novalidate [formGroup]="form" (ngSubmit)="block()">
+ <div class="form-group">
+ <textarea
+ i18n-placeholder placeholder="Reason..." formControlName="reason"
+ [ngClass]="{ 'input-error': formErrors['reason'] }" class="form-control"
+ ></textarea>
+ <div *ngIf="formErrors.reason" class="form-error">
+ {{ formErrors.reason }}
+ </div>
+ </div>
+
+ <div class="form-group" *ngIf="video.isLocal">
+ <my-peertube-checkbox
+ inputName="unfederate" formControlName="unfederate"
+ i18n-labelText labelText="Unfederate the video"
+ >
+ <ng-container ngProjectAs="description">
+ <span i18n>This will ask remote instances to delete it</span>
+ </ng-container>
+ </my-peertube-checkbox>
+ </div>
+
+ <div class="form-group inputs">
+ <input
+ type="button" role="button" i18n-value value="Cancel" class="action-button action-button-cancel"
+ (click)="hide()" (key.enter)="hide()"
+ >
+
+ <input
+ type="submit" i18n-value value="Submit" class="action-button-submit"
+ [disabled]="!form.valid"
+ >
+ </div>
+ </form>
+
+ </div>
+</ng-template>
--- /dev/null
+@import 'variables';
+@import 'mixins';
+
+textarea {
+ @include peertube-textarea(100%, 100px);
+}
--- /dev/null
+import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'
+import { Notifier, RedirectService } from '@app/core'
+import { VideoBlockService } from '../../video-block'
+import { I18n } from '@ngx-translate/i18n-polyfill'
+import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service'
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
+import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
+import { FormReactive, VideoBlockValidatorsService } from '@app/shared/forms'
+import { Video } from '@app/shared/video/video.model'
+
+@Component({
+ selector: 'my-video-block',
+ templateUrl: './video-block.component.html',
+ styleUrls: [ './video-block.component.scss' ]
+})
+export class VideoBlockComponent extends FormReactive implements OnInit {
+ @Input() video: Video = null
+
+ @ViewChild('modal', { static: true }) modal: NgbModal
+
+ @Output() videoBlocked = new EventEmitter()
+
+ error: string = null
+
+ private openedModal: NgbModalRef
+
+ constructor (
+ protected formValidatorService: FormValidatorService,
+ private modalService: NgbModal,
+ private videoBlockValidatorsService: VideoBlockValidatorsService,
+ private videoBlocklistService: VideoBlockService,
+ private notifier: Notifier,
+ private i18n: I18n
+ ) {
+ super()
+ }
+
+ ngOnInit () {
+ const defaultValues = { unfederate: 'true' }
+
+ this.buildForm({
+ reason: this.videoBlockValidatorsService.VIDEO_BLOCK_REASON,
+ unfederate: null
+ }, defaultValues)
+ }
+
+ show () {
+ this.openedModal = this.modalService.open(this.modal, { centered: true, keyboard: false })
+ }
+
+ hide () {
+ this.openedModal.close()
+ this.openedModal = null
+ }
+
+ block () {
+ const reason = this.form.value[ 'reason' ] || undefined
+ const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined
+
+ this.videoBlocklistService.blockVideo(this.video.id, reason, unfederate)
+ .subscribe(
+ () => {
+ this.notifier.success(this.i18n('Video blocked.'))
+ this.hide()
+
+ this.video.blacklisted = true
+ this.video.blockedReason = reason
+
+ this.videoBlocked.emit()
+ },
+
+ err => this.notifier.error(err.message)
+ )
+ }
+}
<my-video-download #videoDownloadModal></my-video-download>
<my-video-report #videoReportModal [video]="video"></my-video-report>
- <my-video-blacklist #videoBlacklistModal [video]="video" (videoBlacklisted)="onVideoBlacklisted()"></my-video-blacklist>
+ <my-video-block #videoBlockModal [video]="video" (videoBlocked)="onVideoBlocked()"></my-video-block>
</ng-container>
import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component'
import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component'
import { VideoReportComponent } from '@app/shared/video/modals/video-report.component'
-import { VideoBlacklistComponent } from '@app/shared/video/modals/video-blacklist.component'
-import { VideoBlacklistService } from '@app/shared/video-blacklist'
+import { VideoBlockComponent } from '@app/shared/video/modals/video-block.component'
+import { VideoBlockService } from '@app/shared/video-block'
import { ScreenService } from '@app/shared/misc/screen.service'
import { VideoCaption } from '@shared/models'
import { RedundancyService } from '@app/shared/video/redundancy.service'
@ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent
@ViewChild('videoReportModal') videoReportModal: VideoReportComponent
- @ViewChild('videoBlacklistModal') videoBlacklistModal: VideoBlacklistComponent
+ @ViewChild('videoBlockModal') videoBlockModal: VideoBlockComponent
@Input() video: Video | VideoDetails
@Input() videoCaptions: VideoCaption[] = []
@Input() buttonDirection: DropdownDirection = 'vertical'
@Output() videoRemoved = new EventEmitter()
- @Output() videoUnblacklisted = new EventEmitter()
- @Output() videoBlacklisted = new EventEmitter()
+ @Output() videoUnblocked = new EventEmitter()
+ @Output() videoBlocked = new EventEmitter()
@Output() modalOpened = new EventEmitter()
videoActions: DropdownAction<{ video: Video }>[][] = []
private authService: AuthService,
private notifier: Notifier,
private confirmService: ConfirmService,
- private videoBlacklistService: VideoBlacklistService,
+ private videoBlocklistService: VideoBlockService,
private screenService: ScreenService,
private videoService: VideoService,
private redundancyService: RedundancyService,
this.videoReportModal.show()
}
- showBlacklistModal () {
+ showBlockModal () {
this.modalOpened.emit()
- this.videoBlacklistModal.show()
+ this.videoBlockModal.show()
}
/* Actions checker */
return this.video.isRemovableBy(this.user)
}
- isVideoBlacklistable () {
- return this.video.isBlackistableBy(this.user)
+ isVideoBlockable () {
+ return this.video.isBlockableBy(this.user)
}
- isVideoUnblacklistable () {
- return this.video.isUnblacklistableBy(this.user)
+ isVideoUnblockable () {
+ return this.video.isUnblockableBy(this.user)
}
isVideoDownloadable () {
/* Action handlers */
- async unblacklistVideo () {
+ async unblockVideo () {
const confirmMessage = this.i18n(
- 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.'
+ 'Do you really want to unblock this video? It will be available again in the videos list.'
)
- const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblacklist'))
+ const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblock'))
if (res === false) return
- this.videoBlacklistService.removeVideoFromBlacklist(this.video.id).subscribe(
+ this.videoBlocklistService.unblockVideo(this.video.id).subscribe(
() => {
- this.notifier.success(this.i18n('Video {{name}} removed from the blacklist.', { name: this.video.name }))
+ this.notifier.success(this.i18n('Video {{name}} unblocked.', { name: this.video.name }))
this.video.blacklisted = false
- this.video.blacklistedReason = null
+ this.video.blockedReason = null
- this.videoUnblacklisted.emit()
+ this.videoUnblocked.emit()
},
err => this.notifier.error(err.message)
)
}
- onVideoBlacklisted () {
- this.videoBlacklisted.emit()
+ onVideoBlocked () {
+ this.videoBlocked.emit()
}
getPlaylistDropdownPlacement () {
isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.update && this.isVideoUpdatable()
},
{
- label: this.i18n('Blacklist'),
- handler: () => this.showBlacklistModal(),
+ label: this.i18n('Block'),
+ handler: () => this.showBlockModal(),
iconName: 'no',
- isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoBlacklistable()
+ isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoBlockable()
},
{
- label: this.i18n('Unblacklist'),
- handler: () => this.unblacklistVideo(),
+ label: this.i18n('Unblock'),
+ handler: () => this.unblockVideo(),
iconName: 'undo',
- isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoUnblacklistable()
+ isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoUnblockable()
},
{
label: this.i18n('Mirror'),
</div>
</div>
- <div *ngIf="displayOptions.blacklistInfo && video.blacklisted" class="video-info-blacklisted">
- <span class="blacklisted-label" i18n>Blacklisted</span>
- <span class="blacklisted-reason" *ngIf="video.blacklistedReason">{{ video.blacklistedReason }}</span>
+ <div *ngIf="displayOptions.blacklistInfo && video.blacklisted" class="video-info-blocked">
+ <span class="blocked-label" i18n>Blocked</span>
+ <span class="blocked-reason" *ngIf="video.blockedReason">{{ video.blockedReason }}</span>
</div>
<div i18n *ngIf="displayOptions.nsfw && video.nsfw" class="video-info-nsfw">
<!-- FIXME: remove bottom placement when overflow is fixed in bootstrap dropdown: https://github.com/ng-bootstrap/ng-bootstrap/issues/3495 -->
<my-video-actions-dropdown
*ngIf="showActions" [video]="video" [displayOptions]="videoActionsDisplayOptions" placement="bottom-left bottom-right left auto"
- (videoRemoved)="onVideoRemoved()" (videoBlacklisted)="onVideoBlacklisted()" (videoUnblacklisted)="onVideoUnblacklisted()"
+ (videoRemoved)="onVideoRemoved()" (videoBlocked)="onVideoBlocked()" (videoUnblocked)="onVideoUnblocked()"
></my-video-actions-dropdown>
</div>
</div>
}
.video-info-privacy,
- .video-info-blacklisted .blacklisted-label,
+ .video-info-blocked .blocked-label,
.video-info-nsfw {
font-weight: $font-semibold;
}
- .video-info-blacklisted {
+ .video-info-blocked {
color: red;
- .blacklisted-reason::before {
+ .blocked-reason::before {
content: ' - ';
}
}
margin-top: 5px;
}
- .video-info-blacklisted {
+ .video-info-blocked {
margin-top: 3px;
}
}
@Input() useLazyLoadUrl = false
- @Output() videoBlacklisted = new EventEmitter()
- @Output() videoUnblacklisted = new EventEmitter()
+ @Output() videoBlocked = new EventEmitter()
+ @Output() videoUnblocked = new EventEmitter()
@Output() videoRemoved = new EventEmitter()
videoActionsDisplayOptions: VideoActionsDisplayType = {
this.loadWatchLater()
}
- onVideoBlacklisted () {
- this.videoBlacklisted.emit()
+ onVideoBlocked () {
+ this.videoBlocked.emit()
}
- onVideoUnblacklisted () {
- this.videoUnblacklisted.emit()
+ onVideoUnblocked () {
+ this.videoUnblocked.emit()
}
onVideoRemoved () {
state?: VideoConstant<VideoState>
scheduledUpdate?: VideoScheduleUpdate
blacklisted?: boolean
- blacklistedReason?: string
+ blockedReason?: string
account: {
id: number
if (this.state) this.state.label = peertubeTranslate(this.state.label, translations)
this.blacklisted = hash.blacklisted
- this.blacklistedReason = hash.blacklistedReason
+ this.blockedReason = hash.blacklistedReason
this.userHistory = hash.userHistory
return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO))
}
- isBlackistableBy (user: AuthUser) {
- return this.blacklisted !== true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) === true
+ isBlockableBy (user: AuthUser) {
+ return this.blacklisted !== true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLOCKS) === true
}
- isUnblacklistableBy (user: AuthUser) {
- return this.blacklisted === true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) === true
+ isUnblockableBy (user: AuthUser) {
+ return this.blacklisted === true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLOCKS) === true
}
isUpdatableBy (user: AuthUser) {
</div>
<div class="col-md-12 alert alert-danger" *ngIf="video?.blacklisted">
- <div class="blacklisted-label" i18n>This video is blacklisted.</div>
- {{ video.blacklistedReason }}
+ <div class="blocked-label" i18n>This video is blocked.</div>
+ {{ video.blockedReason }}
</div>
</div>
}
}
-.blacklisted-label {
+.blocked-label {
font-weight: $font-semibold;
}
this.videoCaptionService.listCaptions(videoId)
])
.pipe(
- // If 401, the video is private or blacklisted so redirect to 404
+ // If 401, the video is private or blocklisted so redirect to 404
catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ]))
)
.subscribe(([ video, captionsResult ]) => {
this.playlistService.getVideoPlaylist(playlistId)
.pipe(
- // If 401, the video is private or blacklisted so redirect to 404
+ // If 401, the video is private or blocklisted so redirect to 404
catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ]))
)
.subscribe(playlist => {
</div>
<div *ngFor="let video of (videos$ | async); let i = index; let length = count">
- <my-video-miniature [displayOptions]="displayOptions" [video]="video" [user]="user" (videoBlacklisted)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()">
+ <my-video-miniature [displayOptions]="displayOptions" [video]="video" [user]="user" (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()">
</my-video-miniature>
<hr *ngIf="!playlist && i == 0 && length > 1" />
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" viewBox="0 0 24 24">
+ <defs/>
+ <g fill="none" fill-rule="evenodd">
+ <rect width="22" height="14" x="1" y="7" stroke="#000" stroke-width="2" rx="2"/>
+ <path fill="#000" d="M11 3h2v4h-2z"/>
+ <circle cx="12" cy="2" r="2" fill="#000"/>
+ <circle cx="18" cy="12" r="2" fill="#000"/>
+ <circle cx="6" cy="12" r="2" fill="#000"/>
+ <path stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 15c0 1.1.9 2 2 2h0a2 2 0 002-2"/>
+ </g>
+</svg>
blacklistRouter.post('/:videoId/blacklist',
authenticate,
- ensureUserHasRight(UserRight.MANAGE_VIDEO_BLACKLIST),
+ ensureUserHasRight(UserRight.MANAGE_VIDEO_BLOCKS),
asyncMiddleware(videosBlacklistAddValidator),
asyncMiddleware(addVideoToBlacklistController)
)
blacklistRouter.get('/blacklist',
authenticate,
- ensureUserHasRight(UserRight.MANAGE_VIDEO_BLACKLIST),
+ ensureUserHasRight(UserRight.MANAGE_VIDEO_BLOCKS),
paginationValidator,
blacklistSortValidator,
setBlacklistSort,
blacklistRouter.put('/:videoId/blacklist',
authenticate,
- ensureUserHasRight(UserRight.MANAGE_VIDEO_BLACKLIST),
+ ensureUserHasRight(UserRight.MANAGE_VIDEO_BLOCKS),
asyncMiddleware(videosBlacklistUpdateValidator),
asyncMiddleware(updateVideoBlacklistController)
)
blacklistRouter.delete('/:videoId/blacklist',
authenticate,
- ensureUserHasRight(UserRight.MANAGE_VIDEO_BLACKLIST),
+ ensureUserHasRight(UserRight.MANAGE_VIDEO_BLOCKS),
asyncMiddleware(videosBlacklistRemoveValidator),
asyncMiddleware(removeVideoFromBlacklistController)
)
import validator from 'validator'
import { exists } from './misc'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
-import { VideoBlacklistType } from '../../../shared/models/videos'
+import { VideoBlockType } from '../../../shared/models/videos'
const VIDEO_BLACKLIST_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_BLACKLIST
}
function isVideoBlacklistTypeValid (value: any) {
- return exists(value) && validator.isInt('' + value) && VideoBlacklistType[value] !== undefined
+ return exists(value) && validator.isInt('' + value) && VideoBlockType[value] !== undefined
}
// ---------------------------------------------------------------------------
import * as Sequelize from 'sequelize'
-import { VideoBlacklistType } from '../../../shared/models/videos'
+import { VideoBlockType } from '../../../shared/models/videos'
async function up (utils: {
transaction: Sequelize.Transaction
}
{
- const query = 'UPDATE "videoBlacklist" SET "type" = ' + VideoBlacklistType.MANUAL
+ const query = 'UPDATE "videoBlacklist" SET "type" = ' + VideoBlockType.MANUAL
await utils.sequelize.query(query)
}
}
private async notifyModeratorsOfVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo) {
- const moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_BLACKLIST)
+ const moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_BLOCKS)
if (moderators.length === 0) return
logger.info('Notifying %s moderators of video auto-blacklist %s.', moderators.length, videoBlacklist.Video.url)
async function notificationCreator (user: MUserWithNotificationSetting) {
const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
- type: UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS,
+ type: UserNotificationType.VIDEO_AUTO_BLOCK_FOR_MODERATORS,
userId: user.id,
videoBlacklistId: videoBlacklist.id
})
async function notificationCreator (user: MUserWithNotificationSetting) {
const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
- type: UserNotificationType.BLACKLIST_ON_MY_VIDEO,
+ type: UserNotificationType.BLOCK_ON_MY_VIDEO,
userId: user.id,
videoBlacklistId: videoBlacklist.id
})
async function notificationCreator (user: MUserWithNotificationSetting) {
const notification = await UserNotificationModel.create<UserNotificationModelForApi>({
- type: UserNotificationType.UNBLACKLIST_ON_MY_VIDEO,
+ type: UserNotificationType.UNBLOCK_ON_MY_VIDEO,
userId: user.id,
videoId: video.id
})
MVideoFullLight,
MVideoWithBlacklistLight
} from '@server/typings/models'
-import { UserRight, VideoBlacklistCreate, VideoBlacklistType } from '../../shared/models'
+import { UserRight, VideoBlacklistCreate, VideoBlockType } from '../../shared/models'
import { UserAdminFlag } from '../../shared/models/users/user-flag.model'
import { logger } from '../helpers/logger'
import { CONFIG } from '../initializers/config'
videoId: video.id,
unfederated: true,
reason: 'Auto-blacklisted. Moderator review required.',
- type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
+ type: VideoBlockType.AUTO_BEFORE_PUBLISHED
}
const [ videoBlacklist ] = await VideoBlacklistModel.findOrCreate<MVideoBlacklistVideo>({
where: {
videoId: videoInstance.id,
unfederated: options.unfederate === true,
reason: options.reason,
- type: VideoBlacklistType.MANUAL
+ type: VideoBlockType.MANUAL
}
)
blacklist.Video = videoInstance
Notifier.Instance.notifyOnVideoUnblacklist(video)
- if (videoBlacklistType === VideoBlacklistType.AUTO_BEFORE_PUBLISHED) {
+ if (videoBlacklistType === VideoBlockType.AUTO_BEFORE_PUBLISHED) {
Notifier.Instance.notifyOnVideoPublishedAfterRemovedFromAutoBlacklist(video)
// Delete on object so new video notifications will send
if (!CONFIG.AUTO_BLACKLIST.VIDEOS.OF_USERS.ENABLED || !user) return false
if (isRemote || isNew === false) return false
- if (user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) || user.hasAdminFlag(UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST)) return false
+ if (user.hasRight(UserRight.MANAGE_VIDEO_BLOCKS) || user.hasAdminFlag(UserAdminFlag.BYPASS_VIDEO_AUTO_BLOCK)) return false
return true
}
const videoUserId = video.VideoChannel.Account.userId
if (video.isBlacklisted()) {
- return videoUserId === this.id || this.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
+ return videoUserId === this.id || this.hasRight(UserRight.MANAGE_VIDEO_BLOCKS)
}
if (video.privacy === VideoPrivacy.PRIVATE) {
- return video.VideoChannel && videoUserId === this.id || this.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)
+ return video.VideoChannel && videoUserId === this.id || this.hasRight(UserRight.MANAGE_VIDEO_BLOCKS)
}
if (video.privacy === VideoPrivacy.INTERNAL) return true
import { VideoModel } from './video'
import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel'
import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist'
-import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos'
+import { VideoBlocklist, VideoBlockType } from '../../../shared/models/videos'
import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
import { FindOptions } from 'sequelize'
import { ThumbnailModel } from './thumbnail'
@Default(null)
@Is('VideoBlacklistType', value => throwIfNotValid(value, isVideoBlacklistTypeValid, 'type'))
@Column
- type: VideoBlacklistType
+ type: VideoBlockType
@CreatedAt
createdAt: Date
count: number
sort: SortType
search?: string
- type?: VideoBlacklistType
+ type?: VideoBlockType
}) {
const { start, count, sort, search, type } = parameters
return VideoBlacklistModel.findOne(query)
}
- toFormattedJSON (this: MVideoBlacklistFormattable): VideoBlacklist {
+ toFormattedJSON (this: MVideoBlacklistFormattable): VideoBlocklist {
return {
id: this.id,
createdAt: this.createdAt,
videoQuota: -1,
videoQuotaDaily: -1,
role: UserRole.USER,
- adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST
+ adminFlags: UserAdminFlag.BYPASS_VIDEO_AUTO_BLOCK
}
it('Should fail with a too small username', async function () {
checkBadSortPagination,
checkBadStartPagination
} from '../../../../shared/extra-utils/requests/check-api-params'
-import { VideoBlacklistType, VideoDetails } from '../../../../shared/models/videos'
+import { VideoBlockType, VideoDetails } from '../../../../shared/models/videos'
import { expect } from 'chai'
describe('Test video blacklist API validators', function () {
})
it('Should succeed with the correct parameters', async function () {
- await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, type: VideoBlacklistType.MANUAL })
+ await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, type: VideoBlockType.MANUAL })
})
})
username: user.username,
password: user.password,
videoQuota: 2 * 1024 * 1024,
- adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST
+ adminFlags: UserAdminFlag.BYPASS_VIDEO_AUTO_BLOCK
})
})
}
expect(userMe.adminFlags).to.be.undefined
- expect(userGet.adminFlags).to.equal(UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST)
+ expect(userGet.adminFlags).to.equal(UserAdminFlag.BYPASS_VIDEO_AUTO_BLOCK)
expect(userMe.specialPlaylists).to.have.lengthOf(1)
expect(userMe.specialPlaylists[0].type).to.equal(VideoPlaylistType.WATCH_LATER)
} from '../../../../shared/extra-utils/index'
import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
-import { VideoBlacklist, VideoBlacklistType } from '../../../../shared/models/videos'
+import { VideoBlocklist, VideoBlockType } from '../../../../shared/models/videos'
import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
import { User, UserRole } from '../../../../shared/models/users'
import { getMagnetURI, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
const res = await getBlacklistedVideosList({
url: servers[0].url,
token: servers[0].accessToken,
- type: VideoBlacklistType.MANUAL
+ type: VideoBlockType.MANUAL
})
expect(res.body.total).to.equal(2)
const res = await getBlacklistedVideosList({
url: servers[0].url,
token: servers[0].accessToken,
- type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
+ type: VideoBlockType.AUTO_BEFORE_PUBLISHED
})
expect(res.body.total).to.equal(0)
})
describe('When removing a blacklisted video', function () {
- let videoToRemove: VideoBlacklist
+ let videoToRemove: VideoBlocklist
let blacklist = []
it('Should not have any video in videos list on server 1', async function () {
it('Should have the correct video blacklist unfederate attribute', async function () {
const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: 'createdAt' })
- const blacklistedVideos: VideoBlacklist[] = res.body.data
+ const blacklistedVideos: VideoBlocklist[] = res.body.data
const video3Blacklisted = blacklistedVideos.find(b => b.video.uuid === video3UUID)
const video4Blacklisted = blacklistedVideos.find(b => b.video.uuid === video4UUID)
url: servers[0].url,
accessToken: servers[0].accessToken,
username: user.username,
- adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST,
+ adminFlags: UserAdminFlag.BYPASS_VIDEO_AUTO_BLOCK,
password: user.password,
role: UserRole.USER
})
const res = await getBlacklistedVideosList({
url: servers[0].url,
token: servers[0].accessToken,
- type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
+ type: VideoBlockType.AUTO_BEFORE_PUBLISHED
})
expect(res.body.total).to.equal(1)
url: servers[0].url,
token: servers[0].accessToken,
sort: 'createdAt',
- type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
+ type: VideoBlockType.AUTO_BEFORE_PUBLISHED
})
expect(res.body.total).to.equal(2)
url: servers[0].url,
token: servers[0].accessToken,
sort: 'createdAt',
- type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
+ type: VideoBlockType.AUTO_BEFORE_PUBLISHED
})
expect(res.body.total).to.equal(3)
const res = await getBlacklistedVideosList({
url: servers[0].url,
token: servers[0].accessToken,
- type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
+ type: VideoBlockType.AUTO_BEFORE_PUBLISHED
})
expect(res.body.total).to.equal(3)
}
async function checkVideoAutoBlacklistForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
- const notificationType = UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS
+ const notificationType = UserNotificationType.VIDEO_AUTO_BLOCK_FOR_MODERATORS
function notificationChecker (notification: UserNotification, type: CheckerType) {
if (type === 'presence') {
blacklistType: 'blacklist' | 'unblacklist'
) {
const notificationType = blacklistType === 'blacklist'
- ? UserNotificationType.BLACKLIST_ON_MY_VIDEO
- : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO
+ ? UserNotificationType.BLOCK_ON_MY_VIDEO
+ : UserNotificationType.UNBLOCK_ON_MY_VIDEO
function notificationChecker (notification: UserNotification) {
expect(notification).to.not.be.undefined
import * as request from 'supertest'
-import { VideoBlacklistType } from '../../models/videos'
+import { VideoBlockType } from '../../models/videos'
import { makeGetRequest } from '..'
function addVideoToBlacklist (
url: string
token: string
sort?: string
- type?: VideoBlacklistType
+ type?: VideoBlockType
specialStatus?: number
}) {
const { url, token, sort, type, specialStatus = 200 } = parameters
export enum UserAdminFlag {
NONE = 0,
- BY_PASS_VIDEO_AUTO_BLACKLIST = 1 << 0
+ BYPASS_VIDEO_AUTO_BLOCK = 1 << 0
}
NEW_COMMENT_ON_MY_VIDEO = 2,
NEW_VIDEO_ABUSE_FOR_MODERATORS = 3,
- BLACKLIST_ON_MY_VIDEO = 4,
- UNBLACKLIST_ON_MY_VIDEO = 5,
+ BLOCK_ON_MY_VIDEO = 4,
+ UNBLOCK_ON_MY_VIDEO = 5,
MY_VIDEO_PUBLISHED = 6,
NEW_FOLLOW = 10,
COMMENT_MENTION = 11,
- VIDEO_AUTO_BLACKLIST_FOR_MODERATORS = 12,
+ VIDEO_AUTO_BLOCK_FOR_MODERATORS = 12,
NEW_INSTANCE_FOLLOWER = 13,
MANAGE_ACCOUNTS_BLOCKLIST,
MANAGE_SERVERS_BLOCKLIST,
- MANAGE_VIDEO_BLACKLIST,
+ MANAGE_VIDEO_BLOCKS,
REMOVE_ANY_VIDEO,
REMOVE_ANY_VIDEO_CHANNEL,
],
[UserRole.MODERATOR]: [
- UserRight.MANAGE_VIDEO_BLACKLIST,
+ UserRight.MANAGE_VIDEO_BLOCKS,
UserRight.MANAGE_VIDEO_ABUSES,
UserRight.REMOVE_ANY_VIDEO,
UserRight.REMOVE_ANY_VIDEO_CHANNEL,
import { Video } from '../video.model'
-export enum VideoBlacklistType {
+export enum VideoBlockType {
MANUAL = 1,
AUTO_BEFORE_PUBLISHED = 2
}
-export interface VideoBlacklist {
+export interface VideoBlocklist {
id: number
unfederated: boolean
reason?: string
- type: VideoBlacklistType
+ type: VideoBlockType
video: Video