|
@@ -40,18 +51,14 @@
-
+ |
-
- ![]()
- Deleted
-
+
{{ videoAbuse.video.name }}
-
-
+
by {{ videoAbuse.video.channel?.displayName }} on {{ videoAbuse.video.channel?.host }}
@@ -60,7 +67,20 @@
|
- {{ videoAbuse.createdAt }} |
+
+
+ Deleted
+
+
+ {{ videoAbuse.video.name }}
+
+
+ by {{ videoAbuse.video.channel?.displayName }} on {{ videoAbuse.video.channel?.host }}
+
+
+ |
+
+ {{ videoAbuse.createdAt }} |
diff --git a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.scss b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.scss
index 09402fda7..9b60c39dc 100644
--- a/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.scss
+++ b/client/src/app/+admin/moderation/video-abuse-list/video-abuse-list.component.scss
@@ -1,6 +1,14 @@
@import 'mixins';
@import 'miniature';
+.caption {
+ justify-content: flex-end;
+
+ input {
+ @include peertube-input-text(250px);
+ }
+}
+
.video-abuse-video-link {
@include disable-outline;
position: relative;
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 cc5014ae8..6dcf96ccf 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
@@ -16,6 +16,8 @@ import { getAbsoluteAPIUrl } from '@app/shared/misc/utils'
import { DomSanitizer } from '@angular/platform-browser'
import { BlocklistService } from '@app/shared/blocklist'
import { VideoService } from '@app/shared/video/video.service'
+import { ActivatedRoute } from '@angular/router'
+import { first } from 'rxjs/operators'
@Component({
selector: 'my-video-abuse-list',
@@ -43,7 +45,8 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
private confirmService: ConfirmService,
private i18n: I18n,
private markdownRenderer: MarkdownService,
- private sanitizer: DomSanitizer
+ private sanitizer: DomSanitizer,
+ private route: ActivatedRoute,
) {
super()
@@ -185,6 +188,10 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
ngOnInit () {
this.initialize()
+
+ this.route.queryParams
+ .pipe(first(params => params.search !== undefined && params.search !== null))
+ .subscribe(params => this.search = params.search)
}
getIdentifier () {
@@ -253,26 +260,29 @@ export class VideoAbuseListComponent extends RestTable implements OnInit {
}
protected loadData () {
- return this.videoAbuseService.getVideoAbuses(this.pagination, this.sort)
- .subscribe(
- async resultList => {
- this.totalRecords = resultList.total
+ return this.videoAbuseService.getVideoAbuses({
+ pagination: this.pagination,
+ sort: this.sort,
+ search: this.search
+ }).subscribe(
+ async resultList => {
+ this.totalRecords = resultList.total
- this.videoAbuses = resultList.data
+ this.videoAbuses = resultList.data
- for (const abuse of this.videoAbuses) {
- Object.assign(abuse, {
- reasonHtml: await this.toHtml(abuse.reason),
- moderationCommentHtml: await this.toHtml(abuse.moderationComment),
- embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)),
- reporterAccount: new Account(abuse.reporterAccount)
- })
- }
+ for (const abuse of this.videoAbuses) {
+ Object.assign(abuse, {
+ reasonHtml: await this.toHtml(abuse.reason),
+ moderationCommentHtml: await this.toHtml(abuse.moderationComment),
+ embedHtml: this.sanitizer.bypassSecurityTrustHtml(this.getVideoEmbed(abuse)),
+ reporterAccount: new Account(abuse.reporterAccount)
+ })
+ }
- },
+ },
- err => this.notifier.error(err.message)
- )
+ err => this.notifier.error(err.message)
+ )
}
private toHtml (text: string) {
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 61a328575..a39ad31d4 100644
--- a/client/src/app/shared/video-abuse/video-abuse.service.ts
+++ b/client/src/app/shared/video-abuse/video-abuse.service.ts
@@ -17,12 +17,19 @@ export class VideoAbuseService {
private restExtractor: RestExtractor
) {}
- getVideoAbuses (pagination: RestPagination, sort: SortMeta): Observable> {
+ getVideoAbuses (options: {
+ pagination: RestPagination,
+ sort: SortMeta,
+ search?: string
+ }): Observable> {
+ const { pagination, sort, search } = options
const url = VideoAbuseService.BASE_VIDEO_ABUSE_URL + 'abuse'
let params = new HttpParams()
params = this.restService.addRestGetParams(params, pagination, sort)
+ if (search) params = params.append('search', search)
+
return this.authHttp.get>(url, { params })
.pipe(
map(res => this.restExtractor.convertResultListDateToHuman(res)),
diff --git a/server/controllers/api/videos/abuse.ts b/server/controllers/api/videos/abuse.ts
index 4ae899b7e..f37d90896 100644
--- a/server/controllers/api/videos/abuse.ts
+++ b/server/controllers/api/videos/abuse.ts
@@ -69,6 +69,7 @@ async function listVideoAbuses (req: express.Request, res: express.Response) {
start: req.query.start,
count: req.query.count,
sort: req.query.sort,
+ search: req.query.search,
serverAccountId: serverActor.Account.id,
user
})
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts
index ea943ffdf..5ead02eca 100644
--- a/server/models/video/video-abuse.ts
+++ b/server/models/video/video-abuse.ts
@@ -1,5 +1,5 @@
import {
- AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt, DefaultScope
+ AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt, Scopes
} from 'sequelize-typescript'
import { VideoAbuseObject } from '../../../shared/models/activitypub/objects'
import { VideoAbuse } from '../../../shared/models/videos'
@@ -21,34 +21,99 @@ import { VideoChannelModel } from './video-channel'
import { ActorModel } from '../activitypub/actor'
import { VideoBlacklistModel } from './video-blacklist'
-@DefaultScope(() => ({
- include: [
- {
- model: AccountModel,
- required: true
- },
- {
- model: VideoModel,
- required: false,
+export enum ScopeNames {
+ FOR_API = 'FOR_API'
+}
+
+@Scopes(() => ({
+ [ScopeNames.FOR_API]: (options: {
+ search?: string
+ searchReporter?: string
+ searchVideo?: string
+ searchVideoChannel?: string
+ serverAccountId: number
+ userAccountId: any
+ }) => {
+ const search = (sourceField, targetField) => sourceField ? ({
+ [targetField]: {
+ [Op.iLike]: `%${sourceField}%`
+ }
+ }) : {}
+
+ let where = {
+ reporterAccountId: {
+ [Op.notIn]: literal('(' + buildBlockedAccountSQL(options.serverAccountId, options.userAccountId) + ')')
+ }
+ }
+
+ if (options.search) {
+ where = Object.assign(where, {
+ [Op.or]: [
+ {
+ [Op.and]: [
+ { videoId: { [Op.not]: null } },
+ { '$Video.name$': { [Op.iLike]: `%${options.search}%` } }
+ ]
+ },
+ {
+ [Op.and]: [
+ { videoId: { [Op.not]: null } },
+ { '$Video.VideoChannel.name$': { [Op.iLike]: `%${options.search}%` } }
+ ]
+ },
+ {
+ [Op.and]: [
+ { deletedVideo: { [Op.not]: null } },
+ { deletedVideo: { name: { [Op.iLike]: `%${options.search}%` } } }
+ ]
+ },
+ {
+ [Op.and]: [
+ { deletedVideo: { [Op.not]: null } },
+ { deletedVideo: { channel: { displayName: { [Op.iLike]: `%${options.search}%` } } } }
+ ]
+ },
+ { '$Account.name$': { [Op.iLike]: `%${options.search}%` } }
+ ]
+ })
+ }
+
+ console.log(where)
+
+ return {
include: [
{
- model: ThumbnailModel
+ model: AccountModel,
+ required: true,
+ where: { ...search(options.searchReporter, 'name') }
},
{
- model: VideoChannelModel.unscoped(),
+ model: VideoModel,
+ required: false,
+ where: { ...search(options.searchVideo, 'name') },
include: [
{
- model: ActorModel
+ model: ThumbnailModel
+ },
+ {
+ model: VideoChannelModel.unscoped(),
+ where: { ...search(options.searchVideoChannel, 'name') },
+ include: [
+ {
+ model: ActorModel
+ }
+ ]
+ },
+ {
+ attributes: [ 'id', 'reason', 'unfederated' ],
+ model: VideoBlacklistModel
}
]
- },
- {
- attributes: [ 'id', 'reason', 'unfederated' ],
- model: VideoBlacklistModel
}
- ]
+ ],
+ where
}
- ]
+ }
}))
@Table({
tableName: 'videoAbuse',
@@ -134,26 +199,30 @@ export class VideoAbuseModel extends Model {
start: number
count: number
sort: string
+ search?: string
serverAccountId: number
user?: MUserAccountId
}) {
- const { start, count, sort, user, serverAccountId } = parameters
+ const { start, count, sort, search, user, serverAccountId } = parameters
const userAccountId = user ? user.Account.id : undefined
const query = {
offset: start,
limit: count,
order: getSort(sort),
- where: {
- reporterAccountId: {
- [Op.notIn]: literal('(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')')
- }
- },
col: 'VideoAbuseModel.id',
distinct: true
}
- return VideoAbuseModel.findAndCountAll(query)
+ const filters = {
+ search,
+ serverAccountId,
+ userAccountId
+ }
+
+ return VideoAbuseModel
+ .scope({ method: [ ScopeNames.FOR_API, filters ] })
+ .findAndCountAll(query)
.then(({ rows, count }) => {
return { total: count, data: rows }
})
|