diff options
author | Chocobozzz <me@florianbigard.com> | 2018-08-14 09:08:47 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-08-14 09:27:18 +0200 |
commit | 191764f30b0a812bf3a9dbdc7daf1d5afe25e12a (patch) | |
tree | a5592f8d89949cde832f025e393a3821ad2aca37 /client/src | |
parent | 26b7305a232e547709f433a6edf700bf495935d8 (diff) | |
download | PeerTube-191764f30b0a812bf3a9dbdc7daf1d5afe25e12a.tar.gz PeerTube-191764f30b0a812bf3a9dbdc7daf1d5afe25e12a.tar.zst PeerTube-191764f30b0a812bf3a9dbdc7daf1d5afe25e12a.zip |
Improve blacklist management
Diffstat (limited to 'client/src')
14 files changed, 124 insertions, 19 deletions
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html index aa0e18c70..f213ab4b0 100644 --- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.html | |||
@@ -42,7 +42,7 @@ | |||
42 | <td>{{ videoAbuse.createdAt }}</td> | 42 | <td>{{ videoAbuse.createdAt }}</td> |
43 | 43 | ||
44 | <td> | 44 | <td> |
45 | <a [href]="videoAbuse.video.url" i18n-title title="Go to the video" target="_blank" rel="noopener noreferrer"> | 45 | <a [href]="getVideoUrl(videoAbuse)" i18n-title title="Go to the video" target="_blank" rel="noopener noreferrer"> |
46 | {{ videoAbuse.video.name }} | 46 | {{ videoAbuse.video.name }} |
47 | </a> | 47 | </a> |
48 | </td> | 48 | </td> |
diff --git a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts index a850c0ec2..377e9c80f 100644 --- a/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts +++ b/client/src/app/+admin/video-abuses/video-abuse-list/video-abuse-list.component.ts | |||
@@ -8,6 +8,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill' | |||
8 | import { DropdownAction } from '@app/shared/buttons/action-dropdown.component' | 8 | import { DropdownAction } from '@app/shared/buttons/action-dropdown.component' |
9 | import { ConfirmService } from '@app/core' | 9 | import { ConfirmService } from '@app/core' |
10 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' | 10 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' |
11 | import { Video } from '@app/shared/video/video.model' | ||
11 | 12 | ||
12 | @Component({ | 13 | @Component({ |
13 | selector: 'my-video-abuse-list', | 14 | selector: 'my-video-abuse-list', |
@@ -79,6 +80,10 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
79 | return videoAbuse.state.id === VideoAbuseState.REJECTED | 80 | return videoAbuse.state.id === VideoAbuseState.REJECTED |
80 | } | 81 | } |
81 | 82 | ||
83 | getVideoUrl (videoAbuse: VideoAbuse) { | ||
84 | return Video.buildClientUrl(videoAbuse.video.uuid) | ||
85 | } | ||
86 | |||
82 | async removeVideoAbuse (videoAbuse: VideoAbuse) { | 87 | async removeVideoAbuse (videoAbuse: VideoAbuse) { |
83 | const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this abuse?'), this.i18n('Delete')) | 88 | const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this abuse?'), this.i18n('Delete')) |
84 | if (res === false) return | 89 | if (res === false) return |
diff --git a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html index 78989dc58..05b3a300c 100644 --- a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html +++ b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.html | |||
@@ -10,8 +10,7 @@ | |||
10 | <tr> | 10 | <tr> |
11 | <th style="width: 40px"></th> | 11 | <th style="width: 40px"></th> |
12 | <th i18n pSortableColumn="name">Video name <p-sortIcon field="name"></p-sortIcon></th> | 12 | <th i18n pSortableColumn="name">Video name <p-sortIcon field="name"></p-sortIcon></th> |
13 | <th i18n>NSFW</th> | 13 | <th i18n>Sensitive</th> |
14 | <th i18n>UUID</th> | ||
15 | <th i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th> | 14 | <th i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th> |
16 | <th style="width: 50px;"></th> | 15 | <th style="width: 50px;"></th> |
17 | </tr> | 16 | </tr> |
@@ -25,9 +24,13 @@ | |||
25 | </span> | 24 | </span> |
26 | </td> | 25 | </td> |
27 | 26 | ||
28 | <td>{{ videoBlacklist.video.name }}</td> | 27 | <td> |
28 | <a [href]="getVideoUrl(videoBlacklist)" i18n-title title="Go to the video" target="_blank" rel="noopener noreferrer"> | ||
29 | {{ videoBlacklist.video.name }} | ||
30 | </a> | ||
31 | </td> | ||
32 | |||
29 | <td>{{ videoBlacklist.video.nsfw }}</td> | 33 | <td>{{ videoBlacklist.video.nsfw }}</td> |
30 | <td>{{ videoBlacklist.video.uuid }}</td> | ||
31 | <td>{{ videoBlacklist.createdAt }}</td> | 34 | <td>{{ videoBlacklist.createdAt }}</td> |
32 | 35 | ||
33 | <td class="action-cell"> | 36 | <td class="action-cell"> |
diff --git a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts index 00b0ac57e..0618252b8 100644 --- a/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts +++ b/client/src/app/+admin/video-blacklist/video-blacklist-list/video-blacklist-list.component.ts | |||
@@ -3,9 +3,10 @@ import { SortMeta } from 'primeng/components/common/sortmeta' | |||
3 | import { NotificationsService } from 'angular2-notifications' | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | import { ConfirmService } from '../../../core' | 4 | import { ConfirmService } from '../../../core' |
5 | import { RestPagination, RestTable, VideoBlacklistService } from '../../../shared' | 5 | import { RestPagination, RestTable, VideoBlacklistService } from '../../../shared' |
6 | import { BlacklistedVideo } from '../../../../../../shared' | 6 | import { VideoBlacklist } from '../../../../../../shared' |
7 | import { I18n } from '@ngx-translate/i18n-polyfill' | 7 | import { I18n } from '@ngx-translate/i18n-polyfill' |
8 | import { DropdownAction } from '@app/shared/buttons/action-dropdown.component' | 8 | import { DropdownAction } from '@app/shared/buttons/action-dropdown.component' |
9 | import { Video } from '@app/shared/video/video.model' | ||
9 | 10 | ||
10 | @Component({ | 11 | @Component({ |
11 | selector: 'my-video-blacklist-list', | 12 | selector: 'my-video-blacklist-list', |
@@ -13,13 +14,13 @@ import { DropdownAction } from '@app/shared/buttons/action-dropdown.component' | |||
13 | styleUrls: [ './video-blacklist-list.component.scss' ] | 14 | styleUrls: [ './video-blacklist-list.component.scss' ] |
14 | }) | 15 | }) |
15 | export class VideoBlacklistListComponent extends RestTable implements OnInit { | 16 | export class VideoBlacklistListComponent extends RestTable implements OnInit { |
16 | blacklist: BlacklistedVideo[] = [] | 17 | blacklist: VideoBlacklist[] = [] |
17 | totalRecords = 0 | 18 | totalRecords = 0 |
18 | rowsPerPage = 10 | 19 | rowsPerPage = 10 |
19 | sort: SortMeta = { field: 'createdAt', order: 1 } | 20 | sort: SortMeta = { field: 'createdAt', order: 1 } |
20 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 21 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
21 | 22 | ||
22 | videoBlacklistActions: DropdownAction<BlacklistedVideo>[] = [] | 23 | videoBlacklistActions: DropdownAction<VideoBlacklist>[] = [] |
23 | 24 | ||
24 | constructor ( | 25 | constructor ( |
25 | private notificationsService: NotificationsService, | 26 | private notificationsService: NotificationsService, |
@@ -41,7 +42,11 @@ export class VideoBlacklistListComponent extends RestTable implements OnInit { | |||
41 | this.loadSort() | 42 | this.loadSort() |
42 | } | 43 | } |
43 | 44 | ||
44 | async removeVideoFromBlacklist (entry: BlacklistedVideo) { | 45 | getVideoUrl (videoBlacklist: VideoBlacklist) { |
46 | return Video.buildClientUrl(videoBlacklist.video.uuid) | ||
47 | } | ||
48 | |||
49 | async removeVideoFromBlacklist (entry: VideoBlacklist) { | ||
45 | const confirmMessage = this.i18n( | 50 | const confirmMessage = this.i18n( |
46 | 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.' | 51 | 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.' |
47 | ) | 52 | ) |
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html index 4823e2db9..8a6cb5c32 100644 --- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.html +++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.html | |||
@@ -18,6 +18,10 @@ | |||
18 | <a class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a> | 18 | <a class="video-info-name" [routerLink]="['/videos/watch', video.uuid]" [attr.title]="video.name">{{ video.name }}</a> |
19 | <span i18n class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span> | 19 | <span i18n class="video-info-date-views">{{ video.createdAt | myFromNow }} - {{ video.views | myNumberFormatter }} views</span> |
20 | <div class="video-info-private">{{ video.privacy.label }}{{ getStateLabel(video) }}</div> | 20 | <div class="video-info-private">{{ video.privacy.label }}{{ getStateLabel(video) }}</div> |
21 | <div *ngIf="video.blacklisted" class="video-info-blacklisted"> | ||
22 | <span class="blacklisted-label" i18n>Blacklisted</span> | ||
23 | <span class="blacklisted-reason" *ngIf="video.blacklistedReason">{{ video.blacklistedReason }}</span> | ||
24 | </div> | ||
21 | </div> | 25 | </div> |
22 | 26 | ||
23 | <!-- Display only once --> | 27 | <!-- Display only once --> |
diff --git a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss index 9df28f472..64a04fa20 100644 --- a/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss +++ b/client/src/app/+my-account/my-account-videos/my-account-videos.component.scss | |||
@@ -76,12 +76,25 @@ | |||
76 | font-weight: $font-semibold; | 76 | font-weight: $font-semibold; |
77 | } | 77 | } |
78 | 78 | ||
79 | .video-info-date-views, .video-info-private { | 79 | .video-info-date-views, |
80 | .video-info-private, | ||
81 | .video-info-blacklisted { | ||
80 | font-size: 13px; | 82 | font-size: 13px; |
81 | 83 | ||
82 | &.video-info-private { | 84 | &.video-info-private, |
85 | &.video-info-blacklisted .blacklisted-label { | ||
83 | font-weight: $font-semibold; | 86 | font-weight: $font-semibold; |
84 | } | 87 | } |
88 | |||
89 | &.video-info-blacklisted { | ||
90 | color: red; | ||
91 | |||
92 | .blacklisted-reason { | ||
93 | &::before { | ||
94 | content: ' - '; | ||
95 | } | ||
96 | } | ||
97 | } | ||
85 | } | 98 | } |
86 | } | 99 | } |
87 | 100 | ||
diff --git a/client/src/app/+page-not-found/page-not-found.component.scss b/client/src/app/+page-not-found/page-not-found.component.scss index 53b6142e1..f3f0354a3 100644 --- a/client/src/app/+page-not-found/page-not-found.component.scss +++ b/client/src/app/+page-not-found/page-not-found.component.scss | |||
@@ -2,7 +2,7 @@ div { | |||
2 | height: 100%; | 2 | height: 100%; |
3 | width: 100%; | 3 | width: 100%; |
4 | text-align: center; | 4 | text-align: center; |
5 | margin-top: 150px; | 5 | padding-top: 150px; |
6 | 6 | ||
7 | font-size: 32px; | 7 | font-size: 32px; |
8 | } \ No newline at end of file | 8 | } \ No newline at end of file |
diff --git a/client/src/app/shared/video-blacklist/video-blacklist.service.ts b/client/src/app/shared/video-blacklist/video-blacklist.service.ts index a014260b1..7d39fd4f2 100644 --- a/client/src/app/shared/video-blacklist/video-blacklist.service.ts +++ b/client/src/app/shared/video-blacklist/video-blacklist.service.ts | |||
@@ -3,7 +3,7 @@ import { HttpClient, HttpParams } from '@angular/common/http' | |||
3 | import { Injectable } from '@angular/core' | 3 | import { Injectable } from '@angular/core' |
4 | import { SortMeta } from 'primeng/components/common/sortmeta' | 4 | import { SortMeta } from 'primeng/components/common/sortmeta' |
5 | import { Observable } from 'rxjs' | 5 | import { Observable } from 'rxjs' |
6 | import { BlacklistedVideo, ResultList } from '../../../../../shared' | 6 | import { VideoBlacklist, ResultList } from '../../../../../shared' |
7 | import { environment } from '../../../environments/environment' | 7 | import { environment } from '../../../environments/environment' |
8 | import { RestExtractor, RestPagination, RestService } from '../rest' | 8 | import { RestExtractor, RestPagination, RestService } from '../rest' |
9 | 9 | ||
@@ -17,11 +17,11 @@ export class VideoBlacklistService { | |||
17 | private restExtractor: RestExtractor | 17 | private restExtractor: RestExtractor |
18 | ) {} | 18 | ) {} |
19 | 19 | ||
20 | listBlacklist (pagination: RestPagination, sort: SortMeta): Observable<ResultList<BlacklistedVideo>> { | 20 | listBlacklist (pagination: RestPagination, sort: SortMeta): Observable<ResultList<VideoBlacklist>> { |
21 | let params = new HttpParams() | 21 | let params = new HttpParams() |
22 | params = this.restService.addRestGetParams(params, pagination, sort) | 22 | params = this.restService.addRestGetParams(params, pagination, sort) |
23 | 23 | ||
24 | return this.authHttp.get<ResultList<BlacklistedVideo>>(VideoBlacklistService.BASE_VIDEOS_URL + 'blacklist', { params }) | 24 | return this.authHttp.get<ResultList<VideoBlacklist>>(VideoBlacklistService.BASE_VIDEOS_URL + 'blacklist', { params }) |
25 | .pipe( | 25 | .pipe( |
26 | map(res => this.restExtractor.convertResultListDateToHuman(res)), | 26 | map(res => this.restExtractor.convertResultListDateToHuman(res)), |
27 | catchError(res => this.restExtractor.handleError(res)) | 27 | catchError(res => this.restExtractor.handleError(res)) |
diff --git a/client/src/app/shared/video/video-details.model.ts b/client/src/app/shared/video/video-details.model.ts index bdcc0bbba..d346f985c 100644 --- a/client/src/app/shared/video/video-details.model.ts +++ b/client/src/app/shared/video/video-details.model.ts | |||
@@ -44,7 +44,11 @@ export class VideoDetails extends Video implements VideoDetailsServerModel { | |||
44 | } | 44 | } |
45 | 45 | ||
46 | isBlackistableBy (user: AuthUser) { | 46 | isBlackistableBy (user: AuthUser) { |
47 | return user && user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) === true | 47 | return this.blacklisted !== true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) === true |
48 | } | ||
49 | |||
50 | isUnblacklistableBy (user: AuthUser) { | ||
51 | return this.blacklisted === true && user && user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST) === true | ||
48 | } | 52 | } |
49 | 53 | ||
50 | isUpdatableBy (user: AuthUser) { | 54 | isUpdatableBy (user: AuthUser) { |
diff --git a/client/src/app/shared/video/video.model.ts b/client/src/app/shared/video/video.model.ts index 6b1a299ea..ec0afcccb 100644 --- a/client/src/app/shared/video/video.model.ts +++ b/client/src/app/shared/video/video.model.ts | |||
@@ -41,6 +41,8 @@ export class Video implements VideoServerModel { | |||
41 | waitTranscoding?: boolean | 41 | waitTranscoding?: boolean |
42 | state?: VideoConstant<VideoState> | 42 | state?: VideoConstant<VideoState> |
43 | scheduledUpdate?: VideoScheduleUpdate | 43 | scheduledUpdate?: VideoScheduleUpdate |
44 | blacklisted?: boolean | ||
45 | blacklistedReason?: string | ||
44 | 46 | ||
45 | account: { | 47 | account: { |
46 | id: number | 48 | id: number |
@@ -62,6 +64,10 @@ export class Video implements VideoServerModel { | |||
62 | avatar: Avatar | 64 | avatar: Avatar |
63 | } | 65 | } |
64 | 66 | ||
67 | static buildClientUrl (videoUUID: string) { | ||
68 | return '/videos/watch/' + videoUUID | ||
69 | } | ||
70 | |||
65 | private static createDurationString (duration: number) { | 71 | private static createDurationString (duration: number) { |
66 | const hours = Math.floor(duration / 3600) | 72 | const hours = Math.floor(duration / 3600) |
67 | const minutes = Math.floor((duration % 3600) / 60) | 73 | const minutes = Math.floor((duration % 3600) / 60) |
@@ -116,6 +122,9 @@ export class Video implements VideoServerModel { | |||
116 | 122 | ||
117 | this.scheduledUpdate = hash.scheduledUpdate | 123 | this.scheduledUpdate = hash.scheduledUpdate |
118 | if (this.state) this.state.label = peertubeTranslate(this.state.label, translations) | 124 | if (this.state) this.state.label = peertubeTranslate(this.state.label, translations) |
125 | |||
126 | this.blacklisted = hash.blacklisted | ||
127 | this.blacklistedReason = hash.blacklistedReason | ||
119 | } | 128 | } |
120 | 129 | ||
121 | isVideoNSFWForUser (user: User, serverConfig: ServerConfig) { | 130 | isVideoNSFWForUser (user: User, serverConfig: ServerConfig) { |
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 f82f1c554..8d4a4a5ca 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.html +++ b/client/src/app/videos/+video-watch/video-watch.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <div class="row"> | 1 | <div class="root-row row"> |
2 | <!-- We need the video container for videojs so we just hide it --> | 2 | <!-- We need the video container for videojs so we just hide it --> |
3 | <div id="video-element-wrapper"> | 3 | <div id="video-element-wrapper"> |
4 | <div *ngIf="remoteServerDown" class="remote-server-down"> | 4 | <div *ngIf="remoteServerDown" class="remote-server-down"> |
@@ -17,7 +17,12 @@ | |||
17 | </div> | 17 | </div> |
18 | 18 | ||
19 | <div i18n class="alert alert-info" *ngIf="hasVideoScheduledPublication()"> | 19 | <div i18n class="alert alert-info" *ngIf="hasVideoScheduledPublication()"> |
20 | This video will be published on {{ video.scheduledUpdate.updateAt | date: 'full' }} | 20 | This video will be published on {{ video.scheduledUpdate.updateAt | date: 'full' }}. |
21 | </div> | ||
22 | |||
23 | <div class="alert alert-danger" *ngIf="video?.blacklisted"> | ||
24 | <div class="blacklisted-label" i18n>This video is blacklisted.</div> | ||
25 | {{ video.blacklistedReason }} | ||
21 | </div> | 26 | </div> |
22 | 27 | ||
23 | <!-- Video information --> | 28 | <!-- Video information --> |
@@ -98,6 +103,10 @@ | |||
98 | <span class="icon icon-blacklist"></span> <ng-container i18n>Blacklist</ng-container> | 103 | <span class="icon icon-blacklist"></span> <ng-container i18n>Blacklist</ng-container> |
99 | </a> | 104 | </a> |
100 | 105 | ||
106 | <a *ngIf="isVideoUnblacklistable()" class="dropdown-item" i18n-title title="Unblacklist this video" href="#" (click)="unblacklistVideo($event)"> | ||
107 | <span class="icon icon-unblacklist"></span> <ng-container i18n>Unblacklist</ng-container> | ||
108 | </a> | ||
109 | |||
101 | <a *ngIf="isVideoRemovable()" class="dropdown-item" i18n-title title="Delete this video" href="#" (click)="removeVideo($event)"> | 110 | <a *ngIf="isVideoRemovable()" class="dropdown-item" i18n-title title="Delete this video" href="#" (click)="removeVideo($event)"> |
102 | <span class="icon icon-delete"></span> <ng-container i18n>Delete</ng-container> | 111 | <span class="icon icon-delete"></span> <ng-container i18n>Delete</ng-container> |
103 | </a> | 112 | </a> |
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 e63ab7bbd..1354de32e 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.scss +++ b/client/src/app/videos/+video-watch/video-watch.component.scss | |||
@@ -1,6 +1,14 @@ | |||
1 | @import '_variables'; | 1 | @import '_variables'; |
2 | @import '_mixins'; | 2 | @import '_mixins'; |
3 | 3 | ||
4 | .root-row { | ||
5 | flex-direction: column; | ||
6 | } | ||
7 | |||
8 | .blacklisted-label { | ||
9 | font-weight: $font-semibold; | ||
10 | } | ||
11 | |||
4 | #video-element-wrapper { | 12 | #video-element-wrapper { |
5 | background-color: #000; | 13 | background-color: #000; |
6 | display: flex; | 14 | display: flex; |
@@ -259,6 +267,10 @@ | |||
259 | background-image: url('../../../assets/images/video/blacklist.svg'); | 267 | background-image: url('../../../assets/images/video/blacklist.svg'); |
260 | } | 268 | } |
261 | 269 | ||
270 | &.icon-unblacklist { | ||
271 | background-image: url('../../../assets/images/global/undo.svg'); | ||
272 | } | ||
273 | |||
262 | &.icon-delete { | 274 | &.icon-delete { |
263 | background-image: url('../../../assets/images/global/delete-black.svg'); | 275 | background-image: url('../../../assets/images/global/delete-black.svg'); |
264 | } | 276 | } |
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 878655d4a..bea13ec99 100644 --- a/client/src/app/videos/+video-watch/video-watch.component.ts +++ b/client/src/app/videos/+video-watch/video-watch.component.ts | |||
@@ -121,7 +121,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
121 | this.videoCaptionService.listCaptions(uuid) | 121 | this.videoCaptionService.listCaptions(uuid) |
122 | ) | 122 | ) |
123 | .pipe( | 123 | .pipe( |
124 | catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ])) | 124 | // If 401, the video is private or blacklisted so redirect to 404 |
125 | catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 401, 404 ])) | ||
125 | ) | 126 | ) |
126 | .subscribe(([ video, captionsResult ]) => { | 127 | .subscribe(([ video, captionsResult ]) => { |
127 | const startTime = this.route.snapshot.queryParams.start | 128 | const startTime = this.route.snapshot.queryParams.start |
@@ -217,6 +218,31 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
217 | this.videoBlacklistModal.show() | 218 | this.videoBlacklistModal.show() |
218 | } | 219 | } |
219 | 220 | ||
221 | async unblacklistVideo (event: Event) { | ||
222 | event.preventDefault() | ||
223 | |||
224 | const confirmMessage = this.i18n( | ||
225 | 'Do you really want to remove this video from the blacklist? It will be available again in the videos list.' | ||
226 | ) | ||
227 | |||
228 | const res = await this.confirmService.confirm(confirmMessage, this.i18n('Unblacklist')) | ||
229 | if (res === false) return | ||
230 | |||
231 | this.videoBlacklistService.removeVideoFromBlacklist(this.video.id).subscribe( | ||
232 | () => { | ||
233 | this.notificationsService.success( | ||
234 | this.i18n('Success'), | ||
235 | this.i18n('Video {{name}} removed from the blacklist.', { name: this.video.name }) | ||
236 | ) | ||
237 | |||
238 | this.video.blacklisted = false | ||
239 | this.video.blacklistedReason = null | ||
240 | }, | ||
241 | |||
242 | err => this.notificationsService.error(this.i18n('Error'), err.message) | ||
243 | ) | ||
244 | } | ||
245 | |||
220 | isUserLoggedIn () { | 246 | isUserLoggedIn () { |
221 | return this.authService.isLoggedIn() | 247 | return this.authService.isLoggedIn() |
222 | } | 248 | } |
@@ -229,6 +255,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
229 | return this.video.isBlackistableBy(this.user) | 255 | return this.video.isBlackistableBy(this.user) |
230 | } | 256 | } |
231 | 257 | ||
258 | isVideoUnblacklistable () { | ||
259 | return this.video.isUnblacklistableBy(this.user) | ||
260 | } | ||
261 | |||
232 | getVideoPoster () { | 262 | getVideoPoster () { |
233 | if (!this.video) return '' | 263 | if (!this.video) return '' |
234 | 264 | ||
diff --git a/client/src/assets/images/global/undo.svg b/client/src/assets/images/global/undo.svg new file mode 100644 index 000000000..f1cca03f7 --- /dev/null +++ b/client/src/assets/images/global/undo.svg | |||
@@ -0,0 +1,11 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> | ||
3 | <defs></defs> | ||
4 | <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> | ||
5 | <g id="Artboard-4" transform="translate(-180.000000, -115.000000)" fill="#000"> | ||
6 | <g id="4" transform="translate(180.000000, 115.000000)"> | ||
7 | <path d="M10,19 C10.5522847,19 11,19.4477153 11,20 C11,20.5522847 10.5522847,21 10,21 C9.99404288,21 9.98809793,20.9999479 9.98216558,20.9998442 C5.01980239,20.990358 1,16.9646166 1,12 C1,7.02943725 5.02943725,3 10,3 C14.9705627,3 19,7.02943725 19,12 L17,12 C17,8.13400675 13.8659932,5 10,5 C6.13400675,5 3,8.13400675 3,12 C3,15.8659932 6.13400675,19 10,19 Z M14,12 L22,12 L18,16 L14,12 Z" id="Combined-Shape" transform="translate(11.500000, 12.000000) scale(-1, 1) translate(-11.500000, -12.000000) "></path> | ||
8 | </g> | ||
9 | </g> | ||
10 | </g> | ||
11 | </svg> | ||