diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-04-13 19:57:57 +0200 |
---|---|---|
committer | Rigel Kent <sendmemail@rigelk.eu> | 2020-04-13 19:57:57 +0200 |
commit | d6af81469ba9390ce8ce80161a7de3526ae0253d (patch) | |
tree | 739e91d6bc779b5cce5af3db68813a48dd780784 | |
parent | 2bc9bd08cd121bdffbf56a0241c4decfb77bfdd5 (diff) | |
download | PeerTube-d6af81469ba9390ce8ce80161a7de3526ae0253d.tar.gz PeerTube-d6af81469ba9390ce8ce80161a7de3526ae0253d.tar.zst PeerTube-d6af81469ba9390ce8ce80161a7de3526ae0253d.zip |
Rich reporter field and video embed in moderation abuse list
9 files changed, 163 insertions, 28 deletions
diff --git a/client/src/app/+admin/moderation/moderation.component.scss b/client/src/app/+admin/moderation/moderation.component.scss index 13b019c5b..89e9b47d3 100644 --- a/client/src/app/+admin/moderation/moderation.component.scss +++ b/client/src/app/+admin/moderation/moderation.component.scss | |||
@@ -8,18 +8,35 @@ | |||
8 | 8 | ||
9 | .moderation-expanded-label { | 9 | .moderation-expanded-label { |
10 | font-weight: $font-semibold; | 10 | font-weight: $font-semibold; |
11 | min-width: 200px; | ||
12 | display: inline-block; | 11 | display: inline-block; |
13 | vertical-align: top; | 12 | vertical-align: top; |
13 | text-align: right; | ||
14 | } | 14 | } |
15 | 15 | ||
16 | .moderation-expanded-text { | 16 | .moderation-expanded-text { |
17 | display: inline-block; | 17 | display: inline-block; |
18 | word-wrap: break-word; | ||
19 | |||
20 | ::ng-deep p:last-child { | ||
21 | margin-bottom: 0px !important; | ||
22 | } | ||
18 | } | 23 | } |
19 | 24 | ||
20 | .moderation-expanded { | 25 | .screenratio { |
21 | word-wrap: break-word; | 26 | position: relative; |
22 | overflow: visible !important; | 27 | width: 100%; |
23 | text-overflow: unset !important; | 28 | height: 0; |
24 | white-space: unset !important; | 29 | padding-bottom: 56%; |
30 | |||
31 | ::ng-deep iframe { | ||
32 | position: absolute; | ||
33 | width: 100% !important; | ||
34 | height: 100% !important; | ||
35 | left: 0; | ||
36 | top: 0; | ||
37 | } | ||
38 | } | ||
39 | |||
40 | .chip { | ||
41 | @include chip; | ||
25 | } | 42 | } |
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 cf7b61d2a..155d10dda 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 | |||
@@ -24,8 +24,19 @@ | |||
24 | </td> | 24 | </td> |
25 | 25 | ||
26 | <td> | 26 | <td> |
27 | <a [href]="videoAbuse.reporterAccount.url" i18n-title title="Go to the account" target="_blank" rel="noopener noreferrer"> | 27 | <a [href]="videoAbuse.reporterAccount.url" i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer"> |
28 | {{ createByString(videoAbuse.reporterAccount) }} | 28 | <div class="chip two-lines"> |
29 | <img | ||
30 | class="avatar" | ||
31 | [src]="videoAbuse.reporterAccount.avatar.path" | ||
32 | (error)="switchToDefaultAvatar($event)" | ||
33 | alt="Avatar" | ||
34 | > | ||
35 | <div> | ||
36 | {{ videoAbuse.reporterAccount.displayName }} | ||
37 | <span class="text-muted">{{ createByString(videoAbuse.reporterAccount) }}</span> | ||
38 | </div> | ||
39 | </div> | ||
29 | </a> | 40 | </a> |
30 | </td> | 41 | </td> |
31 | 42 | ||
@@ -50,14 +61,22 @@ | |||
50 | 61 | ||
51 | <ng-template pTemplate="rowexpansion" let-videoAbuse> | 62 | <ng-template pTemplate="rowexpansion" let-videoAbuse> |
52 | <tr> | 63 | <tr> |
53 | <td class="moderation-expanded" colspan="6"> | 64 | <td class="expand-cell" colspan="6"> |
54 | <div> | 65 | <div class="d-flex"> |
55 | <span i18n class="moderation-expanded-label">Reason:</span> | 66 | <div class="col-8"> |
56 | <span class="moderation-expanded-text" [innerHTML]="videoAbuse.reasonHtml"></span> | 67 | <div class="d-flex"> |
57 | </div> | 68 | <span class="col-3 moderation-expanded-label" i18n>Reason:</span> |
58 | <div *ngIf="videoAbuse.moderationComment"> | 69 | <span class="col-9 moderation-expanded-text" [innerHTML]="videoAbuse.reasonHtml"></span> |
59 | <span i18n class="moderation-expanded-label">Moderation comment:</span> | 70 | </div> |
60 | <span class="moderation-expanded-text" [innerHTML]="videoAbuse.moderationCommentHtml"></span> | 71 | <div class="mt-3 d-flex" *ngIf="videoAbuse.moderationComment"> |
72 | <span class="col-3 moderation-expanded-label" i18n>Note:</span> | ||
73 | <span class="col-9 moderation-expanded-text" [innerHTML]="videoAbuse.moderationCommentHtml"></span> | ||
74 | </div> | ||
75 | </div> | ||
76 | |||
77 | <div class="col-4"> | ||
78 | <div class="screenratio" [innerHTML]="videoAbuse.embedHtml"></div> | ||
79 | </div> | ||
61 | </div> | 80 | </div> |
62 | </td> | 81 | </td> |
63 | </tr> | 82 | </tr> |
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 2d991aae9..b135792a7 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 | |||
@@ -10,6 +10,10 @@ import { ConfirmService } from '../../../core/index' | |||
10 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' | 10 | import { ModerationCommentModalComponent } from './moderation-comment-modal.component' |
11 | import { Video } from '../../../shared/video/video.model' | 11 | import { Video } from '../../../shared/video/video.model' |
12 | import { MarkdownService } from '@app/shared/renderer' | 12 | import { MarkdownService } from '@app/shared/renderer' |
13 | import { Actor } from '@app/shared/actor/actor.model' | ||
14 | import { buildVideoLink, buildVideoEmbed } from 'src/assets/player/utils' | ||
15 | import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' | ||
16 | import { DomSanitizer } from '@angular/platform-browser' | ||
13 | 17 | ||
14 | @Component({ | 18 | @Component({ |
15 | selector: 'my-video-abuse-list', | 19 | selector: 'my-video-abuse-list', |
@@ -32,7 +36,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
32 | private videoAbuseService: VideoAbuseService, | 36 | private videoAbuseService: VideoAbuseService, |
33 | private confirmService: ConfirmService, | 37 | private confirmService: ConfirmService, |
34 | private i18n: I18n, | 38 | private i18n: I18n, |
35 | private markdownRenderer: MarkdownService | 39 | private markdownRenderer: MarkdownService, |
40 | private sanitizer: DomSanitizer | ||
36 | ) { | 41 | ) { |
37 | super() | 42 | super() |
38 | 43 | ||
@@ -42,8 +47,14 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
42 | handler: videoAbuse => this.removeVideoAbuse(videoAbuse) | 47 | handler: videoAbuse => this.removeVideoAbuse(videoAbuse) |
43 | }, | 48 | }, |
44 | { | 49 | { |
45 | label: this.i18n('Update moderation comment'), | 50 | label: this.i18n('Add note'), |
46 | handler: videoAbuse => this.openModerationCommentModal(videoAbuse) | 51 | handler: videoAbuse => this.openModerationCommentModal(videoAbuse), |
52 | isDisplayed: videoAbuse => !videoAbuse.moderationComment | ||
53 | }, | ||
54 | { | ||
55 | label: this.i18n('Update note'), | ||
56 | handler: videoAbuse => this.openModerationCommentModal(videoAbuse), | ||
57 | isDisplayed: videoAbuse => !!videoAbuse.moderationComment | ||
47 | }, | 58 | }, |
48 | { | 59 | { |
49 | label: this.i18n('Mark as accepted'), | 60 | label: this.i18n('Mark as accepted'), |
@@ -90,6 +101,19 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
90 | return Video.buildClientUrl(videoAbuse.video.uuid) | 101 | return Video.buildClientUrl(videoAbuse.video.uuid) |
91 | } | 102 | } |
92 | 103 | ||
104 | getVideoEmbed (videoAbuse: VideoAbuse) { | ||
105 | const absoluteAPIUrl = 'http://localhost:9000' || getAbsoluteAPIUrl() | ||
106 | const embedUrl = buildVideoLink({ | ||
107 | baseUrl: absoluteAPIUrl + '/videos/embed/' + videoAbuse.video.uuid, | ||
108 | warningTitle: false | ||
109 | }) | ||
110 | return buildVideoEmbed(embedUrl) | ||
111 | } | ||
112 | |||
113 | switchToDefaultAvatar ($event: Event) { | ||
114 | ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() | ||
115 | } | ||
116 | |||
93 | async removeVideoAbuse (videoAbuse: VideoAbuse) { | 117 | async removeVideoAbuse (videoAbuse: VideoAbuse) { |
94 | const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this abuse report?'), this.i18n('Delete')) | 118 | const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this abuse report?'), this.i18n('Delete')) |
95 | if (res === false) return | 119 | if (res === false) return |
@@ -125,7 +149,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit { | |||
125 | for (const abuse of this.videoAbuses) { | 149 | for (const abuse of this.videoAbuses) { |
126 | Object.assign(abuse, { | 150 | Object.assign(abuse, { |
127 | reasonHtml: await this.toHtml(abuse.reason), | 151 | reasonHtml: await this.toHtml(abuse.reason), |
128 | moderationCommentHtml: await this.toHtml(abuse.moderationComment) | 152 | moderationCommentHtml: await this.toHtml(abuse.moderationComment), |
153 | embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)) | ||
129 | }) | 154 | }) |
130 | } | 155 | } |
131 | 156 | ||
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 a39e7639e..320172e37 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 | |||
@@ -42,9 +42,9 @@ | |||
42 | 42 | ||
43 | <ng-template pTemplate="rowexpansion" let-videoBlacklist> | 43 | <ng-template pTemplate="rowexpansion" let-videoBlacklist> |
44 | <tr> | 44 | <tr> |
45 | <td class="moderation-expanded" colspan="6"> | 45 | <td class="expand-cell" colspan="6"> |
46 | <span i18n class="moderation-expanded-label">Blacklist reason:</span> | 46 | <span class="col-2 moderation-expanded-label" i18n>Blacklist reason:</span> |
47 | <span class="moderation-expanded-text" [innerHTML]="videoBlacklist.reasonHtml"></span> | 47 | <span class="col-9 moderation-expanded-text" [innerHTML]="videoBlacklist.reasonHtml"></span> |
48 | </td> | 48 | </td> |
49 | </tr> | 49 | </tr> |
50 | </ng-template> | 50 | </ng-template> |
diff --git a/client/src/app/+admin/users/user-list/user-list.component.html b/client/src/app/+admin/users/user-list/user-list.component.html index 15bdb6398..e9ff61283 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.html +++ b/client/src/app/+admin/users/user-list/user-list.component.html | |||
@@ -51,19 +51,30 @@ | |||
51 | <ng-template pTemplate="body" let-expanded="expanded" let-user> | 51 | <ng-template pTemplate="body" let-expanded="expanded" let-user> |
52 | 52 | ||
53 | <tr [pSelectableRow]="user" [ngClass]="{ banned: user.blocked }"> | 53 | <tr [pSelectableRow]="user" [ngClass]="{ banned: user.blocked }"> |
54 | <td class="expand-cell"> | 54 | <td> |
55 | <p-tableCheckbox [value]="user"></p-tableCheckbox> | 55 | <p-tableCheckbox [value]="user"></p-tableCheckbox> |
56 | </td> | 56 | </td> |
57 | 57 | ||
58 | <td> | 58 | <td class="expand-cell"> |
59 | <span *ngIf="user.blockedReason" class="expander" [pRowToggler]="user"> | 59 | <span *ngIf="user.blockedReason" class="expander" [pRowToggler]="user"> |
60 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> | 60 | <i [ngClass]="expanded ? 'glyphicon glyphicon-menu-down' : 'glyphicon glyphicon-menu-right'"></i> |
61 | </span> | 61 | </span> |
62 | </td> | 62 | </td> |
63 | 63 | ||
64 | <td> | 64 | <td> |
65 | <a i18n-title title="Go to the account page" target="_blank" rel="noopener noreferrer" [routerLink]="[ '/accounts/' + user.username ]"> | 65 | <a i18n-title title="Open account in a new tab" target="_blank" rel="noopener noreferrer" [routerLink]="[ '/accounts/' + user.username ]"> |
66 | {{ user.username }} | 66 | <div class="chip two-lines"> |
67 | <img | ||
68 | class="avatar" | ||
69 | [src]="user?.account?.avatar?.path" | ||
70 | (error)="switchToDefaultAvatar($event)" | ||
71 | alt="Avatar" | ||
72 | > | ||
73 | <div> | ||
74 | {{ user.account.displayName }} | ||
75 | <span class="text-muted">{{ user.username }}</span> | ||
76 | </div> | ||
77 | </div> | ||
67 | <span i18n *ngIf="user.blocked" class="banned-info">(banned)</span> | 78 | <span i18n *ngIf="user.blocked" class="banned-info">(banned)</span> |
68 | </a> | 79 | </a> |
69 | </td> | 80 | </td> |
diff --git a/client/src/app/+admin/users/user-list/user-list.component.scss b/client/src/app/+admin/users/user-list/user-list.component.scss index 40f08027f..99b22aaea 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.scss +++ b/client/src/app/+admin/users/user-list/user-list.component.scss | |||
@@ -29,3 +29,7 @@ p-tableCheckbox { | |||
29 | position: relative; | 29 | position: relative; |
30 | top: -2.5px; | 30 | top: -2.5px; |
31 | } | 31 | } |
32 | |||
33 | .chip { | ||
34 | @include chip; | ||
35 | } | ||
diff --git a/client/src/app/+admin/users/user-list/user-list.component.ts b/client/src/app/+admin/users/user-list/user-list.component.ts index 0de123e93..667a0e1fd 100644 --- a/client/src/app/+admin/users/user-list/user-list.component.ts +++ b/client/src/app/+admin/users/user-list/user-list.component.ts | |||
@@ -7,6 +7,7 @@ import { I18n } from '@ngx-translate/i18n-polyfill' | |||
7 | import { ServerConfig, User } from '../../../../../../shared' | 7 | import { ServerConfig, User } from '../../../../../../shared' |
8 | import { UserBanModalComponent } from '@app/shared/moderation' | 8 | import { UserBanModalComponent } from '@app/shared/moderation' |
9 | import { DropdownAction } from '@app/shared/buttons/action-dropdown.component' | 9 | import { DropdownAction } from '@app/shared/buttons/action-dropdown.component' |
10 | import { Actor } from '@app/shared/actor/actor.model' | ||
10 | 11 | ||
11 | @Component({ | 12 | @Component({ |
12 | selector: 'my-user-list', | 13 | selector: 'my-user-list', |
@@ -105,6 +106,10 @@ export class UserListComponent extends RestTable implements OnInit { | |||
105 | this.loadData() | 106 | this.loadData() |
106 | } | 107 | } |
107 | 108 | ||
109 | switchToDefaultAvatar ($event: Event) { | ||
110 | ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() | ||
111 | } | ||
112 | |||
108 | async unbanUsers (users: User[]) { | 113 | async unbanUsers (users: User[]) { |
109 | const message = this.i18n('Do you really want to unban {{num}} users?', { num: users.length }) | 114 | const message = this.i18n('Do you really want to unban {{num}} users?', { num: users.length }) |
110 | 115 | ||
diff --git a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts index 153fc0127..75d6d8acd 100644 --- a/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts +++ b/client/src/app/+my-account/my-account-video-channels/my-account-video-channels.component.ts | |||
@@ -56,7 +56,7 @@ export class MyAccountVideoChannelsComponent implements OnInit { | |||
56 | display: false, | 56 | display: false, |
57 | ticks: { | 57 | ticks: { |
58 | min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)), | 58 | min: Math.max(0, this.videoChannelsMinimumDailyViews - (3 * this.videoChannelsMaximumDailyViews / 100)), |
59 | max: this.videoChannelsMaximumDailyViews | 59 | max: Math.max(1, this.videoChannelsMaximumDailyViews) |
60 | } | 60 | } |
61 | }] | 61 | }] |
62 | }, | 62 | }, |
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss index 975072637..3c420f547 100644 --- a/client/src/sass/include/_mixins.scss +++ b/client/src/sass/include/_mixins.scss | |||
@@ -796,3 +796,57 @@ | |||
796 | } | 796 | } |
797 | } | 797 | } |
798 | } | 798 | } |
799 | |||
800 | @mixin chip { | ||
801 | $avatar-height: 1.2rem; | ||
802 | |||
803 | align-items: center; | ||
804 | border-radius: 5rem; | ||
805 | display: inline-flex; | ||
806 | font-size: 90%; | ||
807 | color: var(--mainForegroundColor); | ||
808 | height: $avatar-height; | ||
809 | line-height: .8rem; | ||
810 | margin: .1rem; | ||
811 | max-width: 320px; | ||
812 | overflow: hidden; | ||
813 | padding: .2rem .4rem; | ||
814 | text-decoration: none; | ||
815 | text-overflow: ellipsis; | ||
816 | vertical-align: middle; | ||
817 | white-space: nowrap; | ||
818 | |||
819 | .avatar { | ||
820 | margin-left: -.4rem; | ||
821 | margin-right: .2rem; | ||
822 | height: $avatar-height; | ||
823 | width: $avatar-height; | ||
824 | |||
825 | border-radius: 50%; | ||
826 | display: inline-block; | ||
827 | line-height: 1.25; | ||
828 | position: relative; | ||
829 | vertical-align: middle; | ||
830 | } | ||
831 | |||
832 | &.two-lines { | ||
833 | $avatar-height: 1.8rem; | ||
834 | |||
835 | height: $avatar-height; | ||
836 | |||
837 | .avatar { | ||
838 | height: $avatar-height; | ||
839 | width: $avatar-height; | ||
840 | } | ||
841 | |||
842 | div { | ||
843 | display: flex; | ||
844 | flex-direction: column; | ||
845 | font-size: 80%; | ||
846 | height: $avatar-height; | ||
847 | margin-left: .1rem; | ||
848 | margin-right: .1rem; | ||
849 | justify-content: center; | ||
850 | } | ||
851 | } | ||
852 | } | ||