aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/+admin
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/+admin')
-rw-r--r--client/src/app/+admin/moderation/abuse-list/abuse-list.component.html8
-rw-r--r--client/src/app/+admin/moderation/abuse-list/abuse-list.component.scss9
-rw-r--r--client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts50
-rw-r--r--client/src/app/+admin/moderation/abuse-list/moderation-comment-modal.component.ts6
4 files changed, 55 insertions, 18 deletions
diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html
index 48b31b99c..9fae5667f 100644
--- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html
+++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.html
@@ -46,6 +46,7 @@
46 <th i18n>Video/Comment/Account</th> 46 <th i18n>Video/Comment/Account</th>
47 <th style="width: 150px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th> 47 <th style="width: 150px;" i18n pSortableColumn="createdAt">Created <p-sortIcon field="createdAt"></p-sortIcon></th>
48 <th i18n pSortableColumn="state" style="width: 80px;">State <p-sortIcon field="state"></p-sortIcon></th> 48 <th i18n pSortableColumn="state" style="width: 80px;">State <p-sortIcon field="state"></p-sortIcon></th>
49 <th i18n style="width: 80px;">Messages</th>
49 <th style="width: 150px;"></th> 50 <th style="width: 150px;"></th>
50 </tr> 51 </tr>
51 </ng-template> 52 </ng-template>
@@ -157,6 +158,12 @@
157 <span *ngIf="abuse.moderationComment" container="body" placement="left auto" [ngbTooltip]="abuse.moderationComment" class="glyphicon glyphicon-comment"></span> 158 <span *ngIf="abuse.moderationComment" container="body" placement="left auto" [ngbTooltip]="abuse.moderationComment" class="glyphicon glyphicon-comment"></span>
158 </td> 159 </td>
159 160
161 <td class="c-hand abuse-messages" (click)="openAbuseMessagesModal(abuse)">
162 {{ abuse.countMessages }}
163
164 <my-global-icon iconName="message-circle"></my-global-icon>
165 </td>
166
160 <td class="action-cell"> 167 <td class="action-cell">
161 <my-action-dropdown 168 <my-action-dropdown
162 [ngClass]="{ 'show': expanded }" placement="bottom-right top-right left auto" container="body" 169 [ngClass]="{ 'show': expanded }" placement="bottom-right top-right left auto" container="body"
@@ -187,3 +194,4 @@
187</p-table> 194</p-table>
188 195
189<my-moderation-comment-modal #moderationCommentModal (commentUpdated)="onModerationCommentUpdated()"></my-moderation-comment-modal> 196<my-moderation-comment-modal #moderationCommentModal (commentUpdated)="onModerationCommentUpdated()"></my-moderation-comment-modal>
197<my-abuse-message-modal #abuseMessagesModal (countMessagesUpdated)="onCountMessagesUpdated($event)"></my-abuse-message-modal>
diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.scss b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.scss
index c22f98c47..48536e3c2 100644
--- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.scss
+++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.scss
@@ -21,3 +21,12 @@
21 margin-left: 0; 21 margin-left: 0;
22 } 22 }
23} 23}
24
25.abuse-messages {
26 my-global-icon {
27 width: 22px;
28 margin-left: 3px;
29 position: relative;
30 top: -2px;
31 }
32}
diff --git a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts
index 74c5fe2b3..86121fe58 100644
--- a/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts
+++ b/client/src/app/+admin/moderation/abuse-list/abuse-list.component.ts
@@ -8,17 +8,17 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser'
8import { ActivatedRoute, Params, Router } from '@angular/router' 8import { ActivatedRoute, Params, Router } from '@angular/router'
9import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core' 9import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core'
10import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main' 10import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main'
11import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation' 11import { AbuseService, BlocklistService, VideoBlockService, AbuseMessageModalComponent } from '@app/shared/shared-moderation'
12import { VideoCommentService } from '@app/shared/shared-video-comment' 12import { VideoCommentService } from '@app/shared/shared-video-comment'
13import { I18n } from '@ngx-translate/i18n-polyfill' 13import { I18n } from '@ngx-translate/i18n-polyfill'
14import { Abuse, AbuseState } from '@shared/models' 14import { AdminAbuse, AbuseState } from '@shared/models'
15import { ModerationCommentModalComponent } from './moderation-comment-modal.component' 15import { ModerationCommentModalComponent } from './moderation-comment-modal.component'
16 16
17const logger = debug('peertube:moderation:AbuseListComponent') 17const logger = debug('peertube:moderation:AbuseListComponent')
18 18
19// Don't use an abuse model because we need external services to compute some properties 19// Don't use an abuse model because we need external services to compute some properties
20// And this model is only used in this component 20// And this model is only used in this component
21export type ProcessedAbuse = Abuse & { 21export type ProcessedAbuse = AdminAbuse & {
22 moderationCommentHtml?: string, 22 moderationCommentHtml?: string,
23 reasonHtml?: string 23 reasonHtml?: string
24 embedHtml?: SafeHtml 24 embedHtml?: SafeHtml
@@ -31,8 +31,8 @@ export type ProcessedAbuse = Abuse & {
31 truncatedCommentHtml?: string 31 truncatedCommentHtml?: string
32 commentHtml?: string 32 commentHtml?: string
33 33
34 video: Abuse['video'] & { 34 video: AdminAbuse['video'] & {
35 channel: Abuse['video']['channel'] & { 35 channel: AdminAbuse['video']['channel'] & {
36 ownerAccount: Account 36 ownerAccount: Account
37 } 37 }
38 } 38 }
@@ -45,6 +45,7 @@ export type ProcessedAbuse = Abuse & {
45}) 45})
46export class AbuseListComponent extends RestTable implements OnInit, AfterViewInit { 46export class AbuseListComponent extends RestTable implements OnInit, AfterViewInit {
47 @ViewChild('moderationCommentModal', { static: true }) moderationCommentModal: ModerationCommentModalComponent 47 @ViewChild('moderationCommentModal', { static: true }) moderationCommentModal: ModerationCommentModalComponent
48 @ViewChild('abuseMessagesModal', { static: true }) abuseMessagesModal: AbuseMessageModalComponent
48 49
49 abuses: ProcessedAbuse[] = [] 50 abuses: ProcessedAbuse[] = []
50 totalRecords = 0 51 totalRecords = 0
@@ -104,7 +105,7 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
104 return 'AbuseListComponent' 105 return 'AbuseListComponent'
105 } 106 }
106 107
107 openModerationCommentModal (abuse: Abuse) { 108 openModerationCommentModal (abuse: AdminAbuse) {
108 this.moderationCommentModal.openModal(abuse) 109 this.moderationCommentModal.openModal(abuse)
109 } 110 }
110 111
@@ -132,19 +133,19 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
132 } 133 }
133 /* END Table filter functions */ 134 /* END Table filter functions */
134 135
135 isAbuseAccepted (abuse: Abuse) { 136 isAbuseAccepted (abuse: AdminAbuse) {
136 return abuse.state.id === AbuseState.ACCEPTED 137 return abuse.state.id === AbuseState.ACCEPTED
137 } 138 }
138 139
139 isAbuseRejected (abuse: Abuse) { 140 isAbuseRejected (abuse: AdminAbuse) {
140 return abuse.state.id === AbuseState.REJECTED 141 return abuse.state.id === AbuseState.REJECTED
141 } 142 }
142 143
143 getVideoUrl (abuse: Abuse) { 144 getVideoUrl (abuse: AdminAbuse) {
144 return Video.buildClientUrl(abuse.video.uuid) 145 return Video.buildClientUrl(abuse.video.uuid)
145 } 146 }
146 147
147 getCommentUrl (abuse: Abuse) { 148 getCommentUrl (abuse: AdminAbuse) {
148 return Video.buildClientUrl(abuse.comment.video.uuid) + ';threadId=' + abuse.comment.threadId 149 return Video.buildClientUrl(abuse.comment.video.uuid) + ';threadId=' + abuse.comment.threadId
149 } 150 }
150 151
@@ -152,7 +153,7 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
152 return '/accounts/' + abuse.flaggedAccount.nameWithHost 153 return '/accounts/' + abuse.flaggedAccount.nameWithHost
153 } 154 }
154 155
155 getVideoEmbed (abuse: Abuse) { 156 getVideoEmbed (abuse: AdminAbuse) {
156 return buildVideoEmbed( 157 return buildVideoEmbed(
157 buildVideoLink({ 158 buildVideoLink({
158 baseUrl: `${environment.embedUrl}/videos/embed/${abuse.video.uuid}`, 159 baseUrl: `${environment.embedUrl}/videos/embed/${abuse.video.uuid}`,
@@ -168,7 +169,7 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
168 ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL() 169 ($event.target as HTMLImageElement).src = Actor.GET_DEFAULT_AVATAR_URL()
169 } 170 }
170 171
171 async removeAbuse (abuse: Abuse) { 172 async removeAbuse (abuse: AdminAbuse) {
172 const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this abuse report?'), this.i18n('Delete')) 173 const res = await this.confirmService.confirm(this.i18n('Do you really want to delete this abuse report?'), this.i18n('Delete'))
173 if (res === false) return 174 if (res === false) return
174 175
@@ -182,7 +183,7 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
182 ) 183 )
183 } 184 }
184 185
185 updateAbuseState (abuse: Abuse, state: AbuseState) { 186 updateAbuseState (abuse: AdminAbuse, state: AbuseState) {
186 this.abuseService.updateAbuse(abuse, { state }) 187 this.abuseService.updateAbuse(abuse, { state })
187 .subscribe( 188 .subscribe(
188 () => this.loadData(), 189 () => this.loadData(),
@@ -191,10 +192,25 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
191 ) 192 )
192 } 193 }
193 194
195 onCountMessagesUpdated (event: { abuseId: number, countMessages: number }) {
196 const abuse = this.abuses.find(a => a.id === event.abuseId)
197
198 if (!abuse) {
199 console.error('Cannot find abuse %d.', event.abuseId)
200 return
201 }
202
203 abuse.countMessages = event.countMessages
204 }
205
206 openAbuseMessagesModal (abuse: AdminAbuse) {
207 this.abuseMessagesModal.openModal(abuse)
208 }
209
194 protected loadData () { 210 protected loadData () {
195 logger('Load data.') 211 logger('Load data.')
196 212
197 return this.abuseService.getAbuses({ 213 return this.abuseService.getAdminAbuses({
198 pagination: this.pagination, 214 pagination: this.pagination,
199 sort: this.sort, 215 sort: this.sort,
200 search: this.search 216 search: this.search
@@ -257,7 +273,11 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
257 handler: abuse => this.removeAbuse(abuse) 273 handler: abuse => this.removeAbuse(abuse)
258 }, 274 },
259 { 275 {
260 label: this.i18n('Add note'), 276 label: this.i18n('Messages'),
277 handler: abuse => this.openAbuseMessagesModal(abuse)
278 },
279 {
280 label: this.i18n('Add internal note'),
261 handler: abuse => this.openModerationCommentModal(abuse), 281 handler: abuse => this.openModerationCommentModal(abuse),
262 isDisplayed: abuse => !abuse.moderationComment 282 isDisplayed: abuse => !abuse.moderationComment
263 }, 283 },
diff --git a/client/src/app/+admin/moderation/abuse-list/moderation-comment-modal.component.ts b/client/src/app/+admin/moderation/abuse-list/moderation-comment-modal.component.ts
index 23738f9cd..ecb7966bf 100644
--- a/client/src/app/+admin/moderation/abuse-list/moderation-comment-modal.component.ts
+++ b/client/src/app/+admin/moderation/abuse-list/moderation-comment-modal.component.ts
@@ -5,7 +5,7 @@ import { AbuseService } from '@app/shared/shared-moderation'
5import { NgbModal } from '@ng-bootstrap/ng-bootstrap' 5import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
6import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref' 6import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
7import { I18n } from '@ngx-translate/i18n-polyfill' 7import { I18n } from '@ngx-translate/i18n-polyfill'
8import { Abuse } from '@shared/models' 8import { AdminAbuse } from '@shared/models'
9 9
10@Component({ 10@Component({
11 selector: 'my-moderation-comment-modal', 11 selector: 'my-moderation-comment-modal',
@@ -16,7 +16,7 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI
16 @ViewChild('modal', { static: true }) modal: NgbModal 16 @ViewChild('modal', { static: true }) modal: NgbModal
17 @Output() commentUpdated = new EventEmitter<string>() 17 @Output() commentUpdated = new EventEmitter<string>()
18 18
19 private abuseToComment: Abuse 19 private abuseToComment: AdminAbuse
20 private openedModal: NgbModalRef 20 private openedModal: NgbModalRef
21 21
22 constructor ( 22 constructor (
@@ -36,7 +36,7 @@ export class ModerationCommentModalComponent extends FormReactive implements OnI
36 }) 36 })
37 } 37 }
38 38
39 openModal (abuseToComment: Abuse) { 39 openModal (abuseToComment: AdminAbuse) {
40 this.abuseToComment = abuseToComment 40 this.abuseToComment = abuseToComment
41 this.openedModal = this.modalService.open(this.modal, { centered: true }) 41 this.openedModal = this.modalService.open(this.modal, { centered: true })
42 42