diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-06-22 13:00:39 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-22 13:00:39 +0200 |
commit | 1ebddadd0704812a4600c39cabe2268321e88331 (patch) | |
tree | 1cc8560e5b63e9976aa5411ba800a62cfe7b8ea9 /client/src/app/+admin | |
parent | 07aea1a2642fc9868cb01e30c322514029d5b95a (diff) | |
download | PeerTube-1ebddadd0704812a4600c39cabe2268321e88331.tar.gz PeerTube-1ebddadd0704812a4600c39cabe2268321e88331.tar.zst PeerTube-1ebddadd0704812a4600c39cabe2268321e88331.zip |
predefined report reasons & improved reporter UI (#2842)
- added `startAt` and `endAt` optional timestamps to help pin down reported sections of a video
- added predefined report reasons
- added video player with report modal
Diffstat (limited to 'client/src/app/+admin')
4 files changed, 77 insertions, 9 deletions
diff --git a/client/src/app/+admin/moderation/moderation.component.scss b/client/src/app/+admin/moderation/moderation.component.scss index ba68cf6f6..0ec420af9 100644 --- a/client/src/app/+admin/moderation/moderation.component.scss +++ b/client/src/app/+admin/moderation/moderation.component.scss | |||
@@ -42,6 +42,20 @@ | |||
42 | } | 42 | } |
43 | } | 43 | } |
44 | 44 | ||
45 | p-calendar { | ||
46 | display: block; | ||
47 | |||
48 | ::ng-deep { | ||
49 | .ui-widget-content { | ||
50 | min-width: 400px; | ||
51 | } | ||
52 | |||
53 | input { | ||
54 | @include peertube-input-text(100%); | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
45 | .screenratio { | 59 | .screenratio { |
46 | div { | 60 | div { |
47 | @include miniature-thumbnail; | 61 | @include miniature-thumbnail; |
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 453a282d1..5512bb1de 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 | |||
@@ -57,6 +57,22 @@ | |||
57 | <span class="col-9 moderation-expanded-text" [innerHTML]="videoAbuse.reasonHtml"></span> | 57 | <span class="col-9 moderation-expanded-text" [innerHTML]="videoAbuse.reasonHtml"></span> |
58 | </div> | 58 | </div> |
59 | 59 | ||
60 | <div *ngIf="getPredefinedReasons()" class="mt-2 d-flex"> | ||
61 | <span class="col-3"></span> | ||
62 | <span class="col-9"> | ||
63 | <a [routerLink]="[ '/admin/moderation/video-abuses/list' ]" [queryParams]="{ 'search': 'tag:' + reason.id }" class="chip rectangular bg-secondary text-light" *ngFor="let reason of getPredefinedReasons()"> | ||
64 | <div>{{ reason.label }}</div> | ||
65 | </a> | ||
66 | </span> | ||
67 | </div> | ||
68 | |||
69 | <div *ngIf="videoAbuse.startAt" class="mt-2 d-flex"> | ||
70 | <span class="col-3 moderation-expanded-label" i18n>Reported part</span> | ||
71 | <span class="col-9"> | ||
72 | {{ startAt }}<ng-container *ngIf="videoAbuse.endAt"> - {{ endAt }}</ng-container> | ||
73 | </span> | ||
74 | </div> | ||
75 | |||
60 | <div class="mt-3 d-flex" *ngIf="videoAbuse.moderationComment"> | 76 | <div class="mt-3 d-flex" *ngIf="videoAbuse.moderationComment"> |
61 | <span class="col-3 moderation-expanded-label" i18n>Note</span> | 77 | <span class="col-3 moderation-expanded-label" i18n>Note</span> |
62 | <span class="col-9 moderation-expanded-text" [innerHTML]="videoAbuse.moderationCommentHtml"></span> | 78 | <span class="col-9 moderation-expanded-text" [innerHTML]="videoAbuse.moderationCommentHtml"></span> |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts index d9cb19845..13485124f 100644 --- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts +++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-details.component.ts | |||
@@ -1,7 +1,9 @@ | |||
1 | import { Component, Input } from '@angular/core' | 1 | import { Component, Input } from '@angular/core' |
2 | import { Account } from '@app/shared/account/account.model' | ||
3 | import { Actor } from '@app/shared/actor/actor.model' | 2 | import { Actor } from '@app/shared/actor/actor.model' |
3 | import { VideoAbusePredefinedReasonsString } from '../../../../../../shared/models/videos/abuse/video-abuse-reason.model' | ||
4 | import { ProcessedVideoAbuse } from './video-abuse-list.component' | 4 | import { ProcessedVideoAbuse } from './video-abuse-list.component' |
5 | import { I18n } from '@ngx-translate/i18n-polyfill' | ||
6 | import { durationToString } from '@app/shared/misc/utils' | ||
5 | 7 | ||
6 | @Component({ | 8 | @Component({ |
7 | selector: 'my-video-abuse-details', | 9 | selector: 'my-video-abuse-details', |
@@ -11,6 +13,39 @@ import { ProcessedVideoAbuse } from './video-abuse-list.component' | |||
11 | export class VideoAbuseDetailsComponent { | 13 | export class VideoAbuseDetailsComponent { |
12 | @Input() videoAbuse: ProcessedVideoAbuse | 14 | @Input() videoAbuse: ProcessedVideoAbuse |
13 | 15 | ||
16 | private predefinedReasonsTranslations: { [key in VideoAbusePredefinedReasonsString]: string } | ||
17 | |||
18 | constructor ( | ||
19 | private i18n: I18n | ||
20 | ) { | ||
21 | this.predefinedReasonsTranslations = { | ||
22 | violentOrRepulsive: this.i18n('Violent or Repulsive'), | ||
23 | hatefulOrAbusive: this.i18n('Hateful or Abusive'), | ||
24 | spamOrMisleading: this.i18n('Spam or Misleading'), | ||
25 | privacy: this.i18n('Privacy'), | ||
26 | rights: this.i18n('Rights'), | ||
27 | serverRules: this.i18n('Server rules'), | ||
28 | thumbnails: this.i18n('Thumbnails'), | ||
29 | captions: this.i18n('Captions') | ||
30 | } | ||
31 | } | ||
32 | |||
33 | get startAt () { | ||
34 | return durationToString(this.videoAbuse.startAt) | ||
35 | } | ||
36 | |||
37 | get endAt () { | ||
38 | return durationToString(this.videoAbuse.endAt) | ||
39 | } | ||
40 | |||
41 | getPredefinedReasons () { | ||
42 | if (!this.videoAbuse.predefinedReasons) return [] | ||
43 | return this.videoAbuse.predefinedReasons.map(r => ({ | ||
44 | id: r, | ||
45 | label: this.predefinedReasonsTranslations[r] | ||
46 | })) | ||
47 | } | ||
48 | |||
14 | switchToDefaultAvatar ($event: Event) { | 49 | switchToDefaultAvatar ($event: Event) { |
15 | ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() | 50 | ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() |
16 | } | 51 | } |
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 a36acc2ab..d7f5beef3 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 | |||
@@ -11,13 +11,13 @@ import { ModerationCommentModalComponent } from './moderation-comment-modal.comp | |||
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' | 13 | import { Actor } from '@app/shared/actor/actor.model' |
14 | import { buildVideoLink, buildVideoEmbed } from 'src/assets/player/utils' | 14 | import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils' |
15 | import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' | ||
16 | import { DomSanitizer } from '@angular/platform-browser' | 15 | import { DomSanitizer } from '@angular/platform-browser' |
17 | import { BlocklistService } from '@app/shared/blocklist' | 16 | import { BlocklistService } from '@app/shared/blocklist' |
18 | import { VideoService } from '@app/shared/video/video.service' | 17 | import { VideoService } from '@app/shared/video/video.service' |
19 | import { ActivatedRoute, Params, Router } from '@angular/router' | 18 | import { ActivatedRoute, Params, Router } from '@angular/router' |
20 | import { filter } from 'rxjs/operators' | 19 | import { filter } from 'rxjs/operators' |
20 | import { environment } from 'src/environments/environment' | ||
21 | 21 | ||
22 | export type ProcessedVideoAbuse = VideoAbuse & { | 22 | export type ProcessedVideoAbuse = VideoAbuse & { |
23 | moderationCommentHtml?: string, | 23 | moderationCommentHtml?: string, |
@@ -259,12 +259,15 @@ export class VideoAbuseListComponent extends RestTable implements OnInit, AfterV | |||
259 | } | 259 | } |
260 | 260 | ||
261 | getVideoEmbed (videoAbuse: VideoAbuse) { | 261 | getVideoEmbed (videoAbuse: VideoAbuse) { |
262 | const absoluteAPIUrl = getAbsoluteAPIUrl() | 262 | return buildVideoEmbed( |
263 | const embedUrl = buildVideoLink({ | 263 | buildVideoLink({ |
264 | baseUrl: absoluteAPIUrl + '/videos/embed/' + videoAbuse.video.uuid, | 264 | baseUrl: `${environment.embedUrl}/videos/embed/${videoAbuse.video.uuid}`, |
265 | warningTitle: false | 265 | title: false, |
266 | }) | 266 | warningTitle: false, |
267 | return buildVideoEmbed(embedUrl) | 267 | startTime: videoAbuse.startAt, |
268 | stopTime: videoAbuse.endAt | ||
269 | }) | ||
270 | ) | ||
268 | } | 271 | } |
269 | 272 | ||
270 | switchToDefaultAvatar ($event: Event) { | 273 | switchToDefaultAvatar ($event: Event) { |