Add ability to report account
This commit is contained in:
parent
8ca56654a1
commit
cfde28bac3
|
@ -22,6 +22,7 @@
|
|||
<span *ngIf="account.mutedServerByInstance" class="badge badge-danger" i18n>Instance muted by your instance</span>
|
||||
|
||||
<my-user-moderation-dropdown
|
||||
[prependActions]="prependModerationActions"
|
||||
buttonSize="small" [account]="account" [user]="accountUser" placement="bottom-left auto"
|
||||
(userChanged)="onUserChanged()" (userDeleted)="onUserDeleted()"
|
||||
></my-user-moderation-dropdown>
|
||||
|
@ -50,3 +51,7 @@
|
|||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="prependModerationActions">
|
||||
<my-account-report #accountReportModal [account]="account"></my-account-report>
|
||||
</ng-container>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Subscription } from 'rxjs'
|
||||
import { catchError, distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators'
|
||||
import { Component, OnDestroy, OnInit } from '@angular/core'
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { AuthService, Notifier, RedirectService, RestExtractor, ScreenService, UserService } from '@app/core'
|
||||
import { Account, AccountService, ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
||||
import { Account, AccountService, DropdownAction, ListOverflowItem, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
||||
import { AccountReportComponent } from '@app/shared/shared-moderation'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { User, UserRight } from '@shared/models'
|
||||
|
||||
|
@ -12,6 +13,8 @@ import { User, UserRight } from '@shared/models'
|
|||
styleUrls: [ './accounts.component.scss' ]
|
||||
})
|
||||
export class AccountsComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('accountReportModal') accountReportModal: AccountReportComponent
|
||||
|
||||
account: Account
|
||||
accountUser: User
|
||||
videoChannels: VideoChannel[] = []
|
||||
|
@ -20,6 +23,8 @@ export class AccountsComponent implements OnInit, OnDestroy {
|
|||
isAccountManageable = false
|
||||
accountFollowerTitle = ''
|
||||
|
||||
prependModerationActions: DropdownAction<any>[]
|
||||
|
||||
private routeSub: Subscription
|
||||
|
||||
constructor (
|
||||
|
@ -42,24 +47,7 @@ export class AccountsComponent implements OnInit, OnDestroy {
|
|||
map(params => params[ 'accountId' ]),
|
||||
distinctUntilChanged(),
|
||||
switchMap(accountId => this.accountService.getAccount(accountId)),
|
||||
tap(account => {
|
||||
this.account = account
|
||||
|
||||
if (this.authService.isLoggedIn()) {
|
||||
this.authService.userInformationLoaded.subscribe(
|
||||
() => {
|
||||
this.isAccountManageable = this.account.userId && this.account.userId === this.authService.getUser().id
|
||||
|
||||
this.accountFollowerTitle = this.i18n(
|
||||
'{{followers}} direct account followers',
|
||||
{ followers: this.subscribersDisplayFor(account.followersCount) }
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
this.getUserIfNeeded(account)
|
||||
}),
|
||||
tap(account => this.onAccount(account)),
|
||||
switchMap(account => this.videoChannelService.listAccountVideoChannels(account)),
|
||||
catchError(err => this.restExtractor.redirectTo404IfNotFound(err, [ 400, 404 ]))
|
||||
)
|
||||
|
@ -107,6 +95,41 @@ export class AccountsComponent implements OnInit, OnDestroy {
|
|||
return this.i18n('{count, plural, =1 {1 subscriber} other {{{count}} subscribers}}', { count })
|
||||
}
|
||||
|
||||
private onAccount (account: Account) {
|
||||
this.prependModerationActions = undefined
|
||||
|
||||
this.account = account
|
||||
|
||||
if (this.authService.isLoggedIn()) {
|
||||
this.authService.userInformationLoaded.subscribe(
|
||||
() => {
|
||||
this.isAccountManageable = this.account.userId && this.account.userId === this.authService.getUser().id
|
||||
|
||||
this.accountFollowerTitle = this.i18n(
|
||||
'{{followers}} direct account followers',
|
||||
{ followers: this.subscribersDisplayFor(account.followersCount) }
|
||||
)
|
||||
|
||||
// It's not our account, we can report it
|
||||
if (!this.isAccountManageable) {
|
||||
this.prependModerationActions = [
|
||||
{
|
||||
label: this.i18n('Report account'),
|
||||
handler: () => this.showReportModal()
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
this.getUserIfNeeded(account)
|
||||
}
|
||||
|
||||
private showReportModal () {
|
||||
this.accountReportModal.show()
|
||||
}
|
||||
|
||||
private getUserIfNeeded (account: Account) {
|
||||
if (!account.userId || !this.authService.isLoggedIn()) return
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<p-table
|
||||
[value]="abuses" [lazy]="true" [paginator]="totalRecords > 0" [totalRecords]="totalRecords" [rows]="rowsPerPage" [rowsPerPageOptions]="rowsPerPageOptions"
|
||||
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true"
|
||||
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)" dataKey="id" [resizableColumns]="true" [lazyLoadOnInit]="false"
|
||||
[showCurrentPageReport]="true" i18n-currentPageReportTemplate
|
||||
currentPageReportTemplate="Showing {{'{first}'}} to {{'{last}'}} of {{'{totalRecords}'}} reports"
|
||||
(onPage)="onPage($event)" [expandedRowKeys]="expandedRows"
|
||||
|
@ -128,6 +128,22 @@
|
|||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!abuse.comment && !abuse.video">
|
||||
<td *ngIf="abuse.flaggedAccount">
|
||||
<a [href]="getAccountUrl(abuse)" class="table-account-link" target="_blank" rel="noopener noreferrer">
|
||||
<span>{{ abuse.flaggedAccount.displayName }}</span>
|
||||
|
||||
<span class="account-flagged-handle">{{ abuse.flaggedAccount.nameWithHostForced }}</span>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
<td i18n *ngIf="!abuse.flaggedAccount">
|
||||
Account deleted
|
||||
</td>
|
||||
|
||||
</ng-container>
|
||||
|
||||
|
||||
<td class="c-hand" [pRowToggler]="abuse">{{ abuse.createdAt | date: 'short' }}</td>
|
||||
|
||||
<td class="c-hand abuse-states" [pRowToggler]="abuse">
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import * as debug from 'debug'
|
||||
import truncate from 'lodash-es/truncate'
|
||||
import { SortMeta } from 'primeng/api'
|
||||
import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils'
|
||||
import { environment } from 'src/environments/environment'
|
||||
|
@ -7,11 +9,15 @@ import { ActivatedRoute, Params, Router } from '@angular/router'
|
|||
import { ConfirmService, MarkdownService, Notifier, RestPagination, RestTable } from '@app/core'
|
||||
import { Account, Actor, DropdownAction, Video, VideoService } from '@app/shared/shared-main'
|
||||
import { AbuseService, BlocklistService, VideoBlockService } from '@app/shared/shared-moderation'
|
||||
import { VideoCommentService } from '@app/shared/shared-video-comment'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { Abuse, AbuseState } from '@shared/models'
|
||||
import { ModerationCommentModalComponent } from './moderation-comment-modal.component'
|
||||
import truncate from 'lodash-es/truncate'
|
||||
|
||||
const logger = debug('peertube:moderation:AbuseListComponent')
|
||||
|
||||
// Don't use an abuse model because we need external services to compute some properties
|
||||
// And this model is only used in this component
|
||||
export type ProcessedAbuse = Abuse & {
|
||||
moderationCommentHtml?: string,
|
||||
reasonHtml?: string
|
||||
|
@ -45,12 +51,13 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
|
|||
sort: SortMeta = { field: 'createdAt', order: 1 }
|
||||
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
|
||||
|
||||
abuseActions: DropdownAction<Abuse>[][] = []
|
||||
abuseActions: DropdownAction<ProcessedAbuse>[][] = []
|
||||
|
||||
constructor (
|
||||
private notifier: Notifier,
|
||||
private abuseService: AbuseService,
|
||||
private blocklistService: BlocklistService,
|
||||
private commentService: VideoCommentService,
|
||||
private videoService: VideoService,
|
||||
private videoBlocklistService: VideoBlockService,
|
||||
private confirmService: ConfirmService,
|
||||
|
@ -63,140 +70,15 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
|
|||
super()
|
||||
|
||||
this.abuseActions = [
|
||||
[
|
||||
{
|
||||
label: this.i18n('Internal actions'),
|
||||
isHeader: true
|
||||
},
|
||||
{
|
||||
label: this.i18n('Delete report'),
|
||||
handler: abuse => this.removeAbuse(abuse)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Add note'),
|
||||
handler: abuse => this.openModerationCommentModal(abuse),
|
||||
isDisplayed: abuse => !abuse.moderationComment
|
||||
},
|
||||
{
|
||||
label: this.i18n('Update note'),
|
||||
handler: abuse => this.openModerationCommentModal(abuse),
|
||||
isDisplayed: abuse => !!abuse.moderationComment
|
||||
},
|
||||
{
|
||||
label: this.i18n('Mark as accepted'),
|
||||
handler: abuse => this.updateAbuseState(abuse, AbuseState.ACCEPTED),
|
||||
isDisplayed: abuse => !this.isAbuseAccepted(abuse)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Mark as rejected'),
|
||||
handler: abuse => this.updateAbuseState(abuse, AbuseState.REJECTED),
|
||||
isDisplayed: abuse => !this.isAbuseRejected(abuse)
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
label: this.i18n('Actions for the video'),
|
||||
isHeader: true,
|
||||
isDisplayed: abuse => abuse.video && !abuse.video.deleted
|
||||
},
|
||||
{
|
||||
label: this.i18n('Block video'),
|
||||
isDisplayed: abuse => abuse.video && !abuse.video.deleted && !abuse.video.blacklisted,
|
||||
handler: abuse => {
|
||||
this.videoBlocklistService.blockVideo(abuse.video.id, undefined, true)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Video blocked.'))
|
||||
this.buildInternalActions(),
|
||||
|
||||
this.updateAbuseState(abuse, AbuseState.ACCEPTED)
|
||||
},
|
||||
this.buildFlaggedAccountActions(),
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: this.i18n('Unblock video'),
|
||||
isDisplayed: abuse => abuse.video && !abuse.video.deleted && abuse.video.blacklisted,
|
||||
handler: abuse => {
|
||||
this.videoBlocklistService.unblockVideo(abuse.video.id)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Video unblocked.'))
|
||||
this.buildCommentActions(),
|
||||
|
||||
this.updateAbuseState(abuse, AbuseState.ACCEPTED)
|
||||
},
|
||||
this.buildVideoActions(),
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: this.i18n('Delete video'),
|
||||
isDisplayed: abuse => abuse.video && !abuse.video.deleted,
|
||||
handler: async abuse => {
|
||||
const res = await this.confirmService.confirm(
|
||||
this.i18n('Do you really want to delete this video?'),
|
||||
this.i18n('Delete')
|
||||
)
|
||||
if (res === false) return
|
||||
|
||||
this.videoService.removeVideo(abuse.video.id)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Video deleted.'))
|
||||
|
||||
this.updateAbuseState(abuse, AbuseState.ACCEPTED)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
label: this.i18n('Actions for the reporter'),
|
||||
isHeader: true,
|
||||
isDisplayed: abuse => !!abuse.reporterAccount
|
||||
},
|
||||
{
|
||||
label: this.i18n('Mute reporter'),
|
||||
isDisplayed: abuse => !!abuse.reporterAccount,
|
||||
handler: async abuse => {
|
||||
const account = abuse.reporterAccount as Account
|
||||
|
||||
this.blocklistService.blockAccountByInstance(account)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(
|
||||
this.i18n('Account {{nameWithHost}} muted by the instance.', { nameWithHost: account.nameWithHost })
|
||||
)
|
||||
|
||||
account.mutedByInstance = true
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: this.i18n('Mute server'),
|
||||
isDisplayed: abuse => abuse.reporterAccount && !abuse.reporterAccount.userId,
|
||||
handler: async abuse => {
|
||||
this.blocklistService.blockServerByInstance(abuse.reporterAccount.host)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(
|
||||
this.i18n('Server {{host}} muted by the instance.', { host: abuse.reporterAccount.host })
|
||||
)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
this.buildAccountActions()
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -207,6 +89,8 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
|
|||
.subscribe(params => {
|
||||
this.search = params.search || ''
|
||||
|
||||
logger('On URL change (search: %s).', this.search)
|
||||
|
||||
this.setTableFilter(this.search)
|
||||
this.loadData()
|
||||
})
|
||||
|
@ -264,6 +148,10 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
|
|||
return Video.buildClientUrl(abuse.comment.video.uuid) + ';threadId=' + abuse.comment.threadId
|
||||
}
|
||||
|
||||
getAccountUrl (abuse: ProcessedAbuse) {
|
||||
return '/accounts/' + abuse.flaggedAccount.nameWithHost
|
||||
}
|
||||
|
||||
getVideoEmbed (abuse: Abuse) {
|
||||
return buildVideoEmbed(
|
||||
buildVideoLink({
|
||||
|
@ -304,6 +192,8 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
|
|||
}
|
||||
|
||||
protected loadData () {
|
||||
logger('Load data.')
|
||||
|
||||
return this.abuseService.getAbuses({
|
||||
pagination: this.pagination,
|
||||
sort: this.sort,
|
||||
|
@ -356,6 +246,208 @@ export class AbuseListComponent extends RestTable implements OnInit, AfterViewIn
|
|||
)
|
||||
}
|
||||
|
||||
private buildInternalActions (): DropdownAction<ProcessedAbuse>[] {
|
||||
return [
|
||||
{
|
||||
label: this.i18n('Internal actions'),
|
||||
isHeader: true
|
||||
},
|
||||
{
|
||||
label: this.i18n('Delete report'),
|
||||
handler: abuse => this.removeAbuse(abuse)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Add note'),
|
||||
handler: abuse => this.openModerationCommentModal(abuse),
|
||||
isDisplayed: abuse => !abuse.moderationComment
|
||||
},
|
||||
{
|
||||
label: this.i18n('Update note'),
|
||||
handler: abuse => this.openModerationCommentModal(abuse),
|
||||
isDisplayed: abuse => !!abuse.moderationComment
|
||||
},
|
||||
{
|
||||
label: this.i18n('Mark as accepted'),
|
||||
handler: abuse => this.updateAbuseState(abuse, AbuseState.ACCEPTED),
|
||||
isDisplayed: abuse => !this.isAbuseAccepted(abuse)
|
||||
},
|
||||
{
|
||||
label: this.i18n('Mark as rejected'),
|
||||
handler: abuse => this.updateAbuseState(abuse, AbuseState.REJECTED),
|
||||
isDisplayed: abuse => !this.isAbuseRejected(abuse)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
private buildFlaggedAccountActions (): DropdownAction<ProcessedAbuse>[] {
|
||||
return [
|
||||
{
|
||||
label: this.i18n('Actions for the flagged account'),
|
||||
isHeader: true,
|
||||
isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video
|
||||
},
|
||||
|
||||
{
|
||||
label: this.i18n('Mute account'),
|
||||
isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video,
|
||||
handler: abuse => this.muteAccountHelper(abuse.flaggedAccount)
|
||||
},
|
||||
|
||||
{
|
||||
label: this.i18n('Mute server account'),
|
||||
isDisplayed: abuse => abuse.flaggedAccount && !abuse.comment && !abuse.video,
|
||||
handler: abuse => this.muteServerHelper(abuse.flaggedAccount.host)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
private buildAccountActions (): DropdownAction<ProcessedAbuse>[] {
|
||||
return [
|
||||
{
|
||||
label: this.i18n('Actions for the reporter'),
|
||||
isHeader: true,
|
||||
isDisplayed: abuse => !!abuse.reporterAccount
|
||||
},
|
||||
|
||||
{
|
||||
label: this.i18n('Mute reporter'),
|
||||
isDisplayed: abuse => !!abuse.reporterAccount,
|
||||
handler: abuse => this.muteAccountHelper(abuse.reporterAccount)
|
||||
},
|
||||
|
||||
{
|
||||
label: this.i18n('Mute server'),
|
||||
isDisplayed: abuse => abuse.reporterAccount && !abuse.reporterAccount.userId,
|
||||
handler: abuse => this.muteServerHelper(abuse.reporterAccount.host)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
private buildVideoActions (): DropdownAction<ProcessedAbuse>[] {
|
||||
return [
|
||||
{
|
||||
label: this.i18n('Actions for the video'),
|
||||
isHeader: true,
|
||||
isDisplayed: abuse => abuse.video && !abuse.video.deleted
|
||||
},
|
||||
{
|
||||
label: this.i18n('Block video'),
|
||||
isDisplayed: abuse => abuse.video && !abuse.video.deleted && !abuse.video.blacklisted,
|
||||
handler: abuse => {
|
||||
this.videoBlocklistService.blockVideo(abuse.video.id, undefined, true)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Video blocked.'))
|
||||
|
||||
this.updateAbuseState(abuse, AbuseState.ACCEPTED)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: this.i18n('Unblock video'),
|
||||
isDisplayed: abuse => abuse.video && !abuse.video.deleted && abuse.video.blacklisted,
|
||||
handler: abuse => {
|
||||
this.videoBlocklistService.unblockVideo(abuse.video.id)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Video unblocked.'))
|
||||
|
||||
this.updateAbuseState(abuse, AbuseState.ACCEPTED)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
label: this.i18n('Delete video'),
|
||||
isDisplayed: abuse => abuse.video && !abuse.video.deleted,
|
||||
handler: async abuse => {
|
||||
const res = await this.confirmService.confirm(
|
||||
this.i18n('Do you really want to delete this video?'),
|
||||
this.i18n('Delete')
|
||||
)
|
||||
if (res === false) return
|
||||
|
||||
this.videoService.removeVideo(abuse.video.id)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Video deleted.'))
|
||||
|
||||
this.updateAbuseState(abuse, AbuseState.ACCEPTED)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
private buildCommentActions (): DropdownAction<ProcessedAbuse>[] {
|
||||
return [
|
||||
{
|
||||
label: this.i18n('Actions for the comment'),
|
||||
isHeader: true,
|
||||
isDisplayed: abuse => abuse.comment && !abuse.comment.deleted
|
||||
},
|
||||
|
||||
{
|
||||
label: this.i18n('Delete comment'),
|
||||
isDisplayed: abuse => abuse.comment && !abuse.comment.deleted,
|
||||
handler: async abuse => {
|
||||
const res = await this.confirmService.confirm(
|
||||
this.i18n('Do you really want to delete this comment?'),
|
||||
this.i18n('Delete')
|
||||
)
|
||||
if (res === false) return
|
||||
|
||||
this.commentService.deleteVideoComment(abuse.comment.video.id, abuse.comment.id)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Comment deleted.'))
|
||||
|
||||
this.updateAbuseState(abuse, AbuseState.ACCEPTED)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
private muteAccountHelper (account: Account) {
|
||||
this.blocklistService.blockAccountByInstance(account)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(
|
||||
this.i18n('Account {{nameWithHost}} muted by the instance.', { nameWithHost: account.nameWithHost })
|
||||
)
|
||||
|
||||
account.mutedByInstance = true
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
|
||||
private muteServerHelper (host: string) {
|
||||
this.blocklistService.blockServerByInstance(host)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success(
|
||||
this.i18n('Server {{host}} muted by the instance.', { host: host })
|
||||
)
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
|
||||
private toHtml (text: string) {
|
||||
return this.markdownRenderer.textMarkdownToHTML(text)
|
||||
}
|
||||
|
|
|
@ -96,7 +96,8 @@ my-action-dropdown.show {
|
|||
top: 3px;
|
||||
}
|
||||
|
||||
.table-comment-link {
|
||||
.table-comment-link,
|
||||
.table-account-link {
|
||||
@include disable-outline;
|
||||
|
||||
color: var(--mainForegroundColor);
|
||||
|
@ -106,7 +107,13 @@ my-action-dropdown.show {
|
|||
}
|
||||
}
|
||||
|
||||
.comment-flagged-account {
|
||||
.table-account-link {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.comment-flagged-account,
|
||||
.account-flagged-handle {
|
||||
font-size: 11px;
|
||||
color: var(--greyForegroundColor);
|
||||
}
|
||||
|
|
|
@ -4,10 +4,9 @@ import { Router } from '@angular/router'
|
|||
import { Notifier, User } from '@app/core'
|
||||
import { FormReactive, FormValidatorService, VideoCommentValidatorsService } from '@app/shared/shared-forms'
|
||||
import { Video } from '@app/shared/shared-main'
|
||||
import { VideoComment, VideoCommentService } from '@app/shared/shared-video-comment'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { VideoCommentCreate } from '@shared/models'
|
||||
import { VideoComment } from './video-comment.model'
|
||||
import { VideoCommentService } from './video-comment.service'
|
||||
|
||||
@Component({
|
||||
selector: 'my-video-comment-add',
|
||||
|
|
|
@ -3,11 +3,10 @@ import { Component, EventEmitter, Input, OnChanges, OnInit, Output, ViewChild }
|
|||
import { MarkdownService, Notifier, UserService } from '@app/core'
|
||||
import { AuthService } from '@app/core/auth'
|
||||
import { Account, Actor, DropdownAction, Video } from '@app/shared/shared-main'
|
||||
import { CommentReportComponent } from '@app/shared/shared-moderation/comment-report.component'
|
||||
import { CommentReportComponent } from '@app/shared/shared-moderation/report-modals/comment-report.component'
|
||||
import { VideoComment, VideoCommentThreadTree } from '@app/shared/shared-video-comment'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { User, UserRight } from '@shared/models'
|
||||
import { VideoCommentThreadTree } from './video-comment-thread-tree.model'
|
||||
import { VideoComment } from './video-comment.model'
|
||||
|
||||
@Component({
|
||||
selector: 'my-video-comment',
|
||||
|
@ -136,7 +135,7 @@ export class VideoCommentComponent implements OnInit, OnChanges {
|
|||
this.comment.account = null
|
||||
}
|
||||
|
||||
if (this.isUserLoggedIn()) {
|
||||
if (this.isUserLoggedIn() && this.authService.getUser().account.id !== this.comment.account.id) {
|
||||
this.prependModerationActions = [
|
||||
{
|
||||
label: this.i18n('Report comment'),
|
||||
|
|
|
@ -4,10 +4,8 @@ import { ActivatedRoute } from '@angular/router'
|
|||
import { AuthService, ComponentPagination, ConfirmService, hasMoreItems, Notifier, User } from '@app/core'
|
||||
import { HooksService } from '@app/core/plugins/hooks.service'
|
||||
import { Syndication, VideoDetails } from '@app/shared/shared-main'
|
||||
import { VideoComment, VideoCommentService, VideoCommentThreadTree } from '@app/shared/shared-video-comment'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { VideoCommentThreadTree } from './video-comment-thread-tree.model'
|
||||
import { VideoComment } from './video-comment.model'
|
||||
import { VideoCommentService } from './video-comment.service'
|
||||
|
||||
@Component({
|
||||
selector: 'my-video-comments',
|
||||
|
|
|
@ -5,16 +5,17 @@ import { SharedGlobalIconModule } from '@app/shared/shared-icons'
|
|||
import { SharedMainModule } from '@app/shared/shared-main'
|
||||
import { SharedModerationModule } from '@app/shared/shared-moderation'
|
||||
import { SharedUserSubscriptionModule } from '@app/shared/shared-user-subscription'
|
||||
import { SharedVideoCommentModule } from '@app/shared/shared-video-comment'
|
||||
import { SharedVideoMiniatureModule } from '@app/shared/shared-video-miniature'
|
||||
import { SharedVideoPlaylistModule } from '@app/shared/shared-video-playlist'
|
||||
import { RecommendationsModule } from './recommendations/recommendations.module'
|
||||
import { NgbTooltipModule } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { VideoCommentService } from '../../shared/shared-video-comment/video-comment.service'
|
||||
import { VideoCommentAddComponent } from './comment/video-comment-add.component'
|
||||
import { VideoCommentComponent } from './comment/video-comment.component'
|
||||
import { VideoCommentService } from './comment/video-comment.service'
|
||||
import { VideoCommentsComponent } from './comment/video-comments.component'
|
||||
import { VideoShareComponent } from './modal/video-share.component'
|
||||
import { VideoSupportComponent } from './modal/video-support.component'
|
||||
import { RecommendationsModule } from './recommendations/recommendations.module'
|
||||
import { TimestampRouteTransformerDirective } from './timestamp-route-transformer.directive'
|
||||
import { VideoDurationPipe } from './video-duration-formatter.pipe'
|
||||
import { VideoWatchPlaylistComponent } from './video-watch-playlist.component'
|
||||
|
@ -34,7 +35,8 @@ import { VideoWatchComponent } from './video-watch.component'
|
|||
SharedVideoPlaylistModule,
|
||||
SharedUserSubscriptionModule,
|
||||
SharedModerationModule,
|
||||
SharedGlobalIconModule
|
||||
SharedGlobalIconModule,
|
||||
SharedVideoCommentModule
|
||||
],
|
||||
|
||||
declarations: [
|
||||
|
|
|
@ -3,6 +3,9 @@ import { LazyLoadEvent, SortMeta } from 'primeng/api'
|
|||
import { RestPagination } from './rest-pagination'
|
||||
import { Subject } from 'rxjs'
|
||||
import { debounceTime, distinctUntilChanged } from 'rxjs/operators'
|
||||
import * as debug from 'debug'
|
||||
|
||||
const logger = debug('peertube:tables:RestTable')
|
||||
|
||||
export abstract class RestTable {
|
||||
|
||||
|
@ -15,7 +18,7 @@ export abstract class RestTable {
|
|||
rowsPerPage = this.rowsPerPageOptions[0]
|
||||
expandedRows = {}
|
||||
|
||||
private searchStream: Subject<string>
|
||||
protected searchStream: Subject<string>
|
||||
|
||||
abstract getIdentifier (): string
|
||||
|
||||
|
@ -37,6 +40,8 @@ export abstract class RestTable {
|
|||
}
|
||||
|
||||
loadLazy (event: LazyLoadEvent) {
|
||||
logger('Load lazy %o.', event)
|
||||
|
||||
this.sort = {
|
||||
order: event.sortOrder,
|
||||
field: event.sortField
|
||||
|
@ -65,6 +70,9 @@ export abstract class RestTable {
|
|||
)
|
||||
.subscribe(search => {
|
||||
this.search = search
|
||||
|
||||
logger('On search %s.', this.search)
|
||||
|
||||
this.loadData()
|
||||
})
|
||||
}
|
||||
|
@ -75,14 +83,18 @@ export abstract class RestTable {
|
|||
}
|
||||
|
||||
onPage (event: { first: number, rows: number }) {
|
||||
logger('On page %o.', event)
|
||||
|
||||
if (this.rowsPerPage !== event.rows) {
|
||||
this.rowsPerPage = event.rows
|
||||
this.pagination = {
|
||||
start: event.first,
|
||||
count: this.rowsPerPage
|
||||
}
|
||||
|
||||
this.loadData()
|
||||
}
|
||||
|
||||
this.expandedRows = {}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ export abstract class Actor implements ActorServer {
|
|||
|
||||
avatarUrl: string
|
||||
|
||||
isLocal: boolean
|
||||
|
||||
static GET_ACTOR_AVATAR_URL (actor: { avatar?: { url?: string, path: string } }) {
|
||||
if (actor?.avatar?.url) return actor.avatar.url
|
||||
|
||||
|
@ -52,6 +54,10 @@ export abstract class Actor implements ActorServer {
|
|||
|
||||
this.avatar = hash.avatar
|
||||
|
||||
const absoluteAPIUrl = getAbsoluteAPIUrl()
|
||||
const thisHost = new URL(absoluteAPIUrl).host
|
||||
this.isLocal = this.host.trim() === thisHost
|
||||
|
||||
this.updateComputedAttributes()
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,9 @@ export class UserNotification implements UserNotificationServer {
|
|||
threadId: number
|
||||
|
||||
video: {
|
||||
id: number
|
||||
uuid: string
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,13 +117,15 @@ export class UserNotification implements UserNotificationServer {
|
|||
case UserNotificationType.COMMENT_MENTION:
|
||||
if (!this.comment) break
|
||||
this.accountUrl = this.buildAccountUrl(this.comment.account)
|
||||
this.commentUrl = [ this.buildVideoUrl(this.comment.video), { threadId: this.comment.threadId } ]
|
||||
this.commentUrl = this.buildCommentUrl(this.comment)
|
||||
break
|
||||
|
||||
case UserNotificationType.NEW_ABUSE_FOR_MODERATORS:
|
||||
this.abuseUrl = '/admin/moderation/abuses/list'
|
||||
|
||||
if (this.abuse.video) this.videoUrl = this.buildVideoUrl(this.abuse.video)
|
||||
else if (this.abuse.comment) this.commentUrl = this.buildCommentUrl(this.abuse.comment)
|
||||
else if (this.abuse.account) this.accountUrl = this.buildAccountUrl(this.abuse.account)
|
||||
break
|
||||
|
||||
case UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS:
|
||||
|
@ -190,6 +194,10 @@ export class UserNotification implements UserNotificationServer {
|
|||
return videoImport.targetUrl || videoImport.magnetUri || videoImport.torrentName
|
||||
}
|
||||
|
||||
private buildCommentUrl (comment: { video: { uuid: string }, threadId: number }) {
|
||||
return [ this.buildVideoUrl(comment.video), { threadId: comment.threadId } ]
|
||||
}
|
||||
|
||||
private setAvatarUrl (actor: { avatarUrl?: string, avatar?: { url?: string, path: string } }) {
|
||||
actor.avatarUrl = Actor.GET_ACTOR_AVATAR_URL(actor)
|
||||
}
|
||||
|
|
|
@ -45,9 +45,22 @@
|
|||
<ng-container *ngSwitchCase="UserNotificationType.NEW_ABUSE_FOR_MODERATORS">
|
||||
<my-global-icon iconName="flag" aria-hidden="true"></my-global-icon>
|
||||
|
||||
<div class="message" i18n>
|
||||
<div class="message" *ngIf="notification.videoUrl" i18n>
|
||||
<a (click)="markAsRead(notification)" [routerLink]="notification.abuseUrl">A new video abuse</a> has been created on video <a (click)="markAsRead(notification)" [routerLink]="notification.videoUrl">{{ notification.abuse.video.name }}</a>
|
||||
</div>
|
||||
|
||||
<div class="message" *ngIf="notification.commentUrl" i18n>
|
||||
<a (click)="markAsRead(notification)" [routerLink]="notification.abuseUrl">A new comment abuse</a> has been created on video <a (click)="markAsRead(notification)" [routerLink]="notification.commentUrl">{{ notification.abuse.comment.video.name }}</a>
|
||||
</div>
|
||||
|
||||
<div class="message" *ngIf="notification.accountUrl" i18n>
|
||||
<a (click)="markAsRead(notification)" [routerLink]="notification.abuseUrl">A new account abuse</a> has been created on account <a (click)="markAsRead(notification)" [routerLink]="notification.accountUrl">{{ notification.abuse.account.displayName }}</a>
|
||||
</div>
|
||||
|
||||
<!-- Deleted entity associated to the abuse -->
|
||||
<div class="message" *ngIf="!notification.videoUrl && !notification.commentUrl && !notification.accountUrl" i18n>
|
||||
<a (click)="markAsRead(notification)" [routerLink]="notification.abuseUrl">A new abuse</a> has been created
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="UserNotificationType.VIDEO_AUTO_BLACKLIST_FOR_MODERATORS">
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
@import 'variables';
|
||||
@import 'mixins';
|
||||
|
||||
.information {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
@include peertube-textarea(100%, 100px);
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
export * from './report-modals'
|
||||
|
||||
export * from './abuse.service'
|
||||
export * from './account-block.model'
|
||||
export * from './account-blocklist.component'
|
||||
|
@ -9,5 +11,4 @@ export * from './user-ban-modal.component'
|
|||
export * from './user-moderation-dropdown.component'
|
||||
export * from './video-block.component'
|
||||
export * from './video-block.service'
|
||||
export * from './video-report.component'
|
||||
export * from './shared-moderation.module'
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
import { mapValues, pickBy } from 'lodash-es'
|
||||
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
||||
import { Notifier } from '@app/core'
|
||||
import { AbuseValidatorsService, FormReactive, FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { Account } from '@app/shared/shared-main'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { abusePredefinedReasonsMap, AbusePredefinedReasonsString } from '@shared/models'
|
||||
import { AbuseService } from '../abuse.service'
|
||||
|
||||
@Component({
|
||||
selector: 'my-account-report',
|
||||
templateUrl: './report.component.html',
|
||||
styleUrls: [ './report.component.scss' ]
|
||||
})
|
||||
export class AccountReportComponent extends FormReactive implements OnInit {
|
||||
@Input() account: Account = null
|
||||
|
||||
@ViewChild('modal', { static: true }) modal: NgbModal
|
||||
|
||||
error: string = null
|
||||
predefinedReasons: { id: AbusePredefinedReasonsString, label: string, description?: string, help?: string }[] = []
|
||||
modalTitle: string
|
||||
|
||||
private openedModal: NgbModalRef
|
||||
|
||||
constructor (
|
||||
protected formValidatorService: FormValidatorService,
|
||||
private modalService: NgbModal,
|
||||
private abuseValidatorsService: AbuseValidatorsService,
|
||||
private abuseService: AbuseService,
|
||||
private notifier: Notifier,
|
||||
private i18n: I18n
|
||||
) {
|
||||
super()
|
||||
}
|
||||
|
||||
get currentHost () {
|
||||
return window.location.host
|
||||
}
|
||||
|
||||
get originHost () {
|
||||
if (this.isRemote()) {
|
||||
return this.account.host
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.modalTitle = this.i18n('Report {{displayName}}', { displayName: this.account.displayName })
|
||||
|
||||
this.buildForm({
|
||||
reason: this.abuseValidatorsService.ABUSE_REASON,
|
||||
predefinedReasons: mapValues(abusePredefinedReasonsMap, r => null)
|
||||
})
|
||||
|
||||
this.predefinedReasons = this.abuseService.getPrefefinedReasons('account')
|
||||
}
|
||||
|
||||
show () {
|
||||
this.openedModal = this.modalService.open(this.modal, { centered: true, keyboard: false, size: 'lg' })
|
||||
}
|
||||
|
||||
hide () {
|
||||
this.openedModal.close()
|
||||
this.openedModal = null
|
||||
}
|
||||
|
||||
report () {
|
||||
const reason = this.form.get('reason').value
|
||||
const predefinedReasons = Object.keys(pickBy(this.form.get('predefinedReasons').value)) as AbusePredefinedReasonsString[]
|
||||
|
||||
this.abuseService.reportVideo({
|
||||
reason,
|
||||
predefinedReasons,
|
||||
account: {
|
||||
id: this.account.id
|
||||
}
|
||||
}).subscribe(
|
||||
() => {
|
||||
this.notifier.success(this.i18n('Account reported.'))
|
||||
this.hide()
|
||||
},
|
||||
|
||||
err => this.notifier.error(err.message)
|
||||
)
|
||||
}
|
||||
|
||||
isRemote () {
|
||||
return !this.account.isLocal
|
||||
}
|
||||
}
|
|
@ -1,28 +1,27 @@
|
|||
import { mapValues, pickBy } from 'lodash-es'
|
||||
import { Component, Input, OnInit, ViewChild } from '@angular/core'
|
||||
import { SafeHtml } from '@angular/platform-browser'
|
||||
import { VideoComment } from '@app/+videos/+video-watch/comment/video-comment.model'
|
||||
import { Notifier } from '@app/core'
|
||||
import { AbuseValidatorsService, FormReactive, FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { VideoComment } from '@app/shared/shared-video-comment'
|
||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { abusePredefinedReasonsMap, AbusePredefinedReasonsString } from '@shared/models'
|
||||
import { AbuseService } from './abuse.service'
|
||||
import { AbuseService } from '../abuse.service'
|
||||
|
||||
@Component({
|
||||
selector: 'my-comment-report',
|
||||
templateUrl: './comment-report.component.html',
|
||||
styleUrls: [ './comment-report.component.scss' ]
|
||||
templateUrl: './report.component.html',
|
||||
styleUrls: [ './report.component.scss' ]
|
||||
})
|
||||
export class CommentReportComponent extends FormReactive implements OnInit {
|
||||
@Input() comment: VideoComment = null
|
||||
|
||||
@ViewChild('modal', { static: true }) modal: NgbModal
|
||||
|
||||
modalTitle: string
|
||||
error: string = null
|
||||
predefinedReasons: { id: AbusePredefinedReasonsString, label: string, description?: string, help?: string }[] = []
|
||||
embedHtml: SafeHtml
|
||||
|
||||
private openedModal: NgbModalRef
|
||||
|
||||
|
@ -42,7 +41,7 @@ export class CommentReportComponent extends FormReactive implements OnInit {
|
|||
}
|
||||
|
||||
get originHost () {
|
||||
if (this.isRemoteComment()) {
|
||||
if (this.isRemote()) {
|
||||
return this.comment.account.host
|
||||
}
|
||||
|
||||
|
@ -50,6 +49,8 @@ export class CommentReportComponent extends FormReactive implements OnInit {
|
|||
}
|
||||
|
||||
ngOnInit () {
|
||||
this.modalTitle = this.i18n('Report comment')
|
||||
|
||||
this.buildForm({
|
||||
reason: this.abuseValidatorsService.ABUSE_REASON,
|
||||
predefinedReasons: mapValues(abusePredefinedReasonsMap, r => null)
|
||||
|
@ -87,7 +88,7 @@ export class CommentReportComponent extends FormReactive implements OnInit {
|
|||
)
|
||||
}
|
||||
|
||||
isRemoteComment () {
|
||||
isRemote () {
|
||||
return !this.comment.isLocal
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export * from './account-report.component'
|
||||
export * from './comment-report.component'
|
||||
export * from './video-report.component'
|
|
@ -1,6 +1,6 @@
|
|||
<ng-template #modal>
|
||||
<div class="modal-header">
|
||||
<h4 i18n class="modal-title">Report comment</h4>
|
||||
<h4 class="modal-title">{{ modalTitle }}</h4>
|
||||
<my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon>
|
||||
</div>
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
|
||||
<div class="col-7">
|
||||
<div i18n class="information">
|
||||
Your report will be sent to moderators of {{ currentHost }}<ng-container *ngIf="isRemoteComment()"> and will be forwarded to the comment origin ({{ originHost }}) too</ng-container>.
|
||||
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>.
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
|
@ -72,7 +72,7 @@
|
|||
</div>
|
||||
|
||||
<div i18n class="information">
|
||||
Your report will be sent to moderators of {{ currentHost }}<ng-container *ngIf="isRemoteVideo()"> and will be forwarded to the video origin ({{ originHost }}) too</ng-container>.
|
||||
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>.
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
|
@ -8,13 +8,13 @@ import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
|||
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap/modal/modal-ref'
|
||||
import { I18n } from '@ngx-translate/i18n-polyfill'
|
||||
import { abusePredefinedReasonsMap, AbusePredefinedReasonsString } from '@shared/models'
|
||||
import { Video } from '../shared-main'
|
||||
import { AbuseService } from './abuse.service'
|
||||
import { Video } from '../../shared-main'
|
||||
import { AbuseService } from '../abuse.service'
|
||||
|
||||
@Component({
|
||||
selector: 'my-video-report',
|
||||
templateUrl: './video-report.component.html',
|
||||
styleUrls: [ './video-report.component.scss' ]
|
||||
styleUrls: [ './report.component.scss' ]
|
||||
})
|
||||
export class VideoReportComponent extends FormReactive implements OnInit {
|
||||
@Input() video: Video = null
|
||||
|
@ -44,7 +44,7 @@ export class VideoReportComponent extends FormReactive implements OnInit {
|
|||
}
|
||||
|
||||
get originHost () {
|
||||
if (this.isRemoteVideo()) {
|
||||
if (this.isRemote()) {
|
||||
return this.video.account.host
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ export class VideoReportComponent extends FormReactive implements OnInit {
|
|||
)
|
||||
}
|
||||
|
||||
isRemoteVideo () {
|
||||
isRemote () {
|
||||
return !this.video.isLocal
|
||||
}
|
||||
}
|
|
@ -3,22 +3,23 @@ import { NgModule } from '@angular/core'
|
|||
import { SharedFormModule } from '../shared-forms/shared-form.module'
|
||||
import { SharedGlobalIconModule } from '../shared-icons'
|
||||
import { SharedMainModule } from '../shared-main/shared-main.module'
|
||||
import { SharedVideoCommentModule } from '../shared-video-comment'
|
||||
import { AbuseService } from './abuse.service'
|
||||
import { BatchDomainsModalComponent } from './batch-domains-modal.component'
|
||||
import { BlocklistService } from './blocklist.service'
|
||||
import { BulkService } from './bulk.service'
|
||||
import { UserBanModalComponent } from './user-ban-modal.component'
|
||||
import { UserModerationDropdownComponent } from './user-moderation-dropdown.component'
|
||||
import { AbuseService } from './abuse.service'
|
||||
import { VideoBlockComponent } from './video-block.component'
|
||||
import { VideoBlockService } from './video-block.service'
|
||||
import { VideoReportComponent } from './video-report.component'
|
||||
import { CommentReportComponent } from './comment-report.component'
|
||||
import { VideoReportComponent, AccountReportComponent, CommentReportComponent } from './report-modals'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedMainModule,
|
||||
SharedFormModule,
|
||||
SharedGlobalIconModule
|
||||
SharedGlobalIconModule,
|
||||
SharedVideoCommentModule
|
||||
],
|
||||
|
||||
declarations: [
|
||||
|
@ -27,7 +28,8 @@ import { CommentReportComponent } from './comment-report.component'
|
|||
VideoBlockComponent,
|
||||
VideoReportComponent,
|
||||
BatchDomainsModalComponent,
|
||||
CommentReportComponent
|
||||
CommentReportComponent,
|
||||
AccountReportComponent
|
||||
],
|
||||
|
||||
exports: [
|
||||
|
@ -36,7 +38,8 @@ import { CommentReportComponent } from './comment-report.component'
|
|||
VideoBlockComponent,
|
||||
VideoReportComponent,
|
||||
BatchDomainsModalComponent,
|
||||
CommentReportComponent
|
||||
CommentReportComponent,
|
||||
AccountReportComponent
|
||||
],
|
||||
|
||||
providers: [
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
export * from './video-comment.service'
|
||||
export * from './video-comment.model'
|
||||
export * from './video-comment-thread-tree.model'
|
||||
|
||||
export * from './shared-video-comment.module'
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
import { NgModule } from '@angular/core'
|
||||
import { SharedMainModule } from '../shared-main/shared-main.module'
|
||||
import { VideoCommentService } from './video-comment.service'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedMainModule
|
||||
],
|
||||
|
||||
declarations: [ ],
|
||||
|
||||
exports: [ ],
|
||||
|
||||
providers: [
|
||||
VideoCommentService
|
||||
]
|
||||
})
|
||||
export class SharedVideoCommentModule { }
|
|
@ -11,7 +11,7 @@ import {
|
|||
VideoCommentCreate,
|
||||
VideoCommentThreadTree as VideoCommentThreadTreeServerModel
|
||||
} from '@shared/models'
|
||||
import { environment } from '../../../../environments/environment'
|
||||
import { environment } from '../../../environments/environment'
|
||||
import { VideoCommentThreadTree } from './video-comment-thread-tree.model'
|
||||
import { VideoComment } from './video-comment.model'
|
||||
|
|
@ -311,7 +311,8 @@ class Emailer {
|
|||
videoPublishedAt: new Date(video.publishedAt).toLocaleString(),
|
||||
videoName: video.name,
|
||||
reason: abuse.reason,
|
||||
videoChannel: video.VideoChannel,
|
||||
videoChannel: abuse.video.channel,
|
||||
reporter,
|
||||
action
|
||||
}
|
||||
}
|
||||
|
@ -330,6 +331,7 @@ class Emailer {
|
|||
commentCreatedAt: new Date(comment.createdAt).toLocaleString(),
|
||||
reason: abuse.reason,
|
||||
flaggedAccount: abuseInstance.FlaggedAccount.getDisplayName(),
|
||||
reporter,
|
||||
action
|
||||
}
|
||||
}
|
||||
|
@ -346,6 +348,7 @@ class Emailer {
|
|||
accountDisplayName: account.getDisplayName(),
|
||||
isLocal: account.isOwned(),
|
||||
reason: abuse.reason,
|
||||
reporter,
|
||||
action
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@ block title
|
|||
|
||||
block content
|
||||
p
|
||||
| #[a(href=WEBSERVER.URL) #{WEBSERVER.HOST}] received an abuse report for the #{isLocal ? '' : 'remote '}account "
|
||||
a(href=accountUrl) #{accountDisplayName}
|
||||
| #[a(href=WEBSERVER.URL) #{WEBSERVER.HOST}] received an abuse report for the #{isLocal ? '' : 'remote '}account
|
||||
a(href=accountUrl) #{accountDisplayName}
|
||||
|
||||
p The reporter, #{reporter}, cited the following reason(s):
|
||||
blockquote #{reason}
|
||||
|
|
|
@ -6,10 +6,10 @@ block title
|
|||
|
||||
block content
|
||||
p
|
||||
| #[a(href=WEBSERVER.URL) #{WEBSERVER.HOST}] received an abuse report for the #{isLocal ? '' : 'remote '}comment "
|
||||
a(href=commentUrl) on video #{videoName}
|
||||
| of #{flaggedAccount}
|
||||
| created on #{commentCreatedAt}
|
||||
| #[a(href=WEBSERVER.URL) #{WEBSERVER.HOST}] received an abuse report for the #{isLocal ? '' : 'remote '}
|
||||
a(href=commentUrl) comment on video "#{videoName}"
|
||||
| of #{flaggedAccount}
|
||||
| created on #{commentCreatedAt}
|
||||
|
||||
p The reporter, #{reporter}, cited the following reason(s):
|
||||
blockquote #{reason}
|
||||
|
|
|
@ -62,9 +62,9 @@ export interface Abuse {
|
|||
// FIXME: deprecated in 2.3, remove the following properties
|
||||
|
||||
// @deprecated
|
||||
startAt: null
|
||||
startAt?: null
|
||||
// @deprecated
|
||||
endAt: null
|
||||
endAt?: null
|
||||
|
||||
// @deprecated
|
||||
count?: number
|
||||
|
|
|
@ -73,7 +73,9 @@ export interface UserNotification {
|
|||
threadId: number
|
||||
|
||||
video: {
|
||||
id: number
|
||||
uuid: string
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue