From 1ebddadd0704812a4600c39cabe2268321e88331 Mon Sep 17 00:00:00 2001 From: Rigel Kent Date: Mon, 22 Jun 2020 13:00:39 +0200 Subject: [PATCH] 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 --- .../moderation/moderation.component.scss | 14 +++ .../video-abuse-details.component.html | 16 +++ .../video-abuse-details.component.ts | 37 +++++- .../video-abuse-list.component.ts | 19 ++-- client/src/app/shared/rest/rest.service.ts | 6 +- .../shared/video-abuse/video-abuse.service.ts | 13 ++- .../video/modals/video-block.component.html | 4 +- .../video/modals/video-report.component.html | 105 ++++++++++++++---- .../video/modals/video-report.component.scss | 17 +++ .../video/modals/video-report.component.ts | 104 +++++++++++++++-- client/src/app/shared/video/video.model.ts | 3 +- client/src/environments/environment.e2e.ts | 3 +- client/src/environments/environment.hmr.ts | 3 +- client/src/environments/environment.prod.ts | 3 +- client/src/environments/environment.ts | 3 +- client/src/sass/include/_mixins.scss | 11 +- client/src/sass/player/peertube-skin.scss | 2 +- server/controllers/api/videos/abuse.ts | 11 +- .../helpers/custom-validators/video-abuses.ts | 29 ++++- server/initializers/constants.ts | 2 +- .../0515-video-abuse-reason-timestamps.ts | 31 ++++++ .../lib/activitypub/process/process-flag.ts | 17 ++- .../validators/videos/video-abuses.ts | 39 ++++++- server/models/video/video-abuse.ts | 64 ++++++++++- server/tests/api/check-params/video-abuses.ts | 30 ++++- server/tests/api/videos/video-abuse.ts | 43 +++++-- shared/extra-utils/videos/video-abuses.ts | 18 ++- shared/models/activitypub/activity.ts | 5 +- .../activitypub/objects/common-objects.ts | 11 +- .../activitypub/objects/video-abuse-object.ts | 5 + .../videos/abuse/video-abuse-create.model.ts | 5 + .../videos/abuse/video-abuse-reason.model.ts | 33 ++++++ .../models/videos/abuse/video-abuse.model.ts | 5 + shared/models/videos/index.ts | 1 + support/doc/api/openapi.yaml | 40 ++++++- 35 files changed, 657 insertions(+), 95 deletions(-) create mode 100644 server/initializers/migrations/0515-video-abuse-reason-timestamps.ts create mode 100644 shared/models/videos/abuse/video-abuse-reason.model.ts 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 @@ } } +p-calendar { + display: block; + + ::ng-deep { + .ui-widget-content { + min-width: 400px; + } + + input { + @include peertube-input-text(100%); + } + } +} + .screenratio { div { @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 @@ +
+ + + +
{{ reason.label }}
+
+
+
+ +
+ Reported part + + {{ startAt }} - {{ endAt }} + +
+
Note 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 @@ import { Component, Input } from '@angular/core' -import { Account } from '@app/shared/account/account.model' import { Actor } from '@app/shared/actor/actor.model' +import { VideoAbusePredefinedReasonsString } from '../../../../../../shared/models/videos/abuse/video-abuse-reason.model' import { ProcessedVideoAbuse } from './video-abuse-list.component' +import { I18n } from '@ngx-translate/i18n-polyfill' +import { durationToString } from '@app/shared/misc/utils' @Component({ selector: 'my-video-abuse-details', @@ -11,6 +13,39 @@ import { ProcessedVideoAbuse } from './video-abuse-list.component' export class VideoAbuseDetailsComponent { @Input() videoAbuse: ProcessedVideoAbuse + private predefinedReasonsTranslations: { [key in VideoAbusePredefinedReasonsString]: string } + + constructor ( + private i18n: I18n + ) { + this.predefinedReasonsTranslations = { + violentOrRepulsive: this.i18n('Violent or Repulsive'), + hatefulOrAbusive: this.i18n('Hateful or Abusive'), + spamOrMisleading: this.i18n('Spam or Misleading'), + privacy: this.i18n('Privacy'), + rights: this.i18n('Rights'), + serverRules: this.i18n('Server rules'), + thumbnails: this.i18n('Thumbnails'), + captions: this.i18n('Captions') + } + } + + get startAt () { + return durationToString(this.videoAbuse.startAt) + } + + get endAt () { + return durationToString(this.videoAbuse.endAt) + } + + getPredefinedReasons () { + if (!this.videoAbuse.predefinedReasons) return [] + return this.videoAbuse.predefinedReasons.map(r => ({ + id: r, + label: this.predefinedReasonsTranslations[r] + })) + } + switchToDefaultAvatar ($event: Event) { ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() } 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 import { Video } from '../../../shared/video/video.model' import { MarkdownService } from '@app/shared/renderer' import { Actor } from '@app/shared/actor/actor.model' -import { buildVideoLink, buildVideoEmbed } from 'src/assets/player/utils' -import { getAbsoluteAPIUrl } from '@app/shared/misc/utils' +import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils' import { DomSanitizer } from '@angular/platform-browser' import { BlocklistService } from '@app/shared/blocklist' import { VideoService } from '@app/shared/video/video.service' import { ActivatedRoute, Params, Router } from '@angular/router' import { filter } from 'rxjs/operators' +import { environment } from 'src/environments/environment' export type ProcessedVideoAbuse = VideoAbuse & { moderationCommentHtml?: string, @@ -259,12 +259,15 @@ export class VideoAbuseListComponent extends RestTable implements OnInit, AfterV } getVideoEmbed (videoAbuse: VideoAbuse) { - const absoluteAPIUrl = getAbsoluteAPIUrl() - const embedUrl = buildVideoLink({ - baseUrl: absoluteAPIUrl + '/videos/embed/' + videoAbuse.video.uuid, - warningTitle: false - }) - return buildVideoEmbed(embedUrl) + return buildVideoEmbed( + buildVideoLink({ + baseUrl: `${environment.embedUrl}/videos/embed/${videoAbuse.video.uuid}`, + title: false, + warningTitle: false, + startTime: videoAbuse.startAt, + stopTime: videoAbuse.endAt + }) + ) } switchToDefaultAvatar ($event: Event) { diff --git a/client/src/app/shared/rest/rest.service.ts b/client/src/app/shared/rest/rest.service.ts index cd6db1f3c..78558851a 100644 --- a/client/src/app/shared/rest/rest.service.ts +++ b/client/src/app/shared/rest/rest.service.ts @@ -46,7 +46,7 @@ export class RestService { addObjectParams (params: HttpParams, object: { [ name: string ]: any }) { for (const name of Object.keys(object)) { const value = object[name] - if (!value) continue + if (value === undefined || value === null) continue if (Array.isArray(value) && value.length !== 0) { for (const v of value) params = params.append(name, v) @@ -93,7 +93,7 @@ export class RestService { return t }) - .filter(t => !!t) + .filter(t => !!t || t === 0) if (matchedTokens.length === 0) continue @@ -103,7 +103,7 @@ export class RestService { } return { - search: searchTokens.join(' '), + search: searchTokens.join(' ') || undefined, ...additionalFilters } diff --git a/client/src/app/shared/video-abuse/video-abuse.service.ts b/client/src/app/shared/video-abuse/video-abuse.service.ts index 700a30239..43f4674b1 100644 --- a/client/src/app/shared/video-abuse/video-abuse.service.ts +++ b/client/src/app/shared/video-abuse/video-abuse.service.ts @@ -3,9 +3,10 @@ import { HttpClient, HttpParams } from '@angular/common/http' import { Injectable } from '@angular/core' import { SortMeta } from 'primeng/api' import { Observable } from 'rxjs' -import { ResultList, VideoAbuse, VideoAbuseUpdate, VideoAbuseState } from '../../../../../shared' +import { ResultList, VideoAbuse, VideoAbuseCreate, VideoAbuseState, VideoAbuseUpdate } from '../../../../../shared' import { environment } from '../../../environments/environment' import { RestExtractor, RestPagination, RestService } from '../rest' +import { omit } from 'lodash-es' @Injectable() export class VideoAbuseService { @@ -51,7 +52,8 @@ export class VideoAbuseService { } }, searchReporter: { prefix: 'reporter:' }, - searchReportee: { prefix: 'reportee:' } + searchReportee: { prefix: 'reportee:' }, + predefinedReason: { prefix: 'tag:' } }) params = this.restService.addObjectParams(params, filters) @@ -63,9 +65,10 @@ export class VideoAbuseService { ) } - reportVideo (id: number, reason: string) { - const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + id + '/abuse' - const body = { reason } + reportVideo (parameters: { id: number } & VideoAbuseCreate) { + const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + parameters.id + '/abuse' + + const body = omit(parameters, [ 'id' ]) return this.authHttp.post(url, body) .pipe( diff --git a/client/src/app/shared/video/modals/video-block.component.html b/client/src/app/shared/video/modals/video-block.component.html index a8dd30b5e..5e73d66c5 100644 --- a/client/src/app/shared/video/modals/video-block.component.html +++ b/client/src/app/shared/video/modals/video-block.component.html @@ -1,6 +1,6 @@ @@ -9,7 +9,7 @@
diff --git a/client/src/app/shared/video/modals/video-report.component.html b/client/src/app/shared/video/modals/video-report.component.html index e336b6660..d6beb6d2a 100644 --- a/client/src/app/shared/video/modals/video-report.component.html +++ b/client/src/app/shared/video/modals/video-report.component.html @@ -1,38 +1,97 @@