aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/shared/shared-moderation/report-modals
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2020-07-09 15:54:24 +0200
committerChocobozzz <chocobozzz@cpy.re>2020-07-10 14:02:41 +0200
commitcfde28bac33c3644e1b6218eb471b675a37def60 (patch)
treeeb648fc358a2face0f14c598c8eec7769e6b0ed5 /client/src/app/shared/shared-moderation/report-modals
parent8ca56654a176ee8f350d31282c6cac4a59f58499 (diff)
downloadPeerTube-cfde28bac33c3644e1b6218eb471b675a37def60.tar.gz
PeerTube-cfde28bac33c3644e1b6218eb471b675a37def60.tar.zst
PeerTube-cfde28bac33c3644e1b6218eb471b675a37def60.zip
Add ability to report account
Diffstat (limited to 'client/src/app/shared/shared-moderation/report-modals')
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/account-report.component.ts94
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/comment-report.component.ts94
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/index.ts3
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/report.component.html62
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/report.component.scss27
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/video-report.component.html100
-rw-r--r--client/src/app/shared/shared-moderation/report-modals/video-report.component.ts122
7 files changed, 502 insertions, 0 deletions
diff --git a/client/src/app/shared/shared-moderation/report-modals/account-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/account-report.component.ts
new file mode 100644
index 000000000..78ca934c7
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/report-modals/account-report.component.ts
@@ -0,0 +1,94 @@
1import { mapValues, pickBy } from 'lodash-es'
2import { Component, Input, OnInit, ViewChild } from '@angular/core'
3import { Notifier } from '@app/core'
4import { AbuseValidatorsService, FormReactive, FormValidatorService } from '@app/shared/shared-forms'
5import { Account } from '@app/shared/shared-main'
6import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
7import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
8import { I18n } from '@ngx-translate/i18n-polyfill'
9import { abusePredefinedReasonsMap, AbusePredefinedReasonsString } from '@shared/models'
10import { AbuseService } from '../abuse.service'
11
12@Component({
13 selector: 'my-account-report',
14 templateUrl: './report.component.html',
15 styleUrls: [ './report.component.scss' ]
16})
17export class AccountReportComponent extends FormReactive implements OnInit {
18 @Input() account: Account = null
19
20 @ViewChild('modal', { static: true }) modal: NgbModal
21
22 error: string = null
23 predefinedReasons: { id: AbusePredefinedReasonsString, label: string, description?: string, help?: string }[] = []
24 modalTitle: string
25
26 private openedModal: NgbModalRef
27
28 constructor (
29 protected formValidatorService: FormValidatorService,
30 private modalService: NgbModal,
31 private abuseValidatorsService: AbuseValidatorsService,
32 private abuseService: AbuseService,
33 private notifier: Notifier,
34 private i18n: I18n
35 ) {
36 super()
37 }
38
39 get currentHost () {
40 return window.location.host
41 }
42
43 get originHost () {
44 if (this.isRemote()) {
45 return this.account.host
46 }
47
48 return ''
49 }
50
51 ngOnInit () {
52 this.modalTitle = this.i18n('Report {{displayName}}', { displayName: this.account.displayName })
53
54 this.buildForm({
55 reason: this.abuseValidatorsService.ABUSE_REASON,
56 predefinedReasons: mapValues(abusePredefinedReasonsMap, r => null)
57 })
58
59 this.predefinedReasons = this.abuseService.getPrefefinedReasons('account')
60 }
61
62 show () {
63 this.openedModal = this.modalService.open(this.modal, { centered: true, keyboard: false, size: 'lg' })
64 }
65
66 hide () {
67 this.openedModal.close()
68 this.openedModal = null
69 }
70
71 report () {
72 const reason = this.form.get('reason').value
73 const predefinedReasons = Object.keys(pickBy(this.form.get('predefinedReasons').value)) as AbusePredefinedReasonsString[]
74
75 this.abuseService.reportVideo({
76 reason,
77 predefinedReasons,
78 account: {
79 id: this.account.id
80 }
81 }).subscribe(
82 () => {
83 this.notifier.success(this.i18n('Account reported.'))
84 this.hide()
85 },
86
87 err => this.notifier.error(err.message)
88 )
89 }
90
91 isRemote () {
92 return !this.account.isLocal
93 }
94}
diff --git a/client/src/app/shared/shared-moderation/report-modals/comment-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/comment-report.component.ts
new file mode 100644
index 000000000..00d7b8d34
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/report-modals/comment-report.component.ts
@@ -0,0 +1,94 @@
1import { mapValues, pickBy } from 'lodash-es'
2import { Component, Input, OnInit, ViewChild } from '@angular/core'
3import { Notifier } from '@app/core'
4import { AbuseValidatorsService, FormReactive, FormValidatorService } from '@app/shared/shared-forms'
5import { VideoComment } from '@app/shared/shared-video-comment'
6import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
7import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
8import { I18n } from '@ngx-translate/i18n-polyfill'
9import { abusePredefinedReasonsMap, AbusePredefinedReasonsString } from '@shared/models'
10import { AbuseService } from '../abuse.service'
11
12@Component({
13 selector: 'my-comment-report',
14 templateUrl: './report.component.html',
15 styleUrls: [ './report.component.scss' ]
16})
17export class CommentReportComponent extends FormReactive implements OnInit {
18 @Input() comment: VideoComment = null
19
20 @ViewChild('modal', { static: true }) modal: NgbModal
21
22 modalTitle: string
23 error: string = null
24 predefinedReasons: { id: AbusePredefinedReasonsString, label: string, description?: string, help?: string }[] = []
25
26 private openedModal: NgbModalRef
27
28 constructor (
29 protected formValidatorService: FormValidatorService,
30 private modalService: NgbModal,
31 private abuseValidatorsService: AbuseValidatorsService,
32 private abuseService: AbuseService,
33 private notifier: Notifier,
34 private i18n: I18n
35 ) {
36 super()
37 }
38
39 get currentHost () {
40 return window.location.host
41 }
42
43 get originHost () {
44 if (this.isRemote()) {
45 return this.comment.account.host
46 }
47
48 return ''
49 }
50
51 ngOnInit () {
52 this.modalTitle = this.i18n('Report comment')
53
54 this.buildForm({
55 reason: this.abuseValidatorsService.ABUSE_REASON,
56 predefinedReasons: mapValues(abusePredefinedReasonsMap, r => null)
57 })
58
59 this.predefinedReasons = this.abuseService.getPrefefinedReasons('comment')
60 }
61
62 show () {
63 this.openedModal = this.modalService.open(this.modal, { centered: true, keyboard: false, size: 'lg' })
64 }
65
66 hide () {
67 this.openedModal.close()
68 this.openedModal = null
69 }
70
71 report () {
72 const reason = this.form.get('reason').value
73 const predefinedReasons = Object.keys(pickBy(this.form.get('predefinedReasons').value)) as AbusePredefinedReasonsString[]
74
75 this.abuseService.reportVideo({
76 reason,
77 predefinedReasons,
78 comment: {
79 id: this.comment.id
80 }
81 }).subscribe(
82 () => {
83 this.notifier.success(this.i18n('Comment reported.'))
84 this.hide()
85 },
86
87 err => this.notifier.error(err.message)
88 )
89 }
90
91 isRemote () {
92 return !this.comment.isLocal
93 }
94}
diff --git a/client/src/app/shared/shared-moderation/report-modals/index.ts b/client/src/app/shared/shared-moderation/report-modals/index.ts
new file mode 100644
index 000000000..f3c4058ae
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/report-modals/index.ts
@@ -0,0 +1,3 @@
1export * from './account-report.component'
2export * from './comment-report.component'
3export * from './video-report.component'
diff --git a/client/src/app/shared/shared-moderation/report-modals/report.component.html b/client/src/app/shared/shared-moderation/report-modals/report.component.html
new file mode 100644
index 000000000..bda62312f
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/report-modals/report.component.html
@@ -0,0 +1,62 @@
1<ng-template #modal>
2 <div class="modal-header">
3 <h4 class="modal-title">{{ modalTitle }}</h4>
4 <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
5 </div>
6
7 <div class="modal-body">
8 <form novalidate [formGroup]="form" (ngSubmit)="report()">
9
10 <div class="row">
11 <div class="col-5 form-group">
12
13 <label i18n for="reportPredefinedReasons">What is the issue?</label>
14
15 <div class="ml-2 mt-2 d-flex flex-column">
16 <ng-container formGroupName="predefinedReasons">
17
18 <div class="form-group" *ngFor="let reason of predefinedReasons">
19 <my-peertube-checkbox [inputName]="reason.id" [formControlName]="reason.id" [labelText]="reason.label">
20 <ng-template *ngIf="reason.help" ptTemplate="help">
21 <div [innerHTML]="reason.help"></div>
22 </ng-template>
23
24 <ng-container *ngIf="reason.description" ngProjectAs="description">
25 <div [innerHTML]="reason.description"></div>
26 </ng-container>
27 </my-peertube-checkbox>
28 </div>
29
30 </ng-container>
31 </div>
32
33 </div>
34
35 <div class="col-7">
36 <div i18n class="information">
37 Your report will be sent to moderators of {{ currentHost }}<ng-container *ngIf="isRemote()"> and will be forwarded to the comment origin ({{ originHost }}) too</ng-container>.
38 </div>
39
40 <div class="form-group">
41 <textarea
42 i18n-placeholder placeholder="Please describe the issue..." formControlName="reason" ngbAutofocus
43 [ngClass]="{ 'input-error': formErrors['reason'] }" class="form-control"
44 ></textarea>
45 <div *ngIf="formErrors.reason" class="form-error">
46 {{ formErrors.reason }}
47 </div>
48 </div>
49 </div>
50 </div>
51
52 <div class="form-group inputs">
53 <input
54 type="button" role="button" i18n-value value="Cancel" class="action-button action-button-cancel"
55 (click)="hide()" (key.enter)="hide()"
56 >
57 <input type="submit" i18n-value value="Submit" class="action-button-submit" [disabled]="!form.valid">
58 </div>
59
60 </form>
61 </div>
62</ng-template>
diff --git a/client/src/app/shared/shared-moderation/report-modals/report.component.scss b/client/src/app/shared/shared-moderation/report-modals/report.component.scss
new file mode 100644
index 000000000..b2606cbd8
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/report-modals/report.component.scss
@@ -0,0 +1,27 @@
1@import 'variables';
2@import 'mixins';
3
4.information {
5 margin-bottom: 20px;
6}
7
8textarea {
9 @include peertube-textarea(100%, 100px);
10}
11
12.start-at,
13.stop-at {
14 width: 300px;
15 display: flex;
16 align-items: center;
17
18 my-timestamp-input {
19 margin-left: 10px;
20 }
21}
22
23.screenratio {
24 @include large-screen-ratio($selector: 'div, ::ng-deep iframe') {
25 left: 0;
26 };
27}
diff --git a/client/src/app/shared/shared-moderation/report-modals/video-report.component.html b/client/src/app/shared/shared-moderation/report-modals/video-report.component.html
new file mode 100644
index 000000000..4947088d1
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/report-modals/video-report.component.html
@@ -0,0 +1,100 @@
1<ng-template #modal>
2 <div class="modal-header">
3 <h4 i18n class="modal-title">Report video "{{ video.name }}"</h4>
4 <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
5 </div>
6
7 <div class="modal-body">
8 <form novalidate [formGroup]="form" (ngSubmit)="report()">
9
10 <div class="row">
11 <div class="col-5 form-group">
12
13 <label i18n for="reportPredefinedReasons">What is the issue?</label>
14
15 <div class="ml-2 mt-2 d-flex flex-column">
16 <ng-container formGroupName="predefinedReasons">
17
18 <div class="form-group" *ngFor="let reason of predefinedReasons">
19 <my-peertube-checkbox [inputName]="reason.id" [formControlName]="reason.id" [labelText]="reason.label">
20 <ng-template *ngIf="reason.help" ptTemplate="help">
21 <div [innerHTML]="reason.help"></div>
22 </ng-template>
23
24 <ng-container *ngIf="reason.description" ngProjectAs="description">
25 <div [innerHTML]="reason.description"></div>
26 </ng-container>
27 </my-peertube-checkbox>
28 </div>
29
30 </ng-container>
31 </div>
32
33 </div>
34
35 <div class="col-7">
36 <div class="row justify-content-center">
37 <div class="col-12 col-lg-9 mb-2">
38 <div class="screenratio">
39 <div [innerHTML]="embedHtml"></div>
40 </div>
41 </div>
42 </div>
43
44 <div class="mb-1 start-at" formGroupName="timestamp">
45 <my-peertube-checkbox
46 formControlName="hasStart"
47 i18n-labelText labelText="Start at"
48 ></my-peertube-checkbox>
49
50 <my-timestamp-input
51 [timestamp]="timestamp.startAt"
52 [maxTimestamp]="video.duration"
53 formControlName="startAt"
54 inputName="startAt"
55 >
56 </my-timestamp-input>
57 </div>
58
59 <div class="mb-3 stop-at" formGroupName="timestamp" *ngIf="timestamp.hasStart">
60 <my-peertube-checkbox
61 formControlName="hasEnd"
62 i18n-labelText labelText="Stop at"
63 ></my-peertube-checkbox>
64
65 <my-timestamp-input
66 [timestamp]="timestamp.endAt"
67 [maxTimestamp]="video.duration"
68 formControlName="endAt"
69 inputName="endAt"
70 >
71 </my-timestamp-input>
72 </div>
73
74 <div i18n class="information">
75 Your report will be sent to moderators of {{ currentHost }}<ng-container *ngIf="isRemote()"> and will be forwarded to the video origin ({{ originHost }}) too</ng-container>.
76 </div>
77
78 <div class="form-group">
79 <textarea
80 i18n-placeholder placeholder="Please describe the issue..." formControlName="reason" ngbAutofocus
81 [ngClass]="{ 'input-error': formErrors['reason'] }" class="form-control"
82 ></textarea>
83 <div *ngIf="formErrors.reason" class="form-error">
84 {{ formErrors.reason }}
85 </div>
86 </div>
87 </div>
88 </div>
89
90 <div class="form-group inputs">
91 <input
92 type="button" role="button" i18n-value value="Cancel" class="action-button action-button-cancel"
93 (click)="hide()" (key.enter)="hide()"
94 >
95 <input type="submit" i18n-value value="Submit" class="action-button-submit" [disabled]="!form.valid">
96 </div>
97
98 </form>
99 </div>
100</ng-template>
diff --git a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts
new file mode 100644
index 000000000..7d53ea3c9
--- /dev/null
+++ b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts
@@ -0,0 +1,122 @@
1import { mapValues, pickBy } from 'lodash-es'
2import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils'
3import { Component, Input, OnInit, ViewChild } from '@angular/core'
4import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
5import { Notifier } from '@app/core'
6import { AbuseValidatorsService, FormReactive, FormValidatorService } from '@app/shared/shared-forms'
7import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
8import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
9import { I18n } from '@ngx-translate/i18n-polyfill'
10import { abusePredefinedReasonsMap, AbusePredefinedReasonsString } from '@shared/models'
11import { Video } from '../../shared-main'
12import { AbuseService } from '../abuse.service'
13
14@Component({
15 selector: 'my-video-report',
16 templateUrl: './video-report.component.html',
17 styleUrls: [ './report.component.scss' ]
18})
19export class VideoReportComponent extends FormReactive implements OnInit {
20 @Input() video: Video = null
21
22 @ViewChild('modal', { static: true }) modal: NgbModal
23
24 error: string = null
25 predefinedReasons: { id: AbusePredefinedReasonsString, label: string, description?: string, help?: string }[] = []
26 embedHtml: SafeHtml
27
28 private openedModal: NgbModalRef
29
30 constructor (
31 protected formValidatorService: FormValidatorService,
32 private modalService: NgbModal,
33 private abuseValidatorsService: AbuseValidatorsService,
34 private abuseService: AbuseService,
35 private notifier: Notifier,
36 private sanitizer: DomSanitizer,
37 private i18n: I18n
38 ) {
39 super()
40 }
41
42 get currentHost () {
43 return window.location.host
44 }
45
46 get originHost () {
47 if (this.isRemote()) {
48 return this.video.account.host
49 }
50
51 return ''
52 }
53
54 get timestamp () {
55 return this.form.get('timestamp').value
56 }
57
58 getVideoEmbed () {
59 return this.sanitizer.bypassSecurityTrustHtml(
60 buildVideoEmbed(
61 buildVideoLink({
62 baseUrl: this.video.embedUrl,
63 title: false,
64 warningTitle: false
65 })
66 )
67 )
68 }
69
70 ngOnInit () {
71 this.buildForm({
72 reason: this.abuseValidatorsService.ABUSE_REASON,
73 predefinedReasons: mapValues(abusePredefinedReasonsMap, r => null),
74 timestamp: {
75 hasStart: null,
76 startAt: null,
77 hasEnd: null,
78 endAt: null
79 }
80 })
81
82 this.predefinedReasons = this.abuseService.getPrefefinedReasons('video')
83
84 this.embedHtml = this.getVideoEmbed()
85 }
86
87 show () {
88 this.openedModal = this.modalService.open(this.modal, { centered: true, keyboard: false, size: 'lg' })
89 }
90
91 hide () {
92 this.openedModal.close()
93 this.openedModal = null
94 }
95
96 report () {
97 const reason = this.form.get('reason').value
98 const predefinedReasons = Object.keys(pickBy(this.form.get('predefinedReasons').value)) as AbusePredefinedReasonsString[]
99 const { hasStart, startAt, hasEnd, endAt } = this.form.get('timestamp').value
100
101 this.abuseService.reportVideo({
102 reason,
103 predefinedReasons,
104 video: {
105 id: this.video.id,
106 startAt: hasStart && startAt ? startAt : undefined,
107 endAt: hasEnd && endAt ? endAt : undefined
108 }
109 }).subscribe(
110 () => {
111 this.notifier.success(this.i18n('Video reported.'))
112 this.hide()
113 },
114
115 err => this.notifier.error(err.message)
116 )
117 }
118
119 isRemote () {
120 return !this.video.isLocal
121 }
122}