diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-06-02 20:50:42 +0200 |
---|---|---|
committer | Rigel Kent <sendmemail@rigelk.eu> | 2020-06-10 21:12:05 +0200 |
commit | 5baee5fca418487e72ddcd6419d31bca8659b668 (patch) | |
tree | 6604cc16d42152f4929d888565d2d435e2480d47 /client | |
parent | d840487fed32b4604b02030c0d7464afa925904f (diff) | |
download | PeerTube-5baee5fca418487e72ddcd6419d31bca8659b668.tar.gz PeerTube-5baee5fca418487e72ddcd6419d31bca8659b668.tar.zst PeerTube-5baee5fca418487e72ddcd6419d31bca8659b668.zip |
rename blacklist to block/blocklist, merge block and auto-block views
- also replace whitelist with allowlist
- add advanced filters for video-block-list view
- move icons in video-block-list and video-abuse-list to left side
for visibility
- add robot icon to depict automated nature of a block in
video-block-list
resolves #2790
Diffstat (limited to 'client')
53 files changed, 575 insertions, 591 deletions
diff --git a/client/src/app/+admin/admin.component.ts b/client/src/app/+admin/admin.component.ts index 9662522dc..4cf3da0e8 100644 --- a/client/src/app/+admin/admin.component.ts +++ b/client/src/app/+admin/admin.component.ts | |||
@@ -18,7 +18,7 @@ export class AdminComponent implements OnInit { | |||
18 | ngOnInit () { | 18 | ngOnInit () { |
19 | if (this.hasUsersRight()) this.items.push({ label: this.i18n('Users'), routerLink: '/admin/users' }) | 19 | if (this.hasUsersRight()) this.items.push({ label: this.i18n('Users'), routerLink: '/admin/users' }) |
20 | if (this.hasServerFollowRight()) this.items.push({ label: this.i18n('Follows & redundancies'), routerLink: '/admin/follows' }) | 20 | if (this.hasServerFollowRight()) this.items.push({ label: this.i18n('Follows & redundancies'), routerLink: '/admin/follows' }) |
21 | if (this.hasVideoAbusesRight() || this.hasVideoBlacklistRight()) this.items.push({ label: this.i18n('Moderation'), routerLink: '/admin/moderation' }) | 21 | if (this.hasVideoAbusesRight() || this.hasVideoBlocklistRight()) this.items.push({ label: this.i18n('Moderation'), routerLink: '/admin/moderation' }) |
22 | if (this.hasConfigRight()) this.items.push({ label: this.i18n('Configuration'), routerLink: '/admin/config' }) | 22 | if (this.hasConfigRight()) this.items.push({ label: this.i18n('Configuration'), routerLink: '/admin/config' }) |
23 | if (this.hasPluginsRight()) this.items.push({ label: this.i18n('Plugins/Themes'), routerLink: '/admin/plugins' }) | 23 | if (this.hasPluginsRight()) this.items.push({ label: this.i18n('Plugins/Themes'), routerLink: '/admin/plugins' }) |
24 | if (this.hasJobsRight() || this.hasLogsRight() || this.hasDebugRight()) this.items.push({ label: this.i18n('System'), routerLink: '/admin/system' }) | 24 | if (this.hasJobsRight() || this.hasLogsRight() || this.hasDebugRight()) this.items.push({ label: this.i18n('System'), routerLink: '/admin/system' }) |
@@ -36,8 +36,8 @@ export class AdminComponent implements OnInit { | |||
36 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES) | 36 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES) |
37 | } | 37 | } |
38 | 38 | ||
39 | hasVideoBlacklistRight () { | 39 | hasVideoBlocklistRight () { |
40 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) | 40 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLOCKS) |
41 | } | 41 | } |
42 | 42 | ||
43 | hasConfigRight () { | 43 | hasConfigRight () { |
diff --git a/client/src/app/+admin/admin.module.ts b/client/src/app/+admin/admin.module.ts index d04313c0a..eb073f709 100644 --- a/client/src/app/+admin/admin.module.ts +++ b/client/src/app/+admin/admin.module.ts | |||
@@ -11,8 +11,7 @@ import { UserCreateComponent, UserListComponent, UserPasswordComponent, UsersCom | |||
11 | import { | 11 | import { |
12 | ModerationCommentModalComponent, | 12 | ModerationCommentModalComponent, |
13 | VideoAbuseListComponent, | 13 | VideoAbuseListComponent, |
14 | VideoAutoBlacklistListComponent, | 14 | VideoBlockListComponent |
15 | VideoBlacklistListComponent | ||
16 | } from './moderation' | 15 | } from './moderation' |
17 | import { ModerationComponent } from '@app/+admin/moderation/moderation.component' | 16 | import { ModerationComponent } from '@app/+admin/moderation/moderation.component' |
18 | import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component' | 17 | import { RedundancyCheckboxComponent } from '@app/+admin/follows/shared/redundancy-checkbox.component' |
@@ -59,10 +58,9 @@ import { VideoAbuseDetailsComponent } from './moderation/video-abuse-list/video- | |||
59 | UserListComponent, | 58 | UserListComponent, |
60 | 59 | ||
61 | ModerationComponent, | 60 | ModerationComponent, |
62 | VideoBlacklistListComponent, | 61 | VideoBlockListComponent, |
63 | VideoAbuseListComponent, | 62 | VideoAbuseListComponent, |
64 | VideoAbuseDetailsComponent, | 63 | VideoAbuseDetailsComponent, |
65 | VideoAutoBlacklistListComponent, | ||
66 | ModerationCommentModalComponent, | 64 | ModerationCommentModalComponent, |
67 | InstanceServerBlocklistComponent, | 65 | InstanceServerBlocklistComponent, |
68 | InstanceAccountBlocklistComponent, | 66 | InstanceAccountBlocklistComponent, |
diff --git a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html index 981b6685f..52c759fb7 100644 --- a/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html +++ b/client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.html | |||
@@ -430,7 +430,7 @@ | |||
430 | <div class="form-group"> | 430 | <div class="form-group"> |
431 | <my-peertube-checkbox | 431 | <my-peertube-checkbox |
432 | inputName="autoBlacklistVideosOfUsersEnabled" formControlName="enabled" | 432 | inputName="autoBlacklistVideosOfUsersEnabled" formControlName="enabled" |
433 | i18n-labelText labelText="Blacklist new videos automatically" | 433 | i18n-labelText labelText="Block new videos automatically" |
434 | > | 434 | > |
435 | <ng-container ngProjectAs="description"> | 435 | <ng-container ngProjectAs="description"> |
436 | <span i18n>Unless a user is marked as trusted, their videos will stay private until a moderator reviews them.</span> | 436 | <span i18n>Unless a user is marked as trusted, their videos will stay private until a moderator reviews them.</span> |
@@ -671,16 +671,16 @@ | |||
671 | <div class="form-group"> | 671 | <div class="form-group"> |
672 | <my-peertube-checkbox inputName="servicesTwitterWhitelisted" formControlName="whitelisted"> | 672 | <my-peertube-checkbox inputName="servicesTwitterWhitelisted" formControlName="whitelisted"> |
673 | <ng-template ptTemplate="label"> | 673 | <ng-template ptTemplate="label"> |
674 | <ng-container i18n>Instance whitelisted by Twitter</ng-container> | 674 | <ng-container i18n>Instance allowed by Twitter</ng-container> |
675 | </ng-template> | 675 | </ng-template> |
676 | 676 | ||
677 | <ng-template ptTemplate="help"> | 677 | <ng-template ptTemplate="help"> |
678 | <ng-container i18n> | 678 | <ng-container i18n> |
679 | If your instance is whitelisted by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br /> | 679 | If your instance is explicitly allowed by Twitter, a video player will be embedded in the Twitter feed on PeerTube video share.<br /> |
680 | If the instance is not whitelisted, we use an image link card that will redirect on your PeerTube instance.<br /><br /> | 680 | If the instance is not, we use an image link card that will redirect on your PeerTube instance.<br /><br /> |
681 | Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on | 681 | Check this checkbox, save the configuration and test with a video URL of your instance (https://example.com/videos/watch/blabla) on |
682 | <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> | 682 | <a target='_blank' rel='noopener noreferrer' href='https://cards-dev.twitter.com/validator'>https://cards-dev.twitter.com/validator</a> |
683 | to see if you instance is whitelisted. | 683 | to see if you instance is allowed. |
684 | </ng-container> | 684 | </ng-container> |
685 | </ng-template> | 685 | </ng-template> |
686 | </my-peertube-checkbox> | 686 | </my-peertube-checkbox> |
diff --git a/client/src/app/+admin/moderation/index.ts b/client/src/app/+admin/moderation/index.ts index 3c683a28c..e99244b74 100644 --- a/client/src/app/+admin/moderation/index.ts +++ b/client/src/app/+admin/moderation/index.ts | |||
@@ -1,5 +1,4 @@ | |||
1 | export * from './video-abuse-list' | 1 | export * from './video-abuse-list' |
2 | export * from './video-auto-blacklist-list' | 2 | export * from './video-block-list' |
3 | export * from './video-blacklist-list' | ||
4 | export * from './moderation.component' | 3 | export * from './moderation.component' |
5 | export * from './moderation.routes' | 4 | export * from './moderation.routes' |
diff --git a/client/src/app/+admin/moderation/moderation.component.html b/client/src/app/+admin/moderation/moderation.component.html index b70027957..09f149c0e 100644 --- a/client/src/app/+admin/moderation/moderation.component.html +++ b/client/src/app/+admin/moderation/moderation.component.html | |||
@@ -2,11 +2,9 @@ | |||
2 | <div i18n class="form-sub-title">Moderation</div> | 2 | <div i18n class="form-sub-title">Moderation</div> |
3 | 3 | ||
4 | <div class="admin-sub-nav"> | 4 | <div class="admin-sub-nav"> |
5 | <a *ngIf="hasVideoAbusesRight()" i18n routerLink="video-abuses/list" routerLinkActive="active">Video abuses</a> | 5 | <a *ngIf="hasVideoAbusesRight()" i18n routerLink="video-abuses/list" routerLinkActive="active">Video reports</a> |
6 | 6 | ||
7 | <a *ngIf="hasVideoBlacklistRight()" i18n routerLink="video-blacklist/list" routerLinkActive="active">{{ autoBlacklistVideosEnabled ? 'Manually blacklisted videos' : 'Blacklisted videos' }}</a> | 7 | <a *ngIf="hasVideoBlocklistRight()" i18n routerLink="video-blocks/list" routerLinkActive="active">Video blocks</a> |
8 | |||
9 | <a *ngIf="autoBlacklistVideosEnabled && hasVideoBlacklistRight()" i18n routerLink="video-auto-blacklist/list" routerLinkActive="active">Auto-blacklisted videos</a> | ||
10 | 8 | ||
11 | <a *ngIf="hasAccountsBlocklistRight()" i18n routerLink="blocklist/accounts" routerLinkActive="active">Muted accounts</a> | 9 | <a *ngIf="hasAccountsBlocklistRight()" i18n routerLink="blocklist/accounts" routerLinkActive="active">Muted accounts</a> |
12 | 10 | ||
diff --git a/client/src/app/+admin/moderation/moderation.component.ts b/client/src/app/+admin/moderation/moderation.component.ts index 7744deb06..d48305eed 100644 --- a/client/src/app/+admin/moderation/moderation.component.ts +++ b/client/src/app/+admin/moderation/moderation.component.ts | |||
@@ -7,7 +7,7 @@ import { AuthService, ServerService } from '@app/core' | |||
7 | styleUrls: [ './moderation.component.scss' ] | 7 | styleUrls: [ './moderation.component.scss' ] |
8 | }) | 8 | }) |
9 | export class ModerationComponent implements OnInit { | 9 | export class ModerationComponent implements OnInit { |
10 | autoBlacklistVideosEnabled = false | 10 | autoBlockVideosEnabled = false |
11 | 11 | ||
12 | constructor ( | 12 | constructor ( |
13 | private auth: AuthService, | 13 | private auth: AuthService, |
@@ -16,7 +16,7 @@ export class ModerationComponent implements OnInit { | |||
16 | 16 | ||
17 | ngOnInit (): void { | 17 | ngOnInit (): void { |
18 | this.serverService.getConfig() | 18 | this.serverService.getConfig() |
19 | .subscribe(config => this.autoBlacklistVideosEnabled = config.autoBlacklist.videos.ofUsers.enabled) | 19 | .subscribe(config => this.autoBlockVideosEnabled = config.autoBlacklist.videos.ofUsers.enabled) |
20 | 20 | ||
21 | } | 21 | } |
22 | 22 | ||
@@ -24,8 +24,8 @@ export class ModerationComponent implements OnInit { | |||
24 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES) | 24 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_ABUSES) |
25 | } | 25 | } |
26 | 26 | ||
27 | hasVideoBlacklistRight () { | 27 | hasVideoBlocklistRight () { |
28 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) | 28 | return this.auth.getUser().hasRight(UserRight.MANAGE_VIDEO_BLOCKS) |
29 | } | 29 | } |
30 | 30 | ||
31 | hasAccountsBlocklistRight () { | 31 | hasAccountsBlocklistRight () { |
diff --git a/client/src/app/+admin/moderation/moderation.routes.ts b/client/src/app/+admin/moderation/moderation.routes.ts index a024f2bee..aeb555c4a 100644 --- a/client/src/app/+admin/moderation/moderation.routes.ts +++ b/client/src/app/+admin/moderation/moderation.routes.ts | |||
@@ -2,8 +2,7 @@ import { Routes } from '@angular/router' | |||
2 | import { UserRight } from '../../../../../shared' | 2 | import { UserRight } from '../../../../../shared' |
3 | import { UserRightGuard } from '@app/core' | 3 | import { UserRightGuard } from '@app/core' |
4 | import { VideoAbuseListComponent } from '@app/+admin/moderation/video-abuse-list' | 4 | import { VideoAbuseListComponent } from '@app/+admin/moderation/video-abuse-list' |
5 | import { VideoBlacklistListComponent } from '@app/+admin/moderation/video-blacklist-list' | 5 | import { VideoBlockListComponent } from '@app/+admin/moderation/video-block-list' |
6 | import { VideoAutoBlacklistListComponent } from '@app/+admin/moderation/video-auto-blacklist-list' | ||
7 | import { ModerationComponent } from '@app/+admin/moderation/moderation.component' | 6 | import { ModerationComponent } from '@app/+admin/moderation/moderation.component' |
8 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist' | 7 | import { InstanceAccountBlocklistComponent, InstanceServerBlocklistComponent } from '@app/+admin/moderation/instance-blocklist' |
9 | 8 | ||
@@ -23,45 +22,44 @@ export const ModerationRoutes: Routes = [ | |||
23 | pathMatch: 'full' | 22 | pathMatch: 'full' |
24 | }, | 23 | }, |
25 | { | 24 | { |
26 | path: 'video-blacklist', | ||
27 | redirectTo: 'video-blacklist/list', | ||
28 | pathMatch: 'full' | ||
29 | }, | ||
30 | { | ||
31 | path: 'video-auto-blacklist', | ||
32 | redirectTo: 'video-auto-blacklist/list', | ||
33 | pathMatch: 'full' | ||
34 | }, | ||
35 | { | ||
36 | path: 'video-abuses/list', | 25 | path: 'video-abuses/list', |
37 | component: VideoAbuseListComponent, | 26 | component: VideoAbuseListComponent, |
38 | canActivate: [ UserRightGuard ], | 27 | canActivate: [ UserRightGuard ], |
39 | data: { | 28 | data: { |
40 | userRight: UserRight.MANAGE_VIDEO_ABUSES, | 29 | userRight: UserRight.MANAGE_VIDEO_ABUSES, |
41 | meta: { | 30 | meta: { |
42 | title: 'Video abuses list' | 31 | title: 'Video reports' |
43 | } | 32 | } |
44 | } | 33 | } |
45 | }, | 34 | }, |
46 | { | 35 | { |
36 | path: 'video-blacklist', | ||
37 | redirectTo: 'video-blocks/list', | ||
38 | pathMatch: 'full' | ||
39 | }, | ||
40 | { | ||
41 | path: 'video-auto-blacklist', | ||
42 | redirectTo: 'video-blocks/list', | ||
43 | pathMatch: 'full' | ||
44 | }, | ||
45 | { | ||
47 | path: 'video-auto-blacklist/list', | 46 | path: 'video-auto-blacklist/list', |
48 | component: VideoAutoBlacklistListComponent, | 47 | redirectTo: 'video-blocks/list', |
49 | canActivate: [ UserRightGuard ], | 48 | pathMatch: 'full' |
50 | data: { | 49 | }, |
51 | userRight: UserRight.MANAGE_VIDEO_BLACKLIST, | 50 | { |
52 | meta: { | 51 | path: 'video-blacklist', |
53 | title: 'Auto-blacklisted videos' | 52 | redirectTo: 'video-blocks/list', |
54 | } | 53 | pathMatch: 'full' |
55 | } | ||
56 | }, | 54 | }, |
57 | { | 55 | { |
58 | path: 'video-blacklist/list', | 56 | path: 'video-blocks/list', |
59 | component: VideoBlacklistListComponent, | 57 | component: VideoBlockListComponent, |
60 | canActivate: [ UserRightGuard ], | 58 | canActivate: [ UserRightGuard ], |
61 | data: { | 59 | data: { |
62 | userRight: UserRight.MANAGE_VIDEO_BLACKLIST, | 60 | userRight: UserRight.MANAGE_VIDEO_BLOCKS, |
63 | meta: { | 61 | meta: { |
64 | title: 'Blacklisted videos' | 62 | title: 'Videos blocked' |
65 | } | 63 | } |
66 | } | 64 | } |
67 | }, | 65 | }, |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html index 2abcc0669..453a282d1 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.html | |||
@@ -69,7 +69,7 @@ | |||
69 | <div class="screenratio"> | 69 | <div class="screenratio"> |
70 | <div *ngIf="videoAbuse.video.deleted || videoAbuse.video.blacklisted"> | 70 | <div *ngIf="videoAbuse.video.deleted || videoAbuse.video.blacklisted"> |
71 | <span i18n *ngIf="videoAbuse.video.deleted">The video was deleted</span> | 71 | <span i18n *ngIf="videoAbuse.video.deleted">The video was deleted</span> |
72 | <span i18n *ngIf="!videoAbuse.video.deleted">The video was blacklisted</span> | 72 | <span i18n *ngIf="!videoAbuse.video.deleted">The video was blocked</span> |
73 | </div> | 73 | </div> |
74 | <div *ngIf="!videoAbuse.video.deleted && !videoAbuse.video.blacklisted" [innerHTML]="videoAbuse.embedHtml"></div> | 74 | <div *ngIf="!videoAbuse.video.deleted && !videoAbuse.video.blacklisted" [innerHTML]="videoAbuse.embedHtml"></div> |
75 | </div> | 75 | </div> |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html index d30475794..df15999ec 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.html | |||
@@ -19,7 +19,7 @@ | |||
19 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:pending' }" class="dropdown-item" i18n>Unsolved reports</a> | 19 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:pending' }" class="dropdown-item" i18n>Unsolved reports</a> |
20 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:accepted' }" class="dropdown-item" i18n>Accepted reports</a> | 20 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:accepted' }" class="dropdown-item" i18n>Accepted reports</a> |
21 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:rejected' }" class="dropdown-item" i18n>Refused reports</a> | 21 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'state:rejected' }" class="dropdown-item" i18n>Refused reports</a> |
22 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'videoIs:blacklisted' }" class="dropdown-item" i18n>Reports with blacklisted videos</a> | 22 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'videoIs:blacklisted' }" class="dropdown-item" i18n>Reports with blocked videos</a> |
23 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'videoIs:deleted' }" class="dropdown-item" i18n>Reports with deleted videos</a> | 23 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'videoIs:deleted' }" class="dropdown-item" i18n>Reports with deleted videos</a> |
24 | </div> | 24 | </div> |
25 | </div> | 25 | </div> |
@@ -84,9 +84,9 @@ | |||
84 | </div> | 84 | </div> |
85 | <div class="video-table-video-text"> | 85 | <div class="video-table-video-text"> |
86 | <div> | 86 | <div> |
87 | {{ videoAbuse.video.name }} | ||
88 | <span *ngIf="!videoAbuse.video.blacklisted" class="glyphicon glyphicon-new-window"></span> | 87 | <span *ngIf="!videoAbuse.video.blacklisted" class="glyphicon glyphicon-new-window"></span> |
89 | <span *ngIf="videoAbuse.video.blacklisted" i18n-title title="Video was blacklisted" class="glyphicon glyphicon-ban-circle"></span> | 88 | <span *ngIf="videoAbuse.video.blacklisted" i18n-title title="The video was blocked" class="glyphicon glyphicon-ban-circle"></span> |
89 | {{ videoAbuse.video.name }} | ||
90 | </div> | 90 | </div> |
91 | <div class="text-muted" i18n>by {{ videoAbuse.video.channel?.displayName }} on {{ videoAbuse.video.channel?.host }} </div> | 91 | <div class="text-muted" i18n>by {{ videoAbuse.video.channel?.displayName }} on {{ videoAbuse.video.channel?.host }} </div> |
92 | </div> | 92 | </div> |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts index 39f619cc3..ca37bccf3 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.ts | |||
@@ -3,7 +3,7 @@ import { Account } from '@app/shared/account/account.model' | |||
3 | import { Notifier } from '@app/core' | 3 | import { Notifier } from '@app/core' |
4 | import { SortMeta } from 'primeng/api' | 4 | import { SortMeta } from 'primeng/api' |
5 | import { VideoAbuse, VideoAbuseState } from '../../../../../../shared' | 5 | import { VideoAbuse, VideoAbuseState } from '../../../../../../shared' |
6 | import { RestPagination, RestTable, VideoAbuseService, VideoBlacklistService } from '../../../shared' | 6 | import { RestPagination, RestTable, VideoAbuseService, VideoBlockService } from '../../../shared' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | 7 | import { I18n } from '@ngx-translate/i18n-polyfill' |
8 | import { DropdownAction } from '../../../shared/buttons/action-dropdown.component' | 8 | import { DropdownAction } from '../../../shared/buttons/action-dropdown.component' |
9 | import { ConfirmService } from '../../../core/index' | 9 | import { ConfirmService } from '../../../core/index' |
@@ -53,7 +53,7 @@ export class VideoAbuseListComponent extends RestTable implements OnInit, AfterV | |||
53 | private videoAbuseService: VideoAbuseService, | 53 | private videoAbuseService: VideoAbuseService, |
54 | private blocklistService: BlocklistService, | 54 | private blocklistService: BlocklistService, |
55 | private videoService: VideoService, | 55 | private videoService: VideoService, |
56 | private videoBlacklistService: VideoBlacklistService, | 56 | private videoBlocklistService: VideoBlockService, |
57 | private confirmService: ConfirmService, | 57 | private confirmService: ConfirmService, |
58 | private i18n: I18n, | 58 | private i18n: I18n, |
59 | private markdownRenderer: MarkdownService, | 59 | private markdownRenderer: MarkdownService, |
@@ -101,13 +101,13 @@ export class VideoAbuseListComponent extends RestTable implements OnInit, AfterV | |||
101 | isDisplayed: videoAbuse => !videoAbuse.video.deleted | 101 | isDisplayed: videoAbuse => !videoAbuse.video.deleted |
102 | }, | 102 | }, |
103 | { | 103 | { |
104 | label: this.i18n('Blacklist video'), | 104 | label: this.i18n('Block video'), |
105 | isDisplayed: videoAbuse => !videoAbuse.video.deleted && !videoAbuse.video.blacklisted, | 105 | isDisplayed: videoAbuse => !videoAbuse.video.deleted && !videoAbuse.video.blacklisted, |
106 | handler: videoAbuse => { | 106 | handler: videoAbuse => { |
107 | this.videoBlacklistService.blacklistVideo(videoAbuse.video.id, undefined, true) | 107 | this.videoBlocklistService.blockVideo(videoAbuse.video.id, undefined, true) |
108 | .subscribe( | 108 | .subscribe( |
109 | () => { | 109 | () => { |
110 | this.notifier.success(this.i18n('Video blacklisted.')) | 110 | this.notifier.success(this.i18n('Video blocklisted.')) |
111 | 111 | ||
112 | this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED) | 112 | this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED) |
113 | }, | 113 | }, |
@@ -117,13 +117,13 @@ export class VideoAbuseListComponent extends RestTable implements OnInit, AfterV | |||
117 | } | 117 | } |
118 | }, | 118 | }, |
119 | { | 119 | { |
120 | label: this.i18n('Unblacklist video'), | 120 | label: this.i18n('Unblock video'), |
121 | isDisplayed: videoAbuse => !videoAbuse.video.deleted && videoAbuse.video.blacklisted, | 121 | isDisplayed: videoAbuse => !videoAbuse.video.deleted && videoAbuse.video.blacklisted, |
122 | handler: videoAbuse => { | 122 | handler: videoAbuse => { |
123 | this.videoBlacklistService.removeVideoFromBlacklist(videoAbuse.video.id) | 123 | this.videoBlocklistService.unblockVideo(videoAbuse.video.id) |
124 | .subscribe( | 124 | .subscribe( |
125 | () => { | 125 | () => { |
126 | this.notifier.success(this.i18n('Video unblacklisted.')) | 126 | this.notifier.success(this.i18n('Video unblocklisted.')) |
127 | 127 | ||
128 | this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED) | 128 | this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED) |
129 | }, | 129 | }, |
@@ -292,7 +292,6 @@ export class VideoAbuseListComponent extends RestTable implements OnInit, AfterV | |||
292 | 292 | ||
293 | err => this.notifier.error(err.message) | 293 | err => this.notifier.error(err.message) |
294 | ) | 294 | ) |
295 | |||
296 | } | 295 | } |
297 | 296 | ||
298 | protected loadData () { | 297 | protected loadData () { |
diff --git a/client/src/app/+admin/moderation/video-auto-blacklist-list/index.ts b/client/src/app/+admin/moderation/video-auto-blacklist-list/index.ts deleted file mode 100644 index e3522f68c..000000000 --- a/client/src/app/+admin/moderation/video-auto-blacklist-list/index.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export * from './video-auto-blacklist-list.component' | ||
diff --git a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.html b/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.html deleted file mode 100644 index e2193b630..000000000 --- a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.html +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | <my-videos-selection | ||
2 | [pagination]="pagination" | ||
3 | [(selection)]="selection" | ||
4 | [(videosModel)]="videos" | ||
5 | [miniatureDisplayOptions]="miniatureDisplayOptions" | ||
6 | [titlePage]="titlePage" | ||
7 | [getVideosObservableFunction]="getVideosObservableFunction" | ||
8 | > | ||
9 | <ng-template ptTemplate="globalButtons"> | ||
10 | <span class="action-button action-button-unblacklist-selection" (click)="removeSelectedVideosFromBlacklist()"> | ||
11 | <my-global-icon iconName="tick"></my-global-icon> | ||
12 | <ng-container i18n>Unblacklist</ng-container> | ||
13 | </span> | ||
14 | </ng-template> | ||
15 | |||
16 | <ng-template ptTemplate="rowButtons" let-video> | ||
17 | <my-button i18n-label label="Unblacklist" icon="tick" (click)="removeVideoFromBlacklist(video)"></my-button> | ||
18 | </ng-template> | ||
19 | |||
20 | </my-videos-selection> | ||
diff --git a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.scss b/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.scss deleted file mode 100644 index 85ebc6041..000000000 --- a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.scss +++ /dev/null | |||
@@ -1,14 +0,0 @@ | |||
1 | @import '_variables'; | ||
2 | @import '_mixins'; | ||
3 | |||
4 | .action-button-unblacklist-selection { | ||
5 | display: inline-block; | ||
6 | |||
7 | @include peertube-button; | ||
8 | @include orange-button; | ||
9 | @include button-with-icon(21px); | ||
10 | |||
11 | my-global-icon { | ||
12 | @include apply-svg-color(#fff); | ||
13 | } | ||
14 | } | ||
diff --git a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.ts b/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.ts deleted file mode 100644 index fb2962b47..000000000 --- a/client/src/app/+admin/moderation/video-auto-blacklist-list/video-auto-blacklist-list.component.ts +++ /dev/null | |||
@@ -1,86 +0,0 @@ | |||
1 | import { Component } from '@angular/core' | ||
2 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
3 | import { ActivatedRoute, Router } from '@angular/router' | ||
4 | import { ComponentPagination } from '@app/shared/rest/component-pagination.model' | ||
5 | import { AuthService, Notifier, ServerService } from '@app/core' | ||
6 | import { VideoBlacklistService } from '@app/shared' | ||
7 | import { immutableAssign } from '@app/shared/misc/utils' | ||
8 | import { ScreenService } from '@app/shared/misc/screen.service' | ||
9 | import { MiniatureDisplayOptions } from '@app/shared/video/video-miniature.component' | ||
10 | import { SelectionType } from '@app/shared/video/videos-selection.component' | ||
11 | import { Video } from '@app/shared/video/video.model' | ||
12 | |||
13 | @Component({ | ||
14 | selector: 'my-video-auto-blacklist-list', | ||
15 | templateUrl: './video-auto-blacklist-list.component.html', | ||
16 | styleUrls: [ './video-auto-blacklist-list.component.scss' ] | ||
17 | }) | ||
18 | export class VideoAutoBlacklistListComponent { | ||
19 | titlePage: string | ||
20 | selection: SelectionType = {} | ||
21 | miniatureDisplayOptions: MiniatureDisplayOptions = { | ||
22 | date: true, | ||
23 | views: false, | ||
24 | by: true, | ||
25 | privacyLabel: false, | ||
26 | privacyText: true, | ||
27 | state: false, | ||
28 | blacklistInfo: false, | ||
29 | nsfw: true | ||
30 | } | ||
31 | pagination: ComponentPagination = { | ||
32 | currentPage: 1, | ||
33 | itemsPerPage: 5, | ||
34 | totalItems: null | ||
35 | } | ||
36 | videos: Video[] = [] | ||
37 | getVideosObservableFunction = this.getVideosObservable.bind(this) | ||
38 | |||
39 | constructor ( | ||
40 | protected router: Router, | ||
41 | protected route: ActivatedRoute, | ||
42 | protected notifier: Notifier, | ||
43 | protected authService: AuthService, | ||
44 | protected screenService: ScreenService, | ||
45 | protected serverService: ServerService, | ||
46 | private i18n: I18n, | ||
47 | private videoBlacklistService: VideoBlacklistService | ||
48 | ) { | ||
49 | this.titlePage = this.i18n('Auto-blacklisted videos') | ||
50 | } | ||
51 | |||
52 | getVideosObservable (page: number) { | ||
53 | const newPagination = immutableAssign(this.pagination, { currentPage: page }) | ||
54 | |||
55 | return this.videoBlacklistService.getAutoBlacklistedAsVideoList(newPagination) | ||
56 | } | ||
57 | |||
58 | removeVideoFromBlacklist (entry: Video) { | ||
59 | this.videoBlacklistService.removeVideoFromBlacklist(entry.id).subscribe( | ||
60 | () => { | ||
61 | this.notifier.success(this.i18n('Video {{name}} removed from blacklist.', { name: entry.name })) | ||
62 | |||
63 | this.videos = this.videos.filter(v => v.id !== entry.id) | ||
64 | }, | ||
65 | |||
66 | error => this.notifier.error(error.message) | ||
67 | ) | ||
68 | } | ||
69 | |||
70 | removeSelectedVideosFromBlacklist () { | ||
71 | const toReleaseVideosIds = Object.keys(this.selection) | ||
72 | .filter(k => this.selection[ k ] === true) | ||
73 | .map(k => parseInt(k, 10)) | ||
74 | |||
75 | this.videoBlacklistService.removeVideoFromBlacklist(toReleaseVideosIds).subscribe( | ||
76 | () => { | ||
77 | this.notifier.success(this.i18n('{{num}} videos removed from blacklist.', { num: toReleaseVideosIds.length })) | ||
78 | |||
79 | this.selection = {} | ||
80 | this.videos = this.videos.filter(v => toReleaseVideosIds.includes(v.id) === false) | ||
81 | }, | ||
82 | |||
83 | error => this.notifier.error(error.message) | ||
84 | ) | ||
85 | } | ||
86 | } | ||
diff --git a/client/src/app/+admin/moderation/video-blacklist-list/index.ts b/client/src/app/+admin/moderation/video-blacklist-list/index.ts deleted file mode 100644 index 4daf64187..000000000 --- a/client/src/app/+admin/moderation/video-blacklist-list/index.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export * from './video-blacklist-list.component' | ||
diff --git a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html deleted file mode 100644 index cfa04514f..000000000 --- a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.html +++ /dev/null | |||
@@ -1,100 +0,0 @@ | |||
1 | <p-table | ||
2 | [value]="blacklist" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | ||
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" | ||
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | ||
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} blacklisted videos" | ||
6 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" | ||
7 | > | ||
8 | <ng-template pTemplate="caption"> | ||
9 | <div class="caption"> | ||
10 | <div class="ml-auto has-feedback has-clear"> | ||
11 | <input | ||
12 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
13 | (keyup)="onSearch($event)" | ||
14 | > | ||
15 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetSearch()"></a> | ||
16 | <span class="sr-only" i18n>Clear filters</span> | ||
17 | </div> | ||
18 | </div> | ||
19 | </ng-template> | ||
20 | |||
21 | <ng-template pTemplate="header"> | ||
22 | <tr> | ||
23 | <th style="width: 40px"></th> | ||
24 | <th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th> | ||
25 | <th style="width: 100px;" i18n>Sensitive</th> | ||
26 | <th style="width: 120px;" i18n>Unfederated</th> | ||
27 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
28 | <th style="width: 150px;"></th> | ||
29 | </tr> | ||
30 | </ng-template> | ||
31 | |||
32 | <ng-template pTemplate="body" let-videoBlacklist let-expanded="expanded"> | ||
33 | <tr> | ||
34 | <td *ngIf="!videoBlacklist.reason"></td> | ||
35 | <td *ngIf="videoBlacklist.reason" class="expand-cell c-hand" [pRowToggler]="videoBlacklist" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body"> | ||
36 | <span class="expander"> | ||
37 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> | ||
38 | </span> | ||
39 | </td> | ||
40 | |||
41 | <td> | ||
42 | <a [href]="getVideoUrl(videoBlacklist)" class="video-table-video-link" i18n-title title="Open video in a new tab" target="_blank" rel="noopener noreferrer"> | ||
43 | <div class="video-table-video"> | ||
44 | <div class="video-table-video-image"> | ||
45 | <img [src]="videoBlacklist.video.thumbnailPath"> | ||
46 | </div> | ||
47 | <div class="video-table-video-text"> | ||
48 | <div> | ||
49 | {{ videoBlacklist.video.name }} | ||
50 | <span i18n-title title="Video was blacklisted" class="glyphicon glyphicon-ban-circle"></span> | ||
51 | </div> | ||
52 | <div class="text-muted">by {{ videoBlacklist.video.channel?.displayName }} on {{ videoBlacklist.video.channel?.host }} </div> | ||
53 | </div> | ||
54 | </div> | ||
55 | </a> | ||
56 | </td> | ||
57 | |||
58 | <ng-container *ngIf="videoBlacklist.reason"> | ||
59 | <td class="c-hand" [pRowToggler]="videoBlacklist">{{ booleanToText(videoBlacklist.video.nsfw) }}</td> | ||
60 | <td class="c-hand" [pRowToggler]="videoBlacklist">{{ booleanToText(videoBlacklist.unfederated) }}</td> | ||
61 | <td class="c-hand" [pRowToggler]="videoBlacklist">{{ videoBlacklist.createdAt | date: 'short' }}</td> | ||
62 | </ng-container> | ||
63 | <ng-container *ngIf="!videoBlacklist.reason"> | ||
64 | <td>{{ booleanToText(videoBlacklist.video.nsfw) }}</td> | ||
65 | <td>{{ booleanToText(videoBlacklist.unfederated) }}</td> | ||
66 | <td>{{ videoBlacklist.createdAt | date: 'short' }}</td> | ||
67 | </ng-container> | ||
68 | |||
69 | <td class="action-cell"> | ||
70 | <my-action-dropdown | ||
71 | [ngClass]="{ 'show': expanded }" placement="bottom-right" container="body" | ||
72 | i18n-label label="Actions" [actions]="videoBlacklistActions" [entry]="videoBlacklist" | ||
73 | ></my-action-dropdown> | ||
74 | </td> | ||
75 | </tr> | ||
76 | </ng-template> | ||
77 | |||
78 | <ng-template pTemplate="rowexpansion" let-videoBlacklist> | ||
79 | <tr> | ||
80 | <td class="expand-cell" colspan="6"> | ||
81 | <div class="d-flex moderation-expanded"> | ||
82 | <span class="col-2 moderation-expanded-label" i18n>Blacklist reason:</span> | ||
83 | <span class="col-9 moderation-expanded-text" [innerHTML]="videoBlacklist.reasonHtml"></span> | ||
84 | </div> | ||
85 | </td> | ||
86 | </tr> | ||
87 | </ng-template> | ||
88 | |||
89 | <ng-template pTemplate="emptymessage"> | ||
90 | <tr> | ||
91 | <td colspan="6"> | ||
92 | <div class="empty-table-message"> | ||
93 | <ng-container *ngIf="search" i18n>No blacklisted video found matching current filters.</ng-container> | ||
94 | <ng-container *ngIf="!search" i18n>No blacklisted video found.</ng-container> | ||
95 | </div> | ||
96 | </td> | ||
97 | </tr> | ||
98 | </ng-template> | ||
99 | </p-table> | ||
100 | |||
diff --git a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts b/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts deleted file mode 100644 index 63ecdeb9f..000000000 --- a/client/src/app/+admin/moderation/video-blacklist-list/video-blacklist-list.component.ts +++ /dev/null | |||
@@ -1,113 +0,0 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { SortMeta } from 'primeng/api' | ||
3 | import { Notifier, ServerService } from '@app/core' | ||
4 | import { ConfirmService } from '../../../core' | ||
5 | import { RestPagination, RestTable, VideoBlacklistService } from '../../../shared' | ||
6 | import { VideoBlacklist, VideoBlacklistType } from '../../../../../../shared' | ||
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
8 | import { DropdownAction } from '../../../shared/buttons/action-dropdown.component' | ||
9 | import { Video } from '../../../shared/video/video.model' | ||
10 | import { MarkdownService } from '@app/shared/renderer' | ||
11 | |||
12 | @Component({ | ||
13 | selector: 'my-video-blacklist-list', | ||
14 | templateUrl: './video-blacklist-list.component.html', | ||
15 | styleUrls: [ '../moderation.component.scss' ] | ||
16 | }) | ||
17 | export class VideoBlacklistListComponent extends RestTable implements OnInit { | ||
18 | blacklist: (VideoBlacklist & { reasonHtml?: string })[] = [] | ||
19 | totalRecords = 0 | ||
20 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
21 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
22 | listBlacklistTypeFilter: VideoBlacklistType = undefined | ||
23 | |||
24 | videoBlacklistActions: DropdownAction<VideoBlacklist>[] = [] | ||
25 | |||
26 | constructor ( | ||
27 | private notifier: Notifier, | ||
28 | private serverService: ServerService, | ||
29 | private confirmService: ConfirmService, | ||
30 | private videoBlacklistService: VideoBlacklistService, | ||
31 | private markdownRenderer: MarkdownService, | ||
32 | private i18n: I18n | ||
33 | ) { | ||
34 | super() | ||
35 | } | ||
36 | |||
37 | ngOnInit () { | ||
38 | this.serverService.getConfig() | ||
39 | .subscribe(config => { | ||
40 | // don't filter if auto-blacklist is not enabled as this will be the only list | ||
41 | if (config.autoBlacklist.videos.ofUsers.enabled) { | ||
42 | this.listBlacklistTypeFilter = VideoBlacklistType.MANUAL | ||
43 | } | ||
44 | }) | ||
45 | |||
46 | this.initialize() | ||
47 | |||
48 | this.videoBlacklistActions = [ | ||
49 | { | ||
50 | label: this.i18n('Unblacklist'), | ||
51 | handler: videoBlacklist => this.removeVideoFromBlacklist(videoBlacklist) | ||
52 | } | ||
53 | ] | ||
54 | } | ||
55 | |||
56 | getIdentifier () { | ||
57 | return 'VideoBlacklistListComponent' | ||
58 | } | ||
59 | |||
60 | getVideoUrl (videoBlacklist: VideoBlacklist) { | ||
61 | return Video.buildClientUrl(videoBlacklist.video.uuid) | ||
62 | } | ||
63 | |||
64 | booleanToText (value: boolean) { | ||
65 | if (value === true) return this.i18n('yes') | ||
66 | |||
67 | return this.i18n('no') | ||
68 | } | ||
69 | |||
70 | toHtml (text: string) { | ||
71 | return this.markdownRenderer.textMarkdownToHTML(text) | ||
72 | } | ||
73 | |||
74 | async removeVideoFromBlacklist (entry: VideoBlacklist) { | ||
75 | const confirmMessage = this.i18n( | ||
76 | 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.' | ||
77 | ) | ||
78 | |||
79 | const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblacklist')) | ||
80 | if (res === false) return | ||
81 | |||
82 | this.videoBlacklistService.removeVideoFromBlacklist(entry.video.id).subscribe( | ||
83 | () => { | ||
84 | this.notifier.success(this.i18n('Video {{name}} removed from the blacklist.', { name: entry.video.name })) | ||
85 | this.loadData() | ||
86 | }, | ||
87 | |||
88 | err => this.notifier.error(err.message) | ||
89 | ) | ||
90 | } | ||
91 | |||
92 | protected loadData () { | ||
93 | this.videoBlacklistService.listBlacklist({ | ||
94 | pagination: this.pagination, | ||
95 | sort: this.sort, | ||
96 | search: this.search, | ||
97 | type: this.listBlacklistTypeFilter | ||
98 | }) | ||
99 | .subscribe( | ||
100 | async resultList => { | ||
101 | this.totalRecords = resultList.total | ||
102 | |||
103 | this.blacklist = resultList.data | ||
104 | |||
105 | for (const element of this.blacklist) { | ||
106 | Object.assign(element, { reasonHtml: await this.toHtml(element.reason) }) | ||
107 | } | ||
108 | }, | ||
109 | |||
110 | err => this.notifier.error(err.message) | ||
111 | ) | ||
112 | } | ||
113 | } | ||
diff --git a/client/src/app/+admin/moderation/video-block-list/index.ts b/client/src/app/+admin/moderation/video-block-list/index.ts new file mode 100644 index 000000000..ec4de8f62 --- /dev/null +++ b/client/src/app/+admin/moderation/video-block-list/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './video-block-list.component' | |||
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html new file mode 100644 index 000000000..f3ec37314 --- /dev/null +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.html | |||
@@ -0,0 +1,113 @@ | |||
1 | <p-table | ||
2 | [value]="blocklist" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" | ||
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" | ||
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | ||
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} blocked videos" | ||
6 | (onPage)="onPage($event)" [expandedRowKeys]="expandedRows" | ||
7 | > | ||
8 | <ng-template pTemplate="caption"> | ||
9 | <div class="caption"> | ||
10 | <div class="ml-auto"> | ||
11 | <div class="input-group has-feedback has-clear"> | ||
12 | <div class="input-group-prepend c-hand" ngbDropdown placement="bottom-left auto" container="body"> | ||
13 | <div class="input-group-text" ngbDropdownToggle> | ||
14 | <span class="caret" aria-haspopup="menu" role="button"></span> | ||
15 | </div> | ||
16 | |||
17 | <div role="menu" ngbDropdownMenu> | ||
18 | <h6 class="dropdown-header" i18n>Advanced block filters</h6> | ||
19 | <a [routerLink]="[ '/admin/moderation/video-blocks/list' ]" [queryParams]="{ 'search': 'type:auto' }" class="dropdown-item" i18n>Automatic blocks</a> | ||
20 | <a [routerLink]="[ '/admin/moderation/video-blocks/list' ]" [queryParams]="{ 'search': 'type:manual' }" class="dropdown-item" i18n>Manual blocks</a> | ||
21 | </div> | ||
22 | </div> | ||
23 | <input | ||
24 | type="text" name="table-filter" id="table-filter" i18n-placeholder placeholder="Filter..." | ||
25 | (keyup)="onBlockSearch($event)" | ||
26 | > | ||
27 | <a class="glyphicon glyphicon-remove-sign form-control-feedback form-control-clear" (click)="resetTableFilter()"></a> | ||
28 | <span class="sr-only" i18n>Clear filters</span> | ||
29 | </div> | ||
30 | </div> | ||
31 | </div> | ||
32 | </ng-template> | ||
33 | |||
34 | <ng-template pTemplate="header"> | ||
35 | <tr> | ||
36 | <th style="width: 40px"></th> | ||
37 | <th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th> | ||
38 | <th style="width: 100px;" i18n>Sensitive</th> | ||
39 | <th style="width: 120px;" i18n>Unfederated</th> | ||
40 | <th style="width: 150px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
41 | <th style="width: 150px;"></th> | ||
42 | </tr> | ||
43 | </ng-template> | ||
44 | |||
45 | <ng-template pTemplate="body" let-videoBlock let-expanded="expanded"> | ||
46 | <tr> | ||
47 | <td *ngIf="!videoBlock.reason"></td> | ||
48 | <td *ngIf="videoBlock.reason" class="expand-cell c-hand" [pRowToggler]="videoBlock" i18n-ngbTooltip ngbTooltip="More information" placement="top-left" container="body"> | ||
49 | <span class="expander"> | ||
50 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> | ||
51 | </span> | ||
52 | </td> | ||
53 | |||
54 | <td> | ||
55 | <a [href]="getVideoUrl(videoBlock)" class="video-table-video-link" i18n-title title="Open video in a new tab" target="_blank" rel="noopener noreferrer"> | ||
56 | <div class="video-table-video"> | ||
57 | <div class="video-table-video-image"> | ||
58 | <img [src]="videoBlock.video.thumbnailPath"> | ||
59 | </div> | ||
60 | <div class="video-table-video-text"> | ||
61 | <div> | ||
62 | <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> | ||
63 | {{ videoBlock.video.name }} | ||
64 | </div> | ||
65 | <div class="text-muted">by {{ videoBlock.video.channel?.displayName }} on {{ videoBlock.video.channel?.host }} </div> | ||
66 | </div> | ||
67 | </div> | ||
68 | </a> | ||
69 | </td> | ||
70 | |||
71 | <ng-container *ngIf="videoBlock.reason"> | ||
72 | <td class="c-hand" [pRowToggler]="videoBlock">{{ booleanToText(videoBlock.video.nsfw) }}</td> | ||
73 | <td class="c-hand" [pRowToggler]="videoBlock">{{ booleanToText(videoBlock.unfederated) }}</td> | ||
74 | <td class="c-hand" [pRowToggler]="videoBlock">{{ videoBlock.createdAt | date: 'short' }}</td> | ||
75 | </ng-container> | ||
76 | <ng-container *ngIf="!videoBlock.reason"> | ||
77 | <td>{{ booleanToText(videoBlock.video.nsfw) }}</td> | ||
78 | <td>{{ booleanToText(videoBlock.unfederated) }}</td> | ||
79 | <td>{{ videoBlock.createdAt | date: 'short' }}</td> | ||
80 | </ng-container> | ||
81 | |||
82 | <td class="action-cell"> | ||
83 | <my-action-dropdown | ||
84 | [ngClass]="{ 'show': expanded }" placement="bottom-right" container="body" | ||
85 | i18n-label label="Actions" [actions]="videoBlocklistActions" [entry]="videoBlock" | ||
86 | ></my-action-dropdown> | ||
87 | </td> | ||
88 | </tr> | ||
89 | </ng-template> | ||
90 | |||
91 | <ng-template pTemplate="rowexpansion" let-videoBlock> | ||
92 | <tr> | ||
93 | <td class="expand-cell" colspan="6"> | ||
94 | <div class="d-flex moderation-expanded"> | ||
95 | <span class="col-2 moderation-expanded-label" i18n>Block reason:</span> | ||
96 | <span class="col-9 moderation-expanded-text" [innerHTML]="videoBlock.reasonHtml"></span> | ||
97 | </div> | ||
98 | </td> | ||
99 | </tr> | ||
100 | </ng-template> | ||
101 | |||
102 | <ng-template pTemplate="emptymessage"> | ||
103 | <tr> | ||
104 | <td colspan="6"> | ||
105 | <div class="empty-table-message"> | ||
106 | <ng-container *ngIf="search" i18n>No blocked video found matching current filters.</ng-container> | ||
107 | <ng-container *ngIf="!search" i18n>No blocked video found.</ng-container> | ||
108 | </div> | ||
109 | </td> | ||
110 | </tr> | ||
111 | </ng-template> | ||
112 | </p-table> | ||
113 | |||
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.scss b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.scss new file mode 100644 index 000000000..43a365608 --- /dev/null +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.scss | |||
@@ -0,0 +1,18 @@ | |||
1 | @import 'mixins'; | ||
2 | |||
3 | my-global-icon { | ||
4 | @include apply-svg-color(#7d7d7d); | ||
5 | |||
6 | width: 12px; | ||
7 | height: 12px; | ||
8 | position: relative; | ||
9 | top: -1px; | ||
10 | } | ||
11 | |||
12 | .input-group { | ||
13 | @include peertube-input-group(300px); | ||
14 | |||
15 | .dropdown-toggle::after { | ||
16 | margin-left: 0; | ||
17 | } | ||
18 | } | ||
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts new file mode 100644 index 000000000..e72ab5348 --- /dev/null +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts | |||
@@ -0,0 +1,196 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | ||
2 | import { SortMeta } from 'primeng/api' | ||
3 | import { Notifier, ServerService } from '@app/core' | ||
4 | import { ConfirmService } from '../../../core' | ||
5 | import { RestPagination, RestTable, VideoBlockService } from '../../../shared' | ||
6 | import { VideoBlocklist, VideoBlockType } from '../../../../../../shared' | ||
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
8 | import { DropdownAction } from '../../../shared/buttons/action-dropdown.component' | ||
9 | import { Video } from '../../../shared/video/video.model' | ||
10 | import { MarkdownService } from '@app/shared/renderer' | ||
11 | import { Params, ActivatedRoute, Router } from '@angular/router' | ||
12 | import { filter, switchMap } from 'rxjs/operators' | ||
13 | import { VideoService } from '@app/shared/video/video.service' | ||
14 | |||
15 | @Component({ | ||
16 | selector: 'my-video-block-list', | ||
17 | templateUrl: './video-block-list.component.html', | ||
18 | styleUrls: [ '../moderation.component.scss', './video-block-list.component.scss' ] | ||
19 | }) | ||
20 | export class VideoBlockListComponent extends RestTable implements OnInit { | ||
21 | blocklist: (VideoBlocklist & { reasonHtml?: string })[] = [] | ||
22 | totalRecords = 0 | ||
23 | sort: SortMeta = { field: 'createdAt', order: -1 } | ||
24 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
25 | listBlockTypeFilter: VideoBlockType = undefined | ||
26 | |||
27 | videoBlocklistActions: DropdownAction<VideoBlocklist>[][] = [] | ||
28 | |||
29 | constructor ( | ||
30 | private notifier: Notifier, | ||
31 | private serverService: ServerService, | ||
32 | private confirmService: ConfirmService, | ||
33 | private videoBlocklistService: VideoBlockService, | ||
34 | private markdownRenderer: MarkdownService, | ||
35 | private videoService: VideoService, | ||
36 | private route: ActivatedRoute, | ||
37 | private router: Router, | ||
38 | private i18n: I18n | ||
39 | ) { | ||
40 | super() | ||
41 | |||
42 | this.videoBlocklistActions = [ | ||
43 | [ | ||
44 | { | ||
45 | label: this.i18n('Internal actions'), | ||
46 | isHeader: true | ||
47 | }, | ||
48 | { | ||
49 | label: this.i18n('Switch video block to manual'), | ||
50 | handler: videoBlock => { | ||
51 | this.videoBlocklistService.unblockVideo(videoBlock.video.id).pipe( | ||
52 | switchMap(_ => this.videoBlocklistService.blockVideo(videoBlock.video.id, undefined, true)) | ||
53 | ).subscribe( | ||
54 | () => { | ||
55 | this.notifier.success(this.i18n('Video {{name}} switched to manual block.', { name: videoBlock.video.name })) | ||
56 | this.loadData() | ||
57 | }, | ||
58 | |||
59 | err => this.notifier.error(err.message) | ||
60 | ) | ||
61 | } | ||
62 | } | ||
63 | ], | ||
64 | [ | ||
65 | { | ||
66 | label: this.i18n('Actions for the video'), | ||
67 | isHeader: true, | ||
68 | }, | ||
69 | { | ||
70 | label: this.i18n('Unblock video'), | ||
71 | handler: videoBlock => this.unblockVideo(videoBlock) | ||
72 | }, | ||
73 | |||
74 | { | ||
75 | label: this.i18n('Delete video'), | ||
76 | handler: async videoBlock => { | ||
77 | const res = await this.confirmService.confirm( | ||
78 | this.i18n('Do you really want to delete this video?'), | ||
79 | this.i18n('Delete') | ||
80 | ) | ||
81 | if (res === false) return | ||
82 | |||
83 | this.videoService.removeVideo(videoBlock.video.id) | ||
84 | .subscribe( | ||
85 | () => { | ||
86 | this.notifier.success(this.i18n('Video deleted.')) | ||
87 | }, | ||
88 | |||
89 | err => this.notifier.error(err.message) | ||
90 | ) | ||
91 | } | ||
92 | } | ||
93 | ] | ||
94 | ] | ||
95 | } | ||
96 | |||
97 | ngOnInit () { | ||
98 | this.serverService.getConfig() | ||
99 | .subscribe(config => { | ||
100 | // don't filter if auto-blacklist is not enabled as this will be the only list | ||
101 | if (config.autoBlacklist.videos.ofUsers.enabled) { | ||
102 | this.listBlockTypeFilter = VideoBlockType.MANUAL | ||
103 | } | ||
104 | }) | ||
105 | |||
106 | this.initialize() | ||
107 | |||
108 | this.route.queryParams | ||
109 | .pipe(filter(params => params.search !== undefined && params.search !== null)) | ||
110 | .subscribe(params => { | ||
111 | this.search = params.search | ||
112 | this.setTableFilter(params.search) | ||
113 | this.loadData() | ||
114 | }) | ||
115 | } | ||
116 | |||
117 | ngAfterViewInit () { | ||
118 | if (this.search) this.setTableFilter(this.search) | ||
119 | } | ||
120 | |||
121 | /* Table filter functions */ | ||
122 | onBlockSearch (event: Event) { | ||
123 | this.onSearch(event) | ||
124 | this.setQueryParams((event.target as HTMLInputElement).value) | ||
125 | } | ||
126 | |||
127 | setQueryParams (search: string) { | ||
128 | const queryParams: Params = {} | ||
129 | if (search) Object.assign(queryParams, { search }) | ||
130 | this.router.navigate([ '/admin/moderation/video-blocks/list' ], { queryParams }) | ||
131 | } | ||
132 | |||
133 | resetTableFilter () { | ||
134 | this.setTableFilter('') | ||
135 | this.setQueryParams('') | ||
136 | this.resetSearch() | ||
137 | } | ||
138 | /* END Table filter functions */ | ||
139 | |||
140 | getIdentifier () { | ||
141 | return 'VideoBlockListComponent' | ||
142 | } | ||
143 | |||
144 | getVideoUrl (videoBlock: VideoBlocklist) { | ||
145 | return Video.buildClientUrl(videoBlock.video.uuid) | ||
146 | } | ||
147 | |||
148 | booleanToText (value: boolean) { | ||
149 | if (value === true) return this.i18n('yes') | ||
150 | |||
151 | return this.i18n('no') | ||
152 | } | ||
153 | |||
154 | toHtml (text: string) { | ||
155 | return this.markdownRenderer.textMarkdownToHTML(text) | ||
156 | } | ||
157 | |||
158 | async unblockVideo (entry: VideoBlocklist) { | ||
159 | const confirmMessage = this.i18n( | ||
160 | 'Do you really want to unblock this video? It will be available again in the videos list.' | ||
161 | ) | ||
162 | |||
163 | const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblock')) | ||
164 | if (res === false) return | ||
165 | |||
166 | this.videoBlocklistService.unblockVideo(entry.video.id).subscribe( | ||
167 | () => { | ||
168 | this.notifier.success(this.i18n('Video {{name}} unblocked.', { name: entry.video.name })) | ||
169 | this.loadData() | ||
170 | }, | ||
171 | |||
172 | err => this.notifier.error(err.message) | ||
173 | ) | ||
174 | } | ||
175 | |||
176 | protected loadData () { | ||
177 | this.videoBlocklistService.listBlocks({ | ||
178 | pagination: this.pagination, | ||
179 | sort: this.sort, | ||
180 | search: this.search, | ||
181 | }) | ||
182 | .subscribe( | ||
183 | async resultList => { | ||
184 | this.totalRecords = resultList.total | ||
185 | |||
186 | this.blocklist = resultList.data | ||
187 | |||
188 | for (const element of this.blocklist) { | ||
189 | Object.assign(element, { reasonHtml: await this.toHtml(element.reason) }) | ||
190 | } | ||
191 | }, | ||
192 | |||
193 | err => this.notifier.error(err.message) | ||
194 | ) | ||
195 | } | ||
196 | } | ||
diff --git a/client/src/app/+admin/users/user-edit/user-edit.ts b/client/src/app/+admin/users/user-edit/user-edit.ts index 6e2952c44..98249bcc1 100644 --- a/client/src/app/+admin/users/user-edit/user-edit.ts +++ b/client/src/app/+admin/users/user-edit/user-edit.ts | |||
@@ -88,7 +88,7 @@ export abstract class UserEdit extends FormReactive implements OnInit { | |||
88 | } | 88 | } |
89 | 89 | ||
90 | protected buildAdminFlags (formValue: any) { | 90 | protected buildAdminFlags (formValue: any) { |
91 | return formValue.byPassAutoBlacklist ? UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST : UserAdminFlag.NONE | 91 | return formValue.byPassAutoBlacklist ? UserAdminFlag.BYPASS_VIDEO_AUTO_BLOCK : UserAdminFlag.NONE |
92 | } | 92 | } |
93 | 93 | ||
94 | protected buildQuotaOptions () { | 94 | protected buildQuotaOptions () { |
diff --git a/client/src/app/+admin/users/user-edit/user-update.component.ts b/client/src/app/+admin/users/user-edit/user-update.component.ts index e0e1fbddf..f2bd8c8ec 100644 --- a/client/src/app/+admin/users/user-edit/user-update.component.ts +++ b/client/src/app/+admin/users/user-edit/user-update.component.ts | |||
@@ -125,7 +125,7 @@ export class UserUpdateComponent extends UserEdit implements OnInit, OnDestroy { | |||
125 | role: userJson.role.toString(), | 125 | role: userJson.role.toString(), |
126 | videoQuota: userJson.videoQuota, | 126 | videoQuota: userJson.videoQuota, |
127 | videoQuotaDaily: userJson.videoQuotaDaily, | 127 | videoQuotaDaily: userJson.videoQuotaDaily, |
128 | byPassAutoBlacklist: userJson.adminFlags & UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST | 128 | byPassAutoBlacklist: userJson.adminFlags & UserAdminFlag.BYPASS_VIDEO_AUTO_BLOCK |
129 | }) | 129 | }) |
130 | } | 130 | } |
131 | } | 131 | } |
diff --git a/client/src/app/+my-account/my-account-history/my-account-history.component.html b/client/src/app/+my-account/my-account-history/my-account-history.component.html index d3a329e8f..817b929fe 100644 --- a/client/src/app/+my-account/my-account-history/my-account-history.component.html +++ b/client/src/app/+my-account/my-account-history/my-account-history.component.html | |||
@@ -17,6 +17,6 @@ | |||
17 | <div class="video" *ngFor="let video of videos"> | 17 | <div class="video" *ngFor="let video of videos"> |
18 | <my-video-miniature | 18 | <my-video-miniature |
19 | [video]="video" [displayAsRow]="true" | 19 | [video]="video" [displayAsRow]="true" |
20 | (videoRemoved)="removeVideoFromArray(video)" (videoBlacklisted)="removeVideoFromArray(video)"></my-video-miniature> | 20 | (videoRemoved)="removeVideoFromArray(video)" (videoBlocked)="removeVideoFromArray(video)"></my-video-miniature> |
21 | </div> | 21 | </div> |
22 | </div> | 22 | </div> |
diff --git a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts index 6ba1a1020..72e26ac28 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-notification-preferences/my-account-notification-preferences.component.ts | |||
@@ -35,8 +35,8 @@ export class MyAccountNotificationPreferencesComponent implements OnInit { | |||
35 | newVideoFromSubscription: this.i18n('New video from your subscriptions'), | 35 | newVideoFromSubscription: this.i18n('New video from your subscriptions'), |
36 | newCommentOnMyVideo: this.i18n('New comment on your video'), | 36 | newCommentOnMyVideo: this.i18n('New comment on your video'), |
37 | videoAbuseAsModerator: this.i18n('New video abuse'), | 37 | videoAbuseAsModerator: this.i18n('New video abuse'), |
38 | videoAutoBlacklistAsModerator: this.i18n('Video auto-blacklisted waiting review'), | 38 | videoAutoBlacklistAsModerator: this.i18n('Video blocked automatically waiting review'), |
39 | blacklistOnMyVideo: this.i18n('One of your video is blacklisted/unblacklisted'), | 39 | blacklistOnMyVideo: this.i18n('One of your video is blocked/unblocked'), |
40 | myVideoPublished: this.i18n('Video published (after transcoding/scheduled update)'), | 40 | myVideoPublished: this.i18n('Video published (after transcoding/scheduled update)'), |
41 | myVideoImportFinished: this.i18n('Video import finished'), | 41 | myVideoImportFinished: this.i18n('Video import finished'), |
42 | newUserRegistration: this.i18n('A new user registered on your instance'), | 42 | newUserRegistration: this.i18n('A new user registered on your instance'), |
@@ -49,7 +49,7 @@ export class MyAccountNotificationPreferencesComponent implements OnInit { | |||
49 | 49 | ||
50 | this.rightNotifications = { | 50 | this.rightNotifications = { |
51 | videoAbuseAsModerator: UserRight.MANAGE_VIDEO_ABUSES, | 51 | videoAbuseAsModerator: UserRight.MANAGE_VIDEO_ABUSES, |
52 | videoAutoBlacklistAsModerator: UserRight.MANAGE_VIDEO_BLACKLIST, | 52 | videoAutoBlacklistAsModerator: UserRight.MANAGE_VIDEO_BLOCKS, |
53 | newUserRegistration: UserRight.MANAGE_USERS, | 53 | newUserRegistration: UserRight.MANAGE_USERS, |
54 | newInstanceFollower: UserRight.MANAGE_SERVER_FOLLOW, | 54 | newInstanceFollower: UserRight.MANAGE_SERVER_FOLLOW, |
55 | autoInstanceFollowing: UserRight.MANAGE_CONFIGURATION | 55 | autoInstanceFollowing: UserRight.MANAGE_CONFIGURATION |
diff --git a/client/src/app/menu/menu.component.ts b/client/src/app/menu/menu.component.ts index 015c14bce..79bf29e9c 100644 --- a/client/src/app/menu/menu.component.ts +++ b/client/src/app/menu/menu.component.ts | |||
@@ -33,7 +33,7 @@ export class MenuComponent implements OnInit { | |||
33 | [UserRight.MANAGE_USERS]: '/admin/users', | 33 | [UserRight.MANAGE_USERS]: '/admin/users', |
34 | [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends', | 34 | [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends', |
35 | [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/moderation/video-abuses', | 35 | [UserRight.MANAGE_VIDEO_ABUSES]: '/admin/moderation/video-abuses', |
36 | [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/moderation/video-blacklist', | 36 | [UserRight.MANAGE_VIDEO_BLOCKS]: '/admin/moderation/video-blocks', |
37 | [UserRight.MANAGE_JOBS]: '/admin/jobs', | 37 | [UserRight.MANAGE_JOBS]: '/admin/jobs', |
38 | [UserRight.MANAGE_CONFIGURATION]: '/admin/config' | 38 | [UserRight.MANAGE_CONFIGURATION]: '/admin/config' |
39 | } | 39 | } |
@@ -131,7 +131,7 @@ export class MenuComponent implements OnInit { | |||
131 | UserRight.MANAGE_USERS, | 131 | UserRight.MANAGE_USERS, |
132 | UserRight.MANAGE_SERVER_FOLLOW, | 132 | UserRight.MANAGE_SERVER_FOLLOW, |
133 | UserRight.MANAGE_VIDEO_ABUSES, | 133 | UserRight.MANAGE_VIDEO_ABUSES, |
134 | UserRight.MANAGE_VIDEO_BLACKLIST, | 134 | UserRight.MANAGE_VIDEO_BLOCKS, |
135 | UserRight.MANAGE_JOBS, | 135 | UserRight.MANAGE_JOBS, |
136 | UserRight.MANAGE_CONFIGURATION | 136 | UserRight.MANAGE_CONFIGURATION |
137 | ] | 137 | ] |
diff --git a/client/src/app/search/search.component.html b/client/src/app/search/search.component.html index 3cafc676d..d723606db 100644 --- a/client/src/app/search/search.component.html +++ b/client/src/app/search/search.component.html | |||
@@ -55,7 +55,7 @@ | |||
55 | <my-video-miniature | 55 | <my-video-miniature |
56 | [video]="result" [user]="user" [displayAsRow]="true" [displayVideoActions]="!hideActions()" | 56 | [video]="result" [user]="user" [displayAsRow]="true" [displayVideoActions]="!hideActions()" |
57 | [useLazyLoadUrl]="advancedSearch.searchTarget === 'search-index'" | 57 | [useLazyLoadUrl]="advancedSearch.searchTarget === 'search-index'" |
58 | (videoBlacklisted)="removeVideoFromArray(result)" (videoRemoved)="removeVideoFromArray(result)" | 58 | (videoBlocked)="removeVideoFromArray(result)" (videoRemoved)="removeVideoFromArray(result)" |
59 | ></my-video-miniature> | 59 | ></my-video-miniature> |
60 | </div> | 60 | </div> |
61 | </ng-container> | 61 | </ng-container> |
diff --git a/client/src/app/shared/forms/form-validators/index.ts b/client/src/app/shared/forms/form-validators/index.ts index e3de3ae13..4a01b1622 100644 --- a/client/src/app/shared/forms/form-validators/index.ts +++ b/client/src/app/shared/forms/form-validators/index.ts | |||
@@ -6,7 +6,7 @@ export * from './login-validators.service' | |||
6 | export * from './reset-password-validators.service' | 6 | export * from './reset-password-validators.service' |
7 | export * from './user-validators.service' | 7 | export * from './user-validators.service' |
8 | export * from './video-abuse-validators.service' | 8 | export * from './video-abuse-validators.service' |
9 | export * from './video-blacklist-validators.service' | 9 | export * from './video-block-validators.service' |
10 | export * from './video-channel-validators.service' | 10 | export * from './video-channel-validators.service' |
11 | export * from './video-comment-validators.service' | 11 | export * from './video-comment-validators.service' |
12 | export * from './video-validators.service' | 12 | export * from './video-validators.service' |
diff --git a/client/src/app/shared/forms/form-validators/video-blacklist-validators.service.ts b/client/src/app/shared/forms/form-validators/video-block-validators.service.ts index 07d1f264a..dc8257761 100644 --- a/client/src/app/shared/forms/form-validators/video-blacklist-validators.service.ts +++ b/client/src/app/shared/forms/form-validators/video-block-validators.service.ts | |||
@@ -4,15 +4,15 @@ import { Injectable } from '@angular/core' | |||
4 | import { BuildFormValidator } from '@app/shared' | 4 | import { BuildFormValidator } from '@app/shared' |
5 | 5 | ||
6 | @Injectable() | 6 | @Injectable() |
7 | export class VideoBlacklistValidatorsService { | 7 | export class VideoBlockValidatorsService { |
8 | readonly VIDEO_BLACKLIST_REASON: BuildFormValidator | 8 | readonly VIDEO_BLOCK_REASON: BuildFormValidator |
9 | 9 | ||
10 | constructor (private i18n: I18n) { | 10 | constructor (private i18n: I18n) { |
11 | this.VIDEO_BLACKLIST_REASON = { | 11 | this.VIDEO_BLOCK_REASON = { |
12 | VALIDATORS: [ Validators.minLength(2), Validators.maxLength(300) ], | 12 | VALIDATORS: [ Validators.minLength(2), Validators.maxLength(300) ], |
13 | MESSAGES: { | 13 | MESSAGES: { |
14 | 'minlength': this.i18n('Blacklist reason must be at least 2 characters long.'), | 14 | 'minlength': this.i18n('Block reason must be at least 2 characters long.'), |
15 | 'maxlength': this.i18n('Blacklist reason cannot be more than 300 characters long.') | 15 | 'maxlength': this.i18n('Block reason cannot be more than 300 characters long.') |
16 | } | 16 | } |
17 | } | 17 | } |
18 | } | 18 | } |
diff --git a/client/src/app/shared/images/global-icon.component.ts b/client/src/app/shared/images/global-icon.component.ts index d2700f6c3..169882685 100644 --- a/client/src/app/shared/images/global-icon.component.ts +++ b/client/src/app/shared/images/global-icon.component.ts | |||
@@ -56,7 +56,8 @@ const icons = { | |||
56 | 'refresh': require('!!raw-loader?!../../../assets/images/global/refresh.svg').default, | 56 | 'refresh': require('!!raw-loader?!../../../assets/images/global/refresh.svg').default, |
57 | 'npm': require('!!raw-loader?!../../../assets/images/global/npm.svg').default, | 57 | 'npm': require('!!raw-loader?!../../../assets/images/global/npm.svg').default, |
58 | 'fullscreen': require('!!raw-loader?!../../../assets/images/global/fullscreen.svg').default, | 58 | 'fullscreen': require('!!raw-loader?!../../../assets/images/global/fullscreen.svg').default, |
59 | 'exit-fullscreen': require('!!raw-loader?!../../../assets/images/global/exit-fullscreen.svg').default | 59 | 'exit-fullscreen': require('!!raw-loader?!../../../assets/images/global/exit-fullscreen.svg').default, |
60 | 'robot': require('!!raw-loader?!../../../assets/images/global/robot.svg').default | ||
60 | } | 61 | } |
61 | 62 | ||
62 | export type GlobalIconName = keyof typeof icons | 63 | export type GlobalIconName = keyof typeof icons |
diff --git a/client/src/app/shared/index.ts b/client/src/app/shared/index.ts index 136730c91..8be578d9f 100644 --- a/client/src/app/shared/index.ts +++ b/client/src/app/shared/index.ts | |||
@@ -3,5 +3,5 @@ export * from './forms' | |||
3 | export * from './rest' | 3 | export * from './rest' |
4 | export * from './users' | 4 | export * from './users' |
5 | export * from './video-abuse' | 5 | export * from './video-abuse' |
6 | export * from './video-blacklist' | 6 | export * from './video-block' |
7 | export * from './shared.module' | 7 | export * from './shared.module' |
diff --git a/client/src/app/shared/shared.module.ts b/client/src/app/shared/shared.module.ts index 813f76672..2035097d7 100644 --- a/client/src/app/shared/shared.module.ts +++ b/client/src/app/shared/shared.module.ts | |||
@@ -35,7 +35,7 @@ import { | |||
35 | UserValidatorsService, | 35 | UserValidatorsService, |
36 | VideoAbuseValidatorsService, | 36 | VideoAbuseValidatorsService, |
37 | VideoAcceptOwnershipValidatorsService, | 37 | VideoAcceptOwnershipValidatorsService, |
38 | VideoBlacklistValidatorsService, | 38 | VideoBlockValidatorsService, |
39 | VideoChangeOwnershipValidatorsService, | 39 | VideoChangeOwnershipValidatorsService, |
40 | VideoChannelValidatorsService, | 40 | VideoChannelValidatorsService, |
41 | VideoCommentValidatorsService, | 41 | VideoCommentValidatorsService, |
@@ -78,7 +78,7 @@ import { VideoPlaylistElementMiniatureComponent } from '@app/shared/video-playli | |||
78 | import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component' | 78 | import { VideoPlaylistMiniatureComponent } from '@app/shared/video-playlist/video-playlist-miniature.component' |
79 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' | 79 | import { VideoPlaylistService } from '@app/shared/video-playlist/video-playlist.service' |
80 | import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive' | 80 | import { InfiniteScrollerDirective } from '@app/shared/video/infinite-scroller.directive' |
81 | import { VideoBlacklistComponent } from '@app/shared/video/modals/video-blacklist.component' | 81 | import { VideoBlockComponent } from '@app/shared/video/modals/video-block.component' |
82 | import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component' | 82 | import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component' |
83 | import { VideoReportComponent } from '@app/shared/video/modals/video-report.component' | 83 | import { VideoReportComponent } from '@app/shared/video/modals/video-report.component' |
84 | import { RedundancyService } from '@app/shared/video/redundancy.service' | 84 | import { RedundancyService } from '@app/shared/video/redundancy.service' |
@@ -102,7 +102,7 @@ import { LoaderComponent } from './misc/loader.component' | |||
102 | import { RestExtractor, RestService } from './rest' | 102 | import { RestExtractor, RestService } from './rest' |
103 | import { UserService } from './users' | 103 | import { UserService } from './users' |
104 | import { VideoAbuseService } from './video-abuse' | 104 | import { VideoAbuseService } from './video-abuse' |
105 | import { VideoBlacklistService } from './video-blacklist' | 105 | import { VideoBlockService } from './video-block' |
106 | import { VideoOwnershipService } from './video-ownership' | 106 | import { VideoOwnershipService } from './video-ownership' |
107 | import { FeedComponent } from './video/feed.component' | 107 | import { FeedComponent } from './video/feed.component' |
108 | import { VideoMiniatureComponent } from './video/video-miniature.component' | 108 | import { VideoMiniatureComponent } from './video/video-miniature.component' |
@@ -147,7 +147,7 @@ import { VideoService } from './video/video.service' | |||
147 | 147 | ||
148 | VideoDownloadComponent, | 148 | VideoDownloadComponent, |
149 | VideoReportComponent, | 149 | VideoReportComponent, |
150 | VideoBlacklistComponent, | 150 | VideoBlockComponent, |
151 | 151 | ||
152 | FeedComponent, | 152 | FeedComponent, |
153 | 153 | ||
@@ -230,7 +230,7 @@ import { VideoService } from './video/video.service' | |||
230 | 230 | ||
231 | VideoDownloadComponent, | 231 | VideoDownloadComponent, |
232 | VideoReportComponent, | 232 | VideoReportComponent, |
233 | VideoBlacklistComponent, | 233 | VideoBlockComponent, |
234 | 234 | ||
235 | FeedComponent, | 235 | FeedComponent, |
236 | 236 | ||
@@ -282,7 +282,7 @@ import { VideoService } from './video/video.service' | |||
282 | RestExtractor, | 282 | RestExtractor, |
283 | RestService, | 283 | RestService, |
284 | VideoAbuseService, | 284 | VideoAbuseService, |
285 | VideoBlacklistService, | 285 | VideoBlockService, |
286 | VideoOwnershipService, | 286 | VideoOwnershipService, |
287 | UserService, | 287 | UserService, |
288 | VideoService, | 288 | VideoService, |
@@ -305,7 +305,7 @@ import { VideoService } from './video/video.service' | |||
305 | VideoCommentValidatorsService, | 305 | VideoCommentValidatorsService, |
306 | VideoValidatorsService, | 306 | VideoValidatorsService, |
307 | VideoCaptionsValidatorsService, | 307 | VideoCaptionsValidatorsService, |
308 | VideoBlacklistValidatorsService, | 308 | VideoBlockValidatorsService, |
309 | OverviewService, | 309 | OverviewService, |
310 | VideoChangeOwnershipValidatorsService, | 310 | VideoChangeOwnershipValidatorsService, |
311 | VideoAcceptOwnershipValidatorsService, | 311 | VideoAcceptOwnershipValidatorsService, |
diff --git a/client/src/app/shared/users/user-notification.model.ts b/client/src/app/shared/users/user-notification.model.ts index 7b8368d87..bc1861c64 100644 --- a/client/src/app/shared/users/user-notification.model.ts +++ b/client/src/app/shared/users/user-notification.model.ts | |||
@@ -96,7 +96,7 @@ export class UserNotification implements UserNotificationServer { | |||
96 | this.videoUrl = this.buildVideoUrl(this.video) | 96 | this.videoUrl = this.buildVideoUrl(this.video) |
97 | break | 97 | break |
98 | 98 | ||
99 | case UserNotificationType.UNBLACKLIST_ON_MY_VIDEO: | 99 | case UserNotificationType.UNBLOCK_ON_MY_VIDEO: |
100 | this.videoUrl = this.buildVideoUrl(this.video) | 100 | this.videoUrl = this.buildVideoUrl(this.video) |
101 | break | 101 | break |
102 | 102 | ||
@@ -112,7 +112,7 @@ export class UserNotification implements UserNotificationServer { | |||
112 | this.videoUrl = this.buildVideoUrl(this.videoAbuse.video) | 112 | this.videoUrl = this.buildVideoUrl(this.videoAbuse.video) |
113 | break | 113 | break |
114 | 114 | ||
115 | case UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS: | 115 | case UserNotificationType.VIDEO_AUTO_BLOCK_FOR_MODERATORS: |
116 | this.videoAutoBlacklistUrl = '/admin/moderation/video-auto-blacklist/list' | 116 | this.videoAutoBlacklistUrl = '/admin/moderation/video-auto-blacklist/list' |
117 | // Backward compatibility where we did not assign videoBlacklist to this type of notification before | 117 | // Backward compatibility where we did not assign videoBlacklist to this type of notification before |
118 | if (!this.videoBlacklist) this.videoBlacklist = { id: null, video: this.video } | 118 | if (!this.videoBlacklist) this.videoBlacklist = { id: null, video: this.video } |
@@ -120,7 +120,7 @@ export class UserNotification implements UserNotificationServer { | |||
120 | this.videoUrl = this.buildVideoUrl(this.videoBlacklist.video) | 120 | this.videoUrl = this.buildVideoUrl(this.videoBlacklist.video) |
121 | break | 121 | break |
122 | 122 | ||
123 | case UserNotificationType.BLACKLIST_ON_MY_VIDEO: | 123 | case UserNotificationType.BLOCK_ON_MY_VIDEO: |
124 | this.videoUrl = this.buildVideoUrl(this.videoBlacklist.video) | 124 | this.videoUrl = this.buildVideoUrl(this.videoBlacklist.video) |
125 | break | 125 | break |
126 | 126 | ||
diff --git a/client/src/app/shared/users/user-notifications.component.html b/client/src/app/shared/users/user-notifications.component.html index 8dbe6e329..5a102995a 100644 --- a/client/src/app/shared/users/user-notifications.component.html +++ b/client/src/app/shared/users/user-notifications.component.html | |||
@@ -26,19 +26,19 @@ | |||
26 | </ng-template> | 26 | </ng-template> |
27 | </ng-container> | 27 | </ng-container> |
28 | 28 | ||
29 | <ng-container *ngSwitchCase="UserNotificationType.UNBLACKLIST_ON_MY_VIDEO"> | 29 | <ng-container *ngSwitchCase="UserNotificationType.UNBLOCK_ON_MY_VIDEO"> |
30 | <my-global-icon iconName="undo"></my-global-icon> | 30 | <my-global-icon iconName="undo"></my-global-icon> |
31 | 31 | ||
32 | <div class="message" i18n> | 32 | <div class="message" i18n> |
33 | Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.video.name }}</a> has been unblacklisted | 33 | Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.video.name }}</a> has been unblocked |
34 | </div> | 34 | </div> |
35 | </ng-container> | 35 | </ng-container> |
36 | 36 | ||
37 | <ng-container *ngSwitchCase="UserNotificationType.BLACKLIST_ON_MY_VIDEO"> | 37 | <ng-container *ngSwitchCase="UserNotificationType.BLOCK_ON_MY_VIDEO"> |
38 | <my-global-icon iconName="no"></my-global-icon> | 38 | <my-global-icon iconName="no"></my-global-icon> |
39 | 39 | ||
40 | <div class="message" i18n> | 40 | <div class="message" i18n> |
41 | Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.videoBlacklist.video.name }}</a> has been blacklisted | 41 | Your video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.videoBlacklist.video.name }}</a> has been blocked |
42 | </div> | 42 | </div> |
43 | </ng-container> | 43 | </ng-container> |
44 | 44 | ||
@@ -50,11 +50,11 @@ | |||
50 | </div> | 50 | </div> |
51 | </ng-container> | 51 | </ng-container> |
52 | 52 | ||
53 | <ng-container *ngSwitchCase="UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS"> | 53 | <ng-container *ngSwitchCase="UserNotificationType.VIDEO_AUTO_BLOCK_FOR_MODERATORS"> |
54 | <my-global-icon iconName="no"></my-global-icon> | 54 | <my-global-icon iconName="no"></my-global-icon> |
55 | 55 | ||
56 | <div class="message" i18n> | 56 | <div class="message" i18n> |
57 | 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> | 57 | 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> |
58 | </div> | 58 | </div> |
59 | </ng-container> | 59 | </ng-container> |
60 | 60 | ||
diff --git a/client/src/app/shared/video-blacklist/index.ts b/client/src/app/shared/video-blacklist/index.ts deleted file mode 100644 index bfb026441..000000000 --- a/client/src/app/shared/video-blacklist/index.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export * from './video-blacklist.service' | ||
diff --git a/client/src/app/shared/video-blacklist/video-blacklist.service.ts b/client/src/app/shared/video-blacklist/video-blacklist.service.ts deleted file mode 100644 index c0e13a651..000000000 --- a/client/src/app/shared/video-blacklist/video-blacklist.service.ts +++ /dev/null | |||
@@ -1,89 +0,0 @@ | |||
1 | import { catchError, map, concatMap, toArray } from 'rxjs/operators' | ||
2 | import { HttpClient, HttpParams } from '@angular/common/http' | ||
3 | import { Injectable } from '@angular/core' | ||
4 | import { SortMeta } from 'primeng/api' | ||
5 | import { from as observableFrom, Observable } from 'rxjs' | ||
6 | import { VideoBlacklist, VideoBlacklistType, ResultList } from '../../../../../shared' | ||
7 | import { Video } from '../video/video.model' | ||
8 | import { environment } from '../../../environments/environment' | ||
9 | import { RestExtractor, RestPagination, RestService } from '../rest' | ||
10 | import { ComponentPaginationLight } from '../rest/component-pagination.model' | ||
11 | |||
12 | @Injectable() | ||
13 | export class VideoBlacklistService { | ||
14 | private static BASE_VIDEOS_URL = environment.apiUrl + '/api/v1/videos/' | ||
15 | |||
16 | constructor ( | ||
17 | private authHttp: HttpClient, | ||
18 | private restService: RestService, | ||
19 | private restExtractor: RestExtractor | ||
20 | ) {} | ||
21 | |||
22 | listBlacklist (options: { | ||
23 | pagination: RestPagination, | ||
24 | sort: SortMeta, | ||
25 | search?: string | ||
26 | type?: VideoBlacklistType | ||
27 | }): Observable<ResultList<VideoBlacklist>> { | ||
28 | const { pagination, sort, search, type } = options | ||
29 | |||
30 | let params = new HttpParams() | ||
31 | params = this.restService.addRestGetParams(params, pagination, sort) | ||
32 | |||
33 | if (search) params = params.append('search', search) | ||
34 | if (type) params = params.append('type', type.toString()) | ||
35 | |||
36 | return this.authHttp.get<ResultList<VideoBlacklist>>(VideoBlacklistService.BASE_VIDEOS_URL + 'blacklist', { params }) | ||
37 | .pipe( | ||
38 | map(res => this.restExtractor.convertResultListDateToHuman(res)), | ||
39 | catchError(res => this.restExtractor.handleError(res)) | ||
40 | ) | ||
41 | } | ||
42 | |||
43 | getAutoBlacklistedAsVideoList (videoPagination: ComponentPaginationLight): Observable<ResultList<Video>> { | ||
44 | const pagination = this.restService.componentPaginationToRestPagination(videoPagination) | ||
45 | |||
46 | // prioritize first created since waiting longest | ||
47 | const AUTO_BLACKLIST_SORT = 'createdAt' | ||
48 | |||
49 | let params = new HttpParams() | ||
50 | params = this.restService.addRestGetParams(params, pagination, AUTO_BLACKLIST_SORT) | ||
51 | |||
52 | params = params.set('type', VideoBlacklistType.AUTO_BEFORE_PUBLISHED.toString()) | ||
53 | |||
54 | return this.authHttp.get<ResultList<VideoBlacklist>>(VideoBlacklistService.BASE_VIDEOS_URL + 'blacklist', { params }) | ||
55 | .pipe( | ||
56 | map(res => { | ||
57 | return { | ||
58 | total: res.total, | ||
59 | data: res.data.map(videoBlacklist => new Video(videoBlacklist.video)) | ||
60 | } | ||
61 | }), | ||
62 | catchError(res => this.restExtractor.handleError(res)) | ||
63 | ) | ||
64 | } | ||
65 | |||
66 | removeVideoFromBlacklist (videoIdArgs: number | number[]) { | ||
67 | const videoIds = Array.isArray(videoIdArgs) ? videoIdArgs : [ videoIdArgs ] | ||
68 | |||
69 | return observableFrom(videoIds) | ||
70 | .pipe( | ||
71 | concatMap(id => this.authHttp.delete(VideoBlacklistService.BASE_VIDEOS_URL + id + '/blacklist')), | ||
72 | toArray(), | ||
73 | catchError(err => this.restExtractor.handleError(err)) | ||
74 | ) | ||
75 | } | ||
76 | |||
77 | blacklistVideo (videoId: number, reason: string, unfederate: boolean) { | ||
78 | const body = { | ||
79 | unfederate, | ||
80 | reason | ||
81 | } | ||
82 | |||
83 | return this.authHttp.post(VideoBlacklistService.BASE_VIDEOS_URL + videoId + '/blacklist', body) | ||
84 | .pipe( | ||
85 | map(this.restExtractor.extractDataBool), | ||
86 | catchError(res => this.restExtractor.handleError(res)) | ||
87 | ) | ||
88 | } | ||
89 | } | ||
diff --git a/client/src/app/shared/video-block/index.ts b/client/src/app/shared/video-block/index.ts new file mode 100644 index 000000000..a99551a38 --- /dev/null +++ b/client/src/app/shared/video-block/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './video-block.service' | |||
diff --git a/client/src/app/shared/video-block/video-block.service.ts b/client/src/app/shared/video-block/video-block.service.ts new file mode 100644 index 000000000..67ca1d85b --- /dev/null +++ b/client/src/app/shared/video-block/video-block.service.ts | |||
@@ -0,0 +1,77 @@ | |||
1 | import { catchError, map, concatMap, toArray } from 'rxjs/operators' | ||
2 | import { HttpClient, HttpParams } from '@angular/common/http' | ||
3 | import { Injectable } from '@angular/core' | ||
4 | import { SortMeta } from 'primeng/api' | ||
5 | import { from as observableFrom, Observable } from 'rxjs' | ||
6 | import { VideoBlocklist, VideoBlockType, ResultList } from '../../../../../shared' | ||
7 | import { environment } from '../../../environments/environment' | ||
8 | import { RestExtractor, RestPagination, RestService } from '../rest' | ||
9 | |||
10 | @Injectable() | ||
11 | export class VideoBlockService { | ||
12 | private static BASE_VIDEOS_URL = environment.apiUrl + '/api/v1/videos/' | ||
13 | |||
14 | constructor ( | ||
15 | private authHttp: HttpClient, | ||
16 | private restService: RestService, | ||
17 | private restExtractor: RestExtractor | ||
18 | ) {} | ||
19 | |||
20 | listBlocks (options: { | ||
21 | pagination: RestPagination | ||
22 | sort: SortMeta | ||
23 | search?: string | ||
24 | type?: VideoBlockType | ||
25 | }): Observable<ResultList<VideoBlocklist>> { | ||
26 | const { pagination, sort, search, type } = options | ||
27 | |||
28 | let params = new HttpParams() | ||
29 | params = this.restService.addRestGetParams(params, pagination, sort) | ||
30 | |||
31 | if (search) { | ||
32 | const filters = this.restService.parseQueryStringFilter(search, { | ||
33 | type: { | ||
34 | prefix: 'type:', | ||
35 | handler: v => { | ||
36 | if (v === 'manual') return VideoBlockType.MANUAL | ||
37 | if (v === 'auto') return VideoBlockType.AUTO_BEFORE_PUBLISHED | ||
38 | |||
39 | return undefined | ||
40 | } | ||
41 | } | ||
42 | }) | ||
43 | |||
44 | params = this.restService.addObjectParams(params, filters) | ||
45 | } | ||
46 | |||
47 | return this.authHttp.get<ResultList<VideoBlocklist>>(VideoBlockService.BASE_VIDEOS_URL + 'blacklist', { params }) | ||
48 | .pipe( | ||
49 | map(res => this.restExtractor.convertResultListDateToHuman(res)), | ||
50 | catchError(res => this.restExtractor.handleError(res)) | ||
51 | ) | ||
52 | } | ||
53 | |||
54 | unblockVideo (videoIdArgs: number | number[]) { | ||
55 | const videoIds = Array.isArray(videoIdArgs) ? videoIdArgs : [ videoIdArgs ] | ||
56 | |||
57 | return observableFrom(videoIds) | ||
58 | .pipe( | ||
59 | concatMap(id => this.authHttp.delete(VideoBlockService.BASE_VIDEOS_URL + id + '/blacklist')), | ||
60 | toArray(), | ||
61 | catchError(err => this.restExtractor.handleError(err)) | ||
62 | ) | ||
63 | } | ||
64 | |||
65 | blockVideo (videoId: number, reason: string, unfederate: boolean) { | ||
66 | const body = { | ||
67 | unfederate, | ||
68 | reason | ||
69 | } | ||
70 | |||
71 | return this.authHttp.post(VideoBlockService.BASE_VIDEOS_URL + videoId + '/blacklist', body) | ||
72 | .pipe( | ||
73 | map(this.restExtractor.extractDataBool), | ||
74 | catchError(res => this.restExtractor.handleError(res)) | ||
75 | ) | ||
76 | } | ||
77 | } | ||
diff --git a/client/src/app/shared/video/abstract-video-list.html b/client/src/app/shared/video/abstract-video-list.html index cd8a5b840..8ce3b25b0 100644 --- a/client/src/app/shared/video/abstract-video-list.html +++ b/client/src/app/shared/video/abstract-video-list.html | |||
@@ -39,7 +39,7 @@ | |||
39 | [fitWidth]="true" | 39 | [fitWidth]="true" |
40 | [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType" | 40 | [video]="video" [user]="user" [ownerDisplayType]="ownerDisplayType" |
41 | [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions" | 41 | [displayVideoActions]="displayVideoActions" [displayOptions]="displayOptions" |
42 | (videoBlacklisted)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)" | 42 | (videoBlocked)="removeVideoFromArray(video)" (videoRemoved)="removeVideoFromArray(video)" |
43 | > | 43 | > |
44 | </my-video-miniature> | 44 | </my-video-miniature> |
45 | </ng-container> | 45 | </ng-container> |
diff --git a/client/src/app/shared/video/modals/video-blacklist.component.html b/client/src/app/shared/video/modals/video-block.component.html index 8f06a6b02..a8dd30b5e 100644 --- a/client/src/app/shared/video/modals/video-blacklist.component.html +++ b/client/src/app/shared/video/modals/video-block.component.html | |||
@@ -1,12 +1,12 @@ | |||
1 | <ng-template #modal> | 1 | <ng-template #modal> |
2 | <div class="modal-header"> | 2 | <div class="modal-header"> |
3 | <h4 i18n class="modal-title">Blacklist video</h4> | 3 | <h4 i18n class="modal-title">Blocklist video</h4> |
4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> | 4 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> |
5 | </div> | 5 | </div> |
6 | 6 | ||
7 | <div class="modal-body"> | 7 | <div class="modal-body"> |
8 | 8 | ||
9 | <form novalidate [formGroup]="form" (ngSubmit)="blacklist()"> | 9 | <form novalidate [formGroup]="form" (ngSubmit)="block()"> |
10 | <div class="form-group"> | 10 | <div class="form-group"> |
11 | <textarea | 11 | <textarea |
12 | i18n-placeholder placeholder="Reason..." formControlName="reason" | 12 | i18n-placeholder placeholder="Reason..." formControlName="reason" |
diff --git a/client/src/app/shared/video/modals/video-blacklist.component.scss b/client/src/app/shared/video/modals/video-block.component.scss index afcdb9a16..afcdb9a16 100644 --- a/client/src/app/shared/video/modals/video-blacklist.component.scss +++ b/client/src/app/shared/video/modals/video-block.component.scss | |||
diff --git a/client/src/app/shared/video/modals/video-blacklist.component.ts b/client/src/app/shared/video/modals/video-block.component.ts index 6ef9c250b..1a25e0578 100644 --- a/client/src/app/shared/video/modals/video-blacklist.component.ts +++ b/client/src/app/shared/video/modals/video-block.component.ts | |||
@@ -1,24 +1,24 @@ | |||
1 | import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' | 1 | import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core' |
2 | import { Notifier, RedirectService } from '@app/core' | 2 | import { Notifier, RedirectService } from '@app/core' |
3 | import { VideoBlacklistService } from '../../../shared/video-blacklist' | 3 | import { VideoBlockService } from '../../video-block' |
4 | import { I18n } from '@ngx-translate/i18n-polyfill' | 4 | import { I18n } from '@ngx-translate/i18n-polyfill' |
5 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' | 5 | import { FormValidatorService } from '@app/shared/forms/form-validators/form-validator.service' |
6 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 6 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' |
7 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' | 7 | import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' |
8 | import { FormReactive, VideoBlacklistValidatorsService } from '@app/shared/forms' | 8 | import { FormReactive, VideoBlockValidatorsService } from '@app/shared/forms' |
9 | import { Video } from '@app/shared/video/video.model' | 9 | import { Video } from '@app/shared/video/video.model' |
10 | 10 | ||
11 | @Component({ | 11 | @Component({ |
12 | selector: 'my-video-blacklist', | 12 | selector: 'my-video-block', |
13 | templateUrl: './video-blacklist.component.html', | 13 | templateUrl: './video-block.component.html', |
14 | styleUrls: [ './video-blacklist.component.scss' ] | 14 | styleUrls: [ './video-block.component.scss' ] |
15 | }) | 15 | }) |
16 | export class VideoBlacklistComponent extends FormReactive implements OnInit { | 16 | export class VideoBlockComponent extends FormReactive implements OnInit { |
17 | @Input() video: Video = null | 17 | @Input() video: Video = null |
18 | 18 | ||
19 | @ViewChild('modal', { static: true }) modal: NgbModal | 19 | @ViewChild('modal', { static: true }) modal: NgbModal |
20 | 20 | ||
21 | @Output() videoBlacklisted = new EventEmitter() | 21 | @Output() videoBlocked = new EventEmitter() |
22 | 22 | ||
23 | error: string = null | 23 | error: string = null |
24 | 24 | ||
@@ -27,10 +27,9 @@ export class VideoBlacklistComponent extends FormReactive implements OnInit { | |||
27 | constructor ( | 27 | constructor ( |
28 | protected formValidatorService: FormValidatorService, | 28 | protected formValidatorService: FormValidatorService, |
29 | private modalService: NgbModal, | 29 | private modalService: NgbModal, |
30 | private videoBlacklistValidatorsService: VideoBlacklistValidatorsService, | 30 | private videoBlockValidatorsService: VideoBlockValidatorsService, |
31 | private videoBlacklistService: VideoBlacklistService, | 31 | private videoBlocklistService: VideoBlockService, |
32 | private notifier: Notifier, | 32 | private notifier: Notifier, |
33 | private redirectService: RedirectService, | ||
34 | private i18n: I18n | 33 | private i18n: I18n |
35 | ) { | 34 | ) { |
36 | super() | 35 | super() |
@@ -40,7 +39,7 @@ export class VideoBlacklistComponent extends FormReactive implements OnInit { | |||
40 | const defaultValues = { unfederate: 'true' } | 39 | const defaultValues = { unfederate: 'true' } |
41 | 40 | ||
42 | this.buildForm({ | 41 | this.buildForm({ |
43 | reason: this.videoBlacklistValidatorsService.VIDEO_BLACKLIST_REASON, | 42 | reason: this.videoBlockValidatorsService.VIDEO_BLOCK_REASON, |
44 | unfederate: null | 43 | unfederate: null |
45 | }, defaultValues) | 44 | }, defaultValues) |
46 | } | 45 | } |
@@ -54,20 +53,20 @@ export class VideoBlacklistComponent extends FormReactive implements OnInit { | |||
54 | this.openedModal = null | 53 | this.openedModal = null |
55 | } | 54 | } |
56 | 55 | ||
57 | blacklist () { | 56 | block () { |
58 | const reason = this.form.value[ 'reason' ] || undefined | 57 | const reason = this.form.value[ 'reason' ] || undefined |
59 | const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined | 58 | const unfederate = this.video.isLocal ? this.form.value[ 'unfederate' ] : undefined |
60 | 59 | ||
61 | this.videoBlacklistService.blacklistVideo(this.video.id, reason, unfederate) | 60 | this.videoBlocklistService.blockVideo(this.video.id, reason, unfederate) |
62 | .subscribe( | 61 | .subscribe( |
63 | () => { | 62 | () => { |
64 | this.notifier.success(this.i18n('Video blacklisted.')) | 63 | this.notifier.success(this.i18n('Video blocked.')) |
65 | this.hide() | 64 | this.hide() |
66 | 65 | ||
67 | this.video.blacklisted = true | 66 | this.video.blacklisted = true |
68 | this.video.blacklistedReason = reason | 67 | this.video.blockedReason = reason |
69 | 68 | ||
70 | this.videoBlacklisted.emit() | 69 | this.videoBlocked.emit() |
71 | }, | 70 | }, |
72 | 71 | ||
73 | err => this.notifier.error(err.message) | 72 | err => this.notifier.error(err.message) |
diff --git a/client/src/app/shared/video/video-actions-dropdown.component.html b/client/src/app/shared/video/video-actions-dropdown.component.html index ec03fa55d..3c8271b65 100644 --- a/client/src/app/shared/video/video-actions-dropdown.component.html +++ b/client/src/app/shared/video/video-actions-dropdown.component.html | |||
@@ -17,5 +17,5 @@ | |||
17 | 17 | ||
18 | <my-video-download #videoDownloadModal></my-video-download> | 18 | <my-video-download #videoDownloadModal></my-video-download> |
19 | <my-video-report #videoReportModal [video]="video"></my-video-report> | 19 | <my-video-report #videoReportModal [video]="video"></my-video-report> |
20 | <my-video-blacklist #videoBlacklistModal [video]="video" (videoBlacklisted)="onVideoBlacklisted()"></my-video-blacklist> | 20 | <my-video-block #videoBlockModal [video]="video" (videoBlocked)="onVideoBlocked()"></my-video-block> |
21 | </ng-container> | 21 | </ng-container> |
diff --git a/client/src/app/shared/video/video-actions-dropdown.component.ts b/client/src/app/shared/video/video-actions-dropdown.component.ts index 4e5fc6476..1f5763610 100644 --- a/client/src/app/shared/video/video-actions-dropdown.component.ts +++ b/client/src/app/shared/video/video-actions-dropdown.component.ts | |||
@@ -9,8 +9,8 @@ import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap' | |||
9 | import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component' | 9 | import { VideoAddToPlaylistComponent } from '@app/shared/video-playlist/video-add-to-playlist.component' |
10 | import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component' | 10 | import { VideoDownloadComponent } from '@app/shared/video/modals/video-download.component' |
11 | import { VideoReportComponent } from '@app/shared/video/modals/video-report.component' | 11 | import { VideoReportComponent } from '@app/shared/video/modals/video-report.component' |
12 | import { VideoBlacklistComponent } from '@app/shared/video/modals/video-blacklist.component' | 12 | import { VideoBlockComponent } from '@app/shared/video/modals/video-block.component' |
13 | import { VideoBlacklistService } from '@app/shared/video-blacklist' | 13 | import { VideoBlockService } from '@app/shared/video-block' |
14 | import { ScreenService } from '@app/shared/misc/screen.service' | 14 | import { ScreenService } from '@app/shared/misc/screen.service' |
15 | import { VideoCaption } from '@shared/models' | 15 | import { VideoCaption } from '@shared/models' |
16 | import { RedundancyService } from '@app/shared/video/redundancy.service' | 16 | import { RedundancyService } from '@app/shared/video/redundancy.service' |
@@ -36,7 +36,7 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
36 | 36 | ||
37 | @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent | 37 | @ViewChild('videoDownloadModal') videoDownloadModal: VideoDownloadComponent |
38 | @ViewChild('videoReportModal') videoReportModal: VideoReportComponent | 38 | @ViewChild('videoReportModal') videoReportModal: VideoReportComponent |
39 | @ViewChild('videoBlacklistModal') videoBlacklistModal: VideoBlacklistComponent | 39 | @ViewChild('videoBlockModal') videoBlockModal: VideoBlockComponent |
40 | 40 | ||
41 | @Input() video: Video | VideoDetails | 41 | @Input() video: Video | VideoDetails |
42 | @Input() videoCaptions: VideoCaption[] = [] | 42 | @Input() videoCaptions: VideoCaption[] = [] |
@@ -59,8 +59,8 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
59 | @Input() buttonDirection: DropdownDirection = 'vertical' | 59 | @Input() buttonDirection: DropdownDirection = 'vertical' |
60 | 60 | ||
61 | @Output() videoRemoved = new EventEmitter() | 61 | @Output() videoRemoved = new EventEmitter() |
62 | @Output() videoUnblacklisted = new EventEmitter() | 62 | @Output() videoUnblocked = new EventEmitter() |
63 | @Output() videoBlacklisted = new EventEmitter() | 63 | @Output() videoBlocked = new EventEmitter() |
64 | @Output() modalOpened = new EventEmitter() | 64 | @Output() modalOpened = new EventEmitter() |
65 | 65 | ||
66 | videoActions: DropdownAction<{ video: Video }>[][] = [] | 66 | videoActions: DropdownAction<{ video: Video }>[][] = [] |
@@ -71,7 +71,7 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
71 | private authService: AuthService, | 71 | private authService: AuthService, |
72 | private notifier: Notifier, | 72 | private notifier: Notifier, |
73 | private confirmService: ConfirmService, | 73 | private confirmService: ConfirmService, |
74 | private videoBlacklistService: VideoBlacklistService, | 74 | private videoBlocklistService: VideoBlockService, |
75 | private screenService: ScreenService, | 75 | private screenService: ScreenService, |
76 | private videoService: VideoService, | 76 | private videoService: VideoService, |
77 | private redundancyService: RedundancyService, | 77 | private redundancyService: RedundancyService, |
@@ -117,10 +117,10 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
117 | this.videoReportModal.show() | 117 | this.videoReportModal.show() |
118 | } | 118 | } |
119 | 119 | ||
120 | showBlacklistModal () { | 120 | showBlockModal () { |
121 | this.modalOpened.emit() | 121 | this.modalOpened.emit() |
122 | 122 | ||
123 | this.videoBlacklistModal.show() | 123 | this.videoBlockModal.show() |
124 | } | 124 | } |
125 | 125 | ||
126 | /* Actions checker */ | 126 | /* Actions checker */ |
@@ -133,12 +133,12 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
133 | return this.video.isRemovableBy(this.user) | 133 | return this.video.isRemovableBy(this.user) |
134 | } | 134 | } |
135 | 135 | ||
136 | isVideoBlacklistable () { | 136 | isVideoBlockable () { |
137 | return this.video.isBlackistableBy(this.user) | 137 | return this.video.isBlockableBy(this.user) |
138 | } | 138 | } |
139 | 139 | ||
140 | isVideoUnblacklistable () { | 140 | isVideoUnblockable () { |
141 | return this.video.isUnblacklistableBy(this.user) | 141 | return this.video.isUnblockableBy(this.user) |
142 | } | 142 | } |
143 | 143 | ||
144 | isVideoDownloadable () { | 144 | isVideoDownloadable () { |
@@ -151,22 +151,22 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
151 | 151 | ||
152 | /* Action handlers */ | 152 | /* Action handlers */ |
153 | 153 | ||
154 | async unblacklistVideo () { | 154 | async unblockVideo () { |
155 | const confirmMessage = this.i18n( | 155 | const confirmMessage = this.i18n( |
156 | 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.' | 156 | 'Do you really want to unblock this video? It will be available again in the videos list.' |
157 | ) | 157 | ) |
158 | 158 | ||
159 | const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblacklist')) | 159 | const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblock')) |
160 | if (res === false) return | 160 | if (res === false) return |
161 | 161 | ||
162 | this.videoBlacklistService.removeVideoFromBlacklist(this.video.id).subscribe( | 162 | this.videoBlocklistService.unblockVideo(this.video.id).subscribe( |
163 | () => { | 163 | () => { |
164 | this.notifier.success(this.i18n('Video {{name}} removed from the blacklist.', { name: this.video.name })) | 164 | this.notifier.success(this.i18n('Video {{name}} unblocked.', { name: this.video.name })) |
165 | 165 | ||
166 | this.video.blacklisted = false | 166 | this.video.blacklisted = false |
167 | this.video.blacklistedReason = null | 167 | this.video.blockedReason = null |
168 | 168 | ||
169 | this.videoUnblacklisted.emit() | 169 | this.videoUnblocked.emit() |
170 | }, | 170 | }, |
171 | 171 | ||
172 | err => this.notifier.error(err.message) | 172 | err => this.notifier.error(err.message) |
@@ -203,8 +203,8 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
203 | ) | 203 | ) |
204 | } | 204 | } |
205 | 205 | ||
206 | onVideoBlacklisted () { | 206 | onVideoBlocked () { |
207 | this.videoBlacklisted.emit() | 207 | this.videoBlocked.emit() |
208 | } | 208 | } |
209 | 209 | ||
210 | getPlaylistDropdownPlacement () { | 210 | getPlaylistDropdownPlacement () { |
@@ -239,16 +239,16 @@ export class VideoActionsDropdownComponent implements OnChanges { | |||
239 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.update && this.isVideoUpdatable() | 239 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.update && this.isVideoUpdatable() |
240 | }, | 240 | }, |
241 | { | 241 | { |
242 | label: this.i18n('Blacklist'), | 242 | label: this.i18n('Block'), |
243 | handler: () => this.showBlacklistModal(), | 243 | handler: () => this.showBlockModal(), |
244 | iconName: 'no', | 244 | iconName: 'no', |
245 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoBlacklistable() | 245 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoBlockable() |
246 | }, | 246 | }, |
247 | { | 247 | { |
248 | label: this.i18n('Unblacklist'), | 248 | label: this.i18n('Unblock'), |
249 | handler: () => this.unblacklistVideo(), | 249 | handler: () => this.unblockVideo(), |
250 | iconName: 'undo', | 250 | iconName: 'undo', |
251 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoUnblacklistable() | 251 | isDisplayed: () => this.authService.isLoggedIn() && this.displayOptions.blacklist && this.isVideoUnblockable() |
252 | }, | 252 | }, |
253 | { | 253 | { |
254 | label: this.i18n('Mirror'), | 254 | label: this.i18n('Mirror'), |
diff --git a/client/src/app/shared/video/video-miniature.component.html b/client/src/app/shared/video/video-miniature.component.html index 3e23cf18c..575505f63 100644 --- a/client/src/app/shared/video/video-miniature.component.html +++ b/client/src/app/shared/video/video-miniature.component.html | |||
@@ -43,9 +43,9 @@ | |||
43 | </div> | 43 | </div> |
44 | </div> | 44 | </div> |
45 | 45 | ||
46 | <div *ngIf="displayOptions.blacklistInfo && video.blacklisted" class="video-info-blacklisted"> | 46 | <div *ngIf="displayOptions.blacklistInfo && video.blacklisted" class="video-info-blocked"> |
47 | <span class="blacklisted-label" i18n>Blacklisted</span> | 47 | <span class="blocked-label" i18n>Blocked</span> |
48 | <span class="blacklisted-reason" *ngIf="video.blacklistedReason">{{ video.blacklistedReason }}</span> | 48 | <span class="blocked-reason" *ngIf="video.blockedReason">{{ video.blockedReason }}</span> |
49 | </div> | 49 | </div> |
50 | 50 | ||
51 | <div i18n *ngIf="displayOptions.nsfw && video.nsfw" class="video-info-nsfw"> | 51 | <div i18n *ngIf="displayOptions.nsfw && video.nsfw" class="video-info-nsfw"> |
@@ -57,7 +57,7 @@ | |||
57 | <!-- FIXME: remove bottom placement when overflow is fixed in bootstrap dropdown: https://github.com/ng-bootstrap/ng-bootstrap/issues/3495 --> | 57 | <!-- FIXME: remove bottom placement when overflow is fixed in bootstrap dropdown: https://github.com/ng-bootstrap/ng-bootstrap/issues/3495 --> |
58 | <my-video-actions-dropdown | 58 | <my-video-actions-dropdown |
59 | *ngIf="showActions" [video]="video" [displayOptions]="videoActionsDisplayOptions" placement="bottom-left bottom-right left auto" | 59 | *ngIf="showActions" [video]="video" [displayOptions]="videoActionsDisplayOptions" placement="bottom-left bottom-right left auto" |
60 | (videoRemoved)="onVideoRemoved()" (videoBlacklisted)="onVideoBlacklisted()" (videoUnblacklisted)="onVideoUnblacklisted()" | 60 | (videoRemoved)="onVideoRemoved()" (videoBlocked)="onVideoBlocked()" (videoUnblocked)="onVideoUnblocked()" |
61 | ></my-video-actions-dropdown> | 61 | ></my-video-actions-dropdown> |
62 | </div> | 62 | </div> |
63 | </div> | 63 | </div> |
diff --git a/client/src/app/shared/video/video-miniature.component.scss b/client/src/app/shared/video/video-miniature.component.scss index 849bd54bb..34f34f228 100644 --- a/client/src/app/shared/video/video-miniature.component.scss +++ b/client/src/app/shared/video/video-miniature.component.scss | |||
@@ -45,15 +45,15 @@ $more-margin-right: 15px; | |||
45 | } | 45 | } |
46 | 46 | ||
47 | .video-info-privacy, | 47 | .video-info-privacy, |
48 | .video-info-blacklisted .blacklisted-label, | 48 | .video-info-blocked .blocked-label, |
49 | .video-info-nsfw { | 49 | .video-info-nsfw { |
50 | font-weight: $font-semibold; | 50 | font-weight: $font-semibold; |
51 | } | 51 | } |
52 | 52 | ||
53 | .video-info-blacklisted { | 53 | .video-info-blocked { |
54 | color: red; | 54 | color: red; |
55 | 55 | ||
56 | .blacklisted-reason::before { | 56 | .blocked-reason::before { |
57 | content: ' - '; | 57 | content: ' - '; |
58 | } | 58 | } |
59 | } | 59 | } |
@@ -160,7 +160,7 @@ $more-margin-right: 15px; | |||
160 | margin-top: 5px; | 160 | margin-top: 5px; |
161 | } | 161 | } |
162 | 162 | ||
163 | .video-info-blacklisted { | 163 | .video-info-blocked { |
164 | margin-top: 3px; | 164 | margin-top: 3px; |
165 | } | 165 | } |
166 | } | 166 | } |
diff --git a/client/src/app/shared/video/video-miniature.component.ts b/client/src/app/shared/video/video-miniature.component.ts index aa1726ca7..f0b0992e2 100644 --- a/client/src/app/shared/video/video-miniature.component.ts +++ b/client/src/app/shared/video/video-miniature.component.ts | |||
@@ -59,8 +59,8 @@ export class VideoMiniatureComponent implements OnInit { | |||
59 | 59 | ||
60 | @Input() useLazyLoadUrl = false | 60 | @Input() useLazyLoadUrl = false |
61 | 61 | ||
62 | @Output() videoBlacklisted = new EventEmitter() | 62 | @Output() videoBlocked = new EventEmitter() |
63 | @Output() videoUnblacklisted = new EventEmitter() | 63 | @Output() videoUnblocked = new EventEmitter() |
64 | @Output() videoRemoved = new EventEmitter() | 64 | @Output() videoRemoved = new EventEmitter() |
65 | 65 | ||
66 | videoActionsDisplayOptions: VideoActionsDisplayType = { | 66 | videoActionsDisplayOptions: VideoActionsDisplayType = { |
@@ -184,12 +184,12 @@ export class VideoMiniatureComponent implements OnInit { | |||
184 | this.loadWatchLater() | 184 | this.loadWatchLater() |
185 | } | 185 | } |
186 | 186 | ||
187 | onVideoBlacklisted () { | 187 | onVideoBlocked () { |
188 | this.videoBlacklisted.emit() | 188 | this.videoBlocked.emit() |
189 | } | 189 | } |
190 | 190 | ||
191 | onVideoUnblacklisted () { | 191 | onVideoUnblocked () { |
192 | this.videoUnblacklisted.emit() | 192 | this.videoUnblocked.emit() |
193 | } | 193 | } |
194 | 194 | ||
195 | onVideoRemoved () { | 195 | onVideoRemoved () { |
diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts index 97759f9c1..2b3d915ef 100644 --- a/client/src/app/shared/video/video.model.ts +++ b/client/src/app/shared/video/video.model.ts | |||
@@ -54,7 +54,7 @@ export class Video implements VideoServerModel { | |||
54 | state?: VideoConstant<VideoState> | 54 | state?: VideoConstant<VideoState> |
55 | scheduledUpdate?: VideoScheduleUpdate | 55 | scheduledUpdate?: VideoScheduleUpdate |
56 | blacklisted?: boolean | 56 | blacklisted?: boolean |
57 | blacklistedReason?: string | 57 | blockedReason?: string |
58 | 58 | ||
59 | account: { | 59 | account: { |
60 | id: number | 60 | id: number |
@@ -140,7 +140,7 @@ export class Video implements VideoServerModel { | |||
140 | if (this.state) this.state.label = peertubeTranslate(this.state.label, translations) | 140 | if (this.state) this.state.label = peertubeTranslate(this.state.label, translations) |
141 | 141 | ||
142 | this.blacklisted = hash.blacklisted | 142 | this.blacklisted = hash.blacklisted |
143 | this.blacklistedReason = hash.blacklistedReason | 143 | this.blockedReason = hash.blacklistedReason |
144 | 144 | ||
145 | this.userHistory = hash.userHistory | 145 | this.userHistory = hash.userHistory |
146 | 146 | ||
@@ -163,12 +163,12 @@ export class Video implements VideoServerModel { | |||
163 | return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO)) | 163 | return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO)) |
164 | } | 164 | } |
165 | 165 | ||
166 | isBlackistableBy (user: AuthUser) { | 166 | isBlockableBy (user: AuthUser) { |
167 | return this.blacklisted !== true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) === true | 167 | return this.blacklisted !== true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLOCKS) === true |
168 | } | 168 | } |
169 | 169 | ||
170 | isUnblacklistableBy (user: AuthUser) { | 170 | isUnblockableBy (user: AuthUser) { |
171 | return this.blacklisted === true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) === true | 171 | return this.blacklisted === true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLOCKS) === true |
172 | } | 172 | } |
173 | 173 | ||
174 | isUpdatableBy (user: AuthUser) { | 174 | isUpdatableBy (user: AuthUser) { |
diff --git a/client/src/app/videos/+video-watch/video-watch.component.html b/client/src/app/videos/+video-watch/video-watch.component.html index 433543a7b..63103e2e7 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -29,8 +29,8 @@ | |||
29 | </div> | 29 | </div> |
30 | 30 | ||
31 | <div class="col-md-12 alert alert-danger" *ngIf="video?.blacklisted"> | 31 | <div class="col-md-12 alert alert-danger" *ngIf="video?.blacklisted"> |
32 | <div class="blacklisted-label" i18n>This video is blacklisted.</div> | 32 | <div class="blocked-label" i18n>This video is blocked.</div> |
33 | {{ video.blacklistedReason }} | 33 | {{ video.blockedReason }} |
34 | </div> | 34 | </div> |
35 | </div> | 35 | </div> |
36 | 36 | ||
diff --git a/client/src/app/videos/+video-watch/video-watch.component.scss b/client/src/app/videos/+video-watch/video-watch.component.scss index 8be0bab1d..e0d41117a 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.scss +++ b/client/src/app/videos/+video-watch/video-watch.component.scss | |||
@@ -45,7 +45,7 @@ $video-info-margin-left: 44px; | |||
45 | } | 45 | } |
46 | } | 46 | } |
47 | 47 | ||
48 | .blacklisted-label { | 48 | .blocked-label { |
49 | font-weight: $font-semibold; | 49 | font-weight: $font-semibold; |
50 | } | 50 | } |
51 | 51 | ||
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts index 3790c7f6a..9f726cf35 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -335,7 +335,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
335 | this.videoCaptionService.listCaptions(videoId) | 335 | this.videoCaptionService.listCaptions(videoId) |
336 | ]) | 336 | ]) |
337 | .pipe( | 337 | .pipe( |
338 | // If 401, the video is private or blacklisted so redirect to 404 | 338 | // If 401, the video is private or blocklisted so redirect to 404 |
339 | catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ])) | 339 | catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ])) |
340 | ) | 340 | ) |
341 | .subscribe(([ video, captionsResult ]) => { | 341 | .subscribe(([ video, captionsResult ]) => { |
@@ -364,7 +364,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
364 | 364 | ||
365 | this.playlistService.getVideoPlaylist(playlistId) | 365 | this.playlistService.getVideoPlaylist(playlistId) |
366 | .pipe( | 366 | .pipe( |
367 | // If 401, the video is private or blacklisted so redirect to 404 | 367 | // If 401, the video is private or blocklisted so redirect to 404 |
368 | catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ])) | 368 | catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 403, 404 ])) |
369 | ) | 369 | ) |
370 | .subscribe(playlist => { | 370 | .subscribe(playlist => { |
diff --git a/client/src/app/videos/recommendations/recommended-videos.component.html b/client/src/app/videos/recommendations/recommended-videos.component.html index c6bdfee46..e4568c309 100644 --- a/client/src/app/videos/recommendations/recommended-videos.component.html +++ b/client/src/app/videos/recommendations/recommended-videos.component.html | |||
@@ -13,7 +13,7 @@ | |||
13 | </div> | 13 | </div> |
14 | 14 | ||
15 | <div *ngFor="let video of (videos$ | async); let i = index; let length = count"> | 15 | <div *ngFor="let video of (videos$ | async); let i = index; let length = count"> |
16 | <my-video-miniature [displayOptions]="displayOptions" [video]="video" [user]="user" (videoBlacklisted)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()"> | 16 | <my-video-miniature [displayOptions]="displayOptions" [video]="video" [user]="user" (videoBlocked)="onVideoRemoved()" (videoRemoved)="onVideoRemoved()"> |
17 | </my-video-miniature> | 17 | </my-video-miniature> |
18 | 18 | ||
19 | <hr *ngIf="!playlist && i == 0 && length > 1" /> | 19 | <hr *ngIf="!playlist && i == 0 && length > 1" /> |
diff --git a/client/src/assets/images/global/robot.svg b/client/src/assets/images/global/robot.svg new file mode 100644 index 000000000..46db9baef --- /dev/null +++ b/client/src/assets/images/global/robot.svg | |||
@@ -0,0 +1,11 @@ | |||
1 | <svg xmlns="http://www.w3.org/2000/svg" height="24px" width="24px" viewBox="0 0 24 24"> | ||
2 | <defs/> | ||
3 | <g fill="none" fill-rule="evenodd"> | ||
4 | <rect width="22" height="14" x="1" y="7" stroke="#000" stroke-width="2" rx="2"/> | ||
5 | <path fill="#000" d="M11 3h2v4h-2z"/> | ||
6 | <circle cx="12" cy="2" r="2" fill="#000"/> | ||
7 | <circle cx="18" cy="12" r="2" fill="#000"/> | ||
8 | <circle cx="6" cy="12" r="2" fill="#000"/> | ||
9 | <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"/> | ||
10 | </g> | ||
11 | </svg> | ||