diff options
9 files changed, 78 insertions, 14 deletions
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html index e40c29abf..6d77c8290 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-account-blocklist.component.html | |||
@@ -8,7 +8,7 @@ | |||
8 | <ng-template pTemplate="header"> | 8 | <ng-template pTemplate="header"> |
9 | <tr> | 9 | <tr> |
10 | <th i18n>Account</th> | 10 | <th i18n>Account</th> |
11 | <th style="width: 200px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | 11 | <th style="width: 190px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> |
12 | <th style="width: 100px;"></th> <!-- column for action buttons --> | 12 | <th style="width: 100px;"></th> <!-- column for action buttons --> |
13 | </tr> | 13 | </tr> |
14 | </ng-template> | 14 | </ng-template> |
diff --git a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html index bf5c00918..075be8498 100644 --- a/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html +++ b/client/src/app/+admin/moderation/instance-blocklist/instance-server-blocklist.component.html | |||
@@ -16,7 +16,7 @@ | |||
16 | <ng-template pTemplate="header"> | 16 | <ng-template pTemplate="header"> |
17 | <tr> | 17 | <tr> |
18 | <th i18n>Instance</th> | 18 | <th i18n>Instance</th> |
19 | <th style="width: 200px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> | 19 | <th style="width: 190px;" i18n pSortableColumn="createdAt">Muted at <p-sortIcon field="createdAt"></p-sortIcon></th> |
20 | <th style="width: 100px;"></th> <!-- column for action buttons --> | 20 | <th style="width: 100px;"></th> <!-- column for action buttons --> |
21 | </tr> | 21 | </tr> |
22 | </ng-template> | 22 | </ng-template> |
diff --git a/client/src/app/+admin/moderation/moderation.component.scss b/client/src/app/+admin/moderation/moderation.component.scss index 9af76d2dd..a015b6d85 100644 --- a/client/src/app/+admin/moderation/moderation.component.scss +++ b/client/src/app/+admin/moderation/moderation.component.scss | |||
@@ -29,6 +29,10 @@ | |||
29 | } | 29 | } |
30 | } | 30 | } |
31 | 31 | ||
32 | .glyphicon-trash { | ||
33 | font-size: 80%; | ||
34 | } | ||
35 | |||
32 | .screenratio { | 36 | .screenratio { |
33 | position: relative; | 37 | position: relative; |
34 | width: 100%; | 38 | width: 100%; |
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 3d356dc7c..204cb209e 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 | |||
@@ -1,15 +1,15 @@ | |||
1 | <p-table | 1 | <p-table |
2 | [value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" | 2 | [value]="videoAbuses" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions" |
3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" | 3 | [sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true" |
4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate | 4 | [showCurrentPageReport]="true" i18n-currentPageReportTemplate |
5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports" | 5 | currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports" |
6 | > | 6 | > |
7 | <ng-template pTemplate="header"> | 7 | <ng-template pTemplate="header"> |
8 | <tr> <!-- header --> | 8 | <tr> <!-- header --> |
9 | <th style="width: 40px;"></th> | 9 | <th style="width: 40px;"></th> |
10 | <th i18n>Reporter</th> | 10 | <th style="width: 20%;" pResizableColumn i18n>Reporter</th> |
11 | <th style="width: 200px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
12 | <th i18n>Video</th> | 11 | <th i18n>Video</th> |
12 | <th style="width:190px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> | ||
13 | <th i18n pSortableColumn="state" style="width: 80px;">State <p-sortIcon field="state"></p-sortIcon></th> | 13 | <th i18n pSortableColumn="state" style="width: 80px;">State <p-sortIcon field="state"></p-sortIcon></th> |
14 | <th style="width: 120px;"></th> | 14 | <th style="width: 120px;"></th> |
15 | </tr> | 15 | </tr> |
@@ -40,14 +40,15 @@ | |||
40 | </a> | 40 | </a> |
41 | </td> | 41 | </td> |
42 | 42 | ||
43 | <td>{{ videoAbuse.createdAt }}</td> | ||
44 | |||
45 | <td> | 43 | <td> |
44 | <span *ngIf="videoAbuse.video.deleted" i18n-title title="Video was deleted" class="glyphicon glyphicon-trash"></span> | ||
46 | <a [href]="getVideoUrl(videoAbuse)" i18n-title title="Open video in a new tab" target="_blank" rel="noopener noreferrer"> | 45 | <a [href]="getVideoUrl(videoAbuse)" i18n-title title="Open video in a new tab" target="_blank" rel="noopener noreferrer"> |
47 | {{ videoAbuse.video.name }} | 46 | {{ videoAbuse.video.name }} |
48 | </a> | 47 | </a> |
49 | </td> | 48 | </td> |
50 | 49 | ||
50 | <td>{{ videoAbuse.createdAt }}</td> | ||
51 | |||
51 | <td class="c-hand video-abuse-states" [pRowToggler]="videoAbuse"> | 52 | <td class="c-hand video-abuse-states" [pRowToggler]="videoAbuse"> |
52 | <span *ngIf="isVideoAbuseAccepted(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-ok"></span> | 53 | <span *ngIf="isVideoAbuseAccepted(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-ok"></span> |
53 | <span *ngIf="isVideoAbuseRejected(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-remove"></span> | 54 | <span *ngIf="isVideoAbuseRejected(videoAbuse)" [title]="videoAbuse.state.label" class="glyphicon glyphicon-remove"></span> |
@@ -55,7 +56,7 @@ | |||
55 | </td> | 56 | </td> |
56 | 57 | ||
57 | <td class="action-cell"> | 58 | <td class="action-cell"> |
58 | <my-action-dropdown placement="bottom-right auto" i18n-label label="Actions" [actions]="videoAbuseActions" [entry]="videoAbuse"></my-action-dropdown> | 59 | <my-action-dropdown placement="bottom-right auto" container="body" i18n-label label="Actions" [actions]="videoAbuseActions" [entry]="videoAbuse"></my-action-dropdown> |
59 | </td> | 60 | </td> |
60 | </tr> | 61 | </tr> |
61 | </ng-template> | 62 | </ng-template> |
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 5e48cf24f..9858cbce2 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 | |||
@@ -15,6 +15,7 @@ import { buildVideoLink, buildVideoEmbed } from 'src/assets/player/utils' | |||
15 | import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' | 15 | import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' |
16 | import { DomSanitizer } from '@angular/platform-browser' | 16 | import { DomSanitizer } from '@angular/platform-browser' |
17 | import { BlocklistService } from '@app/shared/blocklist' | 17 | import { BlocklistService } from '@app/shared/blocklist' |
18 | import { VideoService } from '@app/shared/video/video.service' | ||
18 | 19 | ||
19 | @Component({ | 20 | @Component({ |
20 | selector: 'my-video-abuse-list', | 21 | selector: 'my-video-abuse-list', |
@@ -26,7 +27,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
26 | 27 | ||
27 | videoAbuses: (VideoAbuse & { moderationCommentHtml?: string, reasonHtml?: string })[] = [] | 28 | videoAbuses: (VideoAbuse & { moderationCommentHtml?: string, reasonHtml?: string })[] = [] |
28 | totalRecords = 0 | 29 | totalRecords = 0 |
29 | rowsPerPage = 10 | 30 | rowsPerPageOptions = [ 20, 50, 100 ] |
31 | rowsPerPage = this.rowsPerPageOptions[0] | ||
30 | sort: SortMeta = { field: 'createdAt', order: 1 } | 32 | sort: SortMeta = { field: 'createdAt', order: 1 } |
31 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | 33 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } |
32 | 34 | ||
@@ -36,6 +38,7 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
36 | private notifier: Notifier, | 38 | private notifier: Notifier, |
37 | private videoAbuseService: VideoAbuseService, | 39 | private videoAbuseService: VideoAbuseService, |
38 | private blocklistService: BlocklistService, | 40 | private blocklistService: BlocklistService, |
41 | private videoService: VideoService, | ||
39 | private videoBlacklistService: VideoBlacklistService, | 42 | private videoBlacklistService: VideoBlacklistService, |
40 | private confirmService: ConfirmService, | 43 | private confirmService: ConfirmService, |
41 | private i18n: I18n, | 44 | private i18n: I18n, |
@@ -78,10 +81,12 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
78 | [ | 81 | [ |
79 | { | 82 | { |
80 | label: this.i18n('Actions for the video'), | 83 | label: this.i18n('Actions for the video'), |
81 | isHeader: true | 84 | isHeader: true, |
85 | isDisplayed: videoAbuse => !videoAbuse.video.deleted | ||
82 | }, | 86 | }, |
83 | { | 87 | { |
84 | label: this.i18n('Blacklist video'), | 88 | label: this.i18n('Blacklist video'), |
89 | isDisplayed: videoAbuse => !videoAbuse.video.deleted, | ||
85 | handler: videoAbuse => { | 90 | handler: videoAbuse => { |
86 | this.videoBlacklistService.blacklistVideo(videoAbuse.video.id, undefined, true) | 91 | this.videoBlacklistService.blacklistVideo(videoAbuse.video.id, undefined, true) |
87 | .subscribe( | 92 | .subscribe( |
@@ -94,6 +99,48 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
94 | err => this.notifier.error(err.message) | 99 | err => this.notifier.error(err.message) |
95 | ) | 100 | ) |
96 | } | 101 | } |
102 | }, | ||
103 | { | ||
104 | label: this.i18n('Delete video'), | ||
105 | isDisplayed: videoAbuse => !videoAbuse.video.deleted, | ||
106 | handler: async videoAbuse => { | ||
107 | const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this video?'), this.i18n('Delete')) | ||
108 | if (res === false) return | ||
109 | |||
110 | this.videoService.removeVideo(videoAbuse.video.id) | ||
111 | .subscribe( | ||
112 | () => { | ||
113 | this.notifier.success(this.i18n('Video deleted.')) | ||
114 | |||
115 | this.updateVideoAbuseState(videoAbuse, VideoAbuseState.ACCEPTED) | ||
116 | }, | ||
117 | |||
118 | err => this.notifier.error(err.message) | ||
119 | ) | ||
120 | } | ||
121 | } | ||
122 | ], | ||
123 | [ | ||
124 | { | ||
125 | label: this.i18n('Actions for the reporter'), | ||
126 | isHeader: true | ||
127 | }, | ||
128 | { | ||
129 | label: this.i18n('Mute reporter'), | ||
130 | handler: async videoAbuse => { | ||
131 | const account = videoAbuse.reporterAccount as Account | ||
132 | |||
133 | this.blocklistService.blockAccountByInstance(account) | ||
134 | .subscribe( | ||
135 | () => { | ||
136 | this.notifier.success(this.i18n('Account {{nameWithHost}} muted by the instance.', { nameWithHost: account.nameWithHost })) | ||
137 | |||
138 | account.mutedByInstance = true | ||
139 | }, | ||
140 | |||
141 | err => this.notifier.error(err.message) | ||
142 | ) | ||
143 | } | ||
97 | } | 144 | } |
98 | ] | 145 | ] |
99 | ] | 146 | ] |
@@ -180,7 +227,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
180 | Object.assign(abuse, { | 227 | Object.assign(abuse, { |
181 | reasonHtml: await this.toHtml(abuse.reason), | 228 | reasonHtml: await this.toHtml(abuse.reason), |
182 | moderationCommentHtml: await this.toHtml(abuse.moderationComment), | 229 | moderationCommentHtml: await this.toHtml(abuse.moderationComment), |
183 | embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)) | 230 | embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)), |
231 | reporterAccount: new Account(abuse.reporterAccount) | ||
184 | }) | 232 | }) |
185 | } | 233 | } |
186 | 234 | ||
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 index 023f4e7b7..2f9fc8ba4 100644 --- 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 | |||
@@ -10,7 +10,7 @@ | |||
10 | <th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th> | 10 | <th i18n pSortableColumn="name">Video <p-sortIcon field="name"></p-sortIcon></th> |
11 | <th style="width: 120px;" i18n>Sensitive</th> | 11 | <th style="width: 120px;" i18n>Sensitive</th> |
12 | <th style="width: 120px;" i18n>Unfederated</th> | 12 | <th style="width: 120px;" i18n>Unfederated</th> |
13 | <th style="width: 200px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th> | 13 | <th style="width: 190px;" i18n pSortableColumn="createdAt">Date <p-sortIcon field="createdAt"></p-sortIcon></th> |
14 | <th style="width: 120px;"></th> | 14 | <th style="width: 120px;"></th> |
15 | </tr> | 15 | </tr> |
16 | </ng-template> | 16 | </ng-template> |
diff --git a/client/src/app/shared/buttons/action-dropdown.component.html b/client/src/app/shared/buttons/action-dropdown.component.html index 0efc01d38..952b3b6f8 100644 --- a/client/src/app/shared/buttons/action-dropdown.component.html +++ b/client/src/app/shared/buttons/action-dropdown.component.html | |||
@@ -1,4 +1,4 @@ | |||
1 | <div class="dropdown-root" ngbDropdown [placement]="placement" container="body" *ngIf="areActionsDisplayed(actions, entry)"> | 1 | <div class="dropdown-root" ngbDropdown [placement]="placement" [container]="container" *ngIf="areActionsDisplayed(actions, entry)"> |
2 | <div | 2 | <div |
3 | class="action-button" [ngClass]="{ small: buttonSize === 'small', grey: theme === 'grey', orange: theme === 'orange', 'button-styled': buttonStyled }" | 3 | class="action-button" [ngClass]="{ small: buttonSize === 'small', grey: theme === 'grey', orange: theme === 'orange', 'button-styled': buttonStyled }" |
4 | ngbDropdownToggle role="button" | 4 | ngbDropdownToggle role="button" |
diff --git a/client/src/app/shared/buttons/action-dropdown.component.ts b/client/src/app/shared/buttons/action-dropdown.component.ts index 8fcaa38b9..15f9556dc 100644 --- a/client/src/app/shared/buttons/action-dropdown.component.ts +++ b/client/src/app/shared/buttons/action-dropdown.component.ts | |||
@@ -27,6 +27,7 @@ export class ActionDropdownComponent<T> { | |||
27 | @Input() entry: T | 27 | @Input() entry: T |
28 | 28 | ||
29 | @Input() placement = 'bottom-left auto' | 29 | @Input() placement = 'bottom-left auto' |
30 | @Input() container: null | 'body' | ||
30 | 31 | ||
31 | @Input() buttonSize: DropdownButtonSize = 'normal' | 32 | @Input() buttonSize: DropdownButtonSize = 'normal' |
32 | @Input() buttonDirection: DropdownDirection = 'horizontal' | 33 | @Input() buttonDirection: DropdownDirection = 'horizontal' |
diff --git a/client/src/sass/primeng-custom.scss b/client/src/sass/primeng-custom.scss index b8e685aba..9c9a6197d 100644 --- a/client/src/sass/primeng-custom.scss +++ b/client/src/sass/primeng-custom.scss | |||
@@ -191,12 +191,22 @@ p-table { | |||
191 | 191 | ||
192 | .ui-dropdown { | 192 | .ui-dropdown { |
193 | position: absolute; | 193 | position: absolute; |
194 | top: 3px; | ||
194 | left: 0; | 195 | left: 0; |
196 | |||
197 | &.ui-state-focus { | ||
198 | box-shadow: #{$focus-box-shadow-form} var(--mainColorLightest); | ||
199 | } | ||
200 | |||
201 | .ui-dropdown-label { | ||
202 | color: var(--inputPlaceholderColor); | ||
203 | } | ||
195 | } | 204 | } |
196 | 205 | ||
197 | .ui-paginator-current { | 206 | .ui-paginator-current { |
198 | position: absolute; | 207 | position: absolute; |
199 | right: 0; | 208 | right: 0; |
209 | color: var(--inputPlaceholderColor); | ||
200 | } | 210 | } |
201 | 211 | ||
202 | .ui-paginator-first, | 212 | .ui-paginator-first, |