aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/abuse
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/abuse')
-rw-r--r--server/models/abuse/abuse.ts130
1 files changed, 59 insertions, 71 deletions
diff --git a/server/models/abuse/abuse.ts b/server/models/abuse/abuse.ts
index 087c77bd3..9c17c4d51 100644
--- a/server/models/abuse/abuse.ts
+++ b/server/models/abuse/abuse.ts
@@ -31,15 +31,15 @@ import {
31} from '@shared/models' 31} from '@shared/models'
32import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants' 32import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants'
33import { MAbuse, MAbuseAP, MAbuseFormattable, MUserAccountId } from '../../types/models' 33import { MAbuse, MAbuseAP, MAbuseFormattable, MUserAccountId } from '../../types/models'
34import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account' 34import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions as AccountSummaryOptions } from '../account/account'
35import { buildBlockedAccountSQL, getSort, searchAttribute, throwIfNotValid } from '../utils' 35import { buildBlockedAccountSQL, getSort, searchAttribute, throwIfNotValid } from '../utils'
36import { ThumbnailModel } from '../video/thumbnail' 36import { ThumbnailModel } from '../video/thumbnail'
37import { VideoModel } from '../video/video' 37import { VideoModel } from '../video/video'
38import { VideoBlacklistModel } from '../video/video-blacklist' 38import { VideoBlacklistModel } from '../video/video-blacklist'
39import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel' 39import { ScopeNames as VideoChannelScopeNames, SummaryOptions as ChannelSummaryOptions, VideoChannelModel } from '../video/video-channel'
40import { VideoCommentModel } from '../video/video-comment'
40import { VideoAbuseModel } from './video-abuse' 41import { VideoAbuseModel } from './video-abuse'
41import { VideoCommentAbuseModel } from './video-comment-abuse' 42import { VideoCommentAbuseModel } from './video-comment-abuse'
42import { VideoCommentModel } from '../video/video-comment'
43 43
44export enum ScopeNames { 44export enum ScopeNames {
45 FOR_API = 'FOR_API' 45 FOR_API = 'FOR_API'
@@ -149,7 +149,7 @@ export enum ScopeNames {
149 '(' + 149 '(' +
150 'SELECT count(*) ' + 150 'SELECT count(*) ' +
151 'FROM "videoAbuse" ' + 151 'FROM "videoAbuse" ' +
152 'WHERE "videoId" = "VideoAbuse"."videoId" ' + 152 'WHERE "videoId" = "VideoAbuse"."videoId" AND "videoId" IS NOT NULL' +
153 ')' 153 ')'
154 ), 154 ),
155 'countReportsForVideo' 155 'countReportsForVideo'
@@ -164,7 +164,7 @@ export enum ScopeNames {
164 'row_number() OVER (PARTITION BY "videoId" ORDER BY "createdAt") AS nth ' + 164 'row_number() OVER (PARTITION BY "videoId" ORDER BY "createdAt") AS nth ' +
165 'FROM "videoAbuse" ' + 165 'FROM "videoAbuse" ' +
166 ') t ' + 166 ') t ' +
167 'WHERE t.id = "VideoAbuse".id' + 167 'WHERE t.id = "VideoAbuse".id AND t.id IS NOT NULL' +
168 ')' 168 ')'
169 ), 169 ),
170 'nthReportForVideo' 170 'nthReportForVideo'
@@ -172,51 +172,22 @@ export enum ScopeNames {
172 [ 172 [
173 literal( 173 literal(
174 '(' + 174 '(' +
175 'SELECT count("videoAbuse"."id") ' + 175 'SELECT count("abuse"."id") ' +
176 'FROM "videoAbuse" ' + 176 'FROM "abuse" ' +
177 'INNER JOIN "video" ON "video"."id" = "videoAbuse"."videoId" ' + 177 'WHERE "abuse"."reporterAccountId" = "AbuseModel"."reporterAccountId"' +
178 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
179 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
180 'WHERE "account"."id" = "AbuseModel"."reporterAccountId" ' +
181 ')'
182 ),
183 'countReportsForReporter__video'
184 ],
185 [
186 literal(
187 '(' +
188 'SELECT count(DISTINCT "videoAbuse"."id") ' +
189 'FROM "videoAbuse" ' +
190 `WHERE CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = "AbuseModel"."reporterAccountId" ` +
191 ')'
192 ),
193 'countReportsForReporter__deletedVideo'
194 ],
195 [
196 literal(
197 '(' +
198 'SELECT count(DISTINCT "videoAbuse"."id") ' +
199 'FROM "videoAbuse" ' +
200 'INNER JOIN "video" ON "video"."id" = "videoAbuse"."videoId" ' +
201 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
202 'INNER JOIN "account" ON ' +
203 '"videoChannel"."accountId" = "VideoAbuse->Video->VideoChannel"."accountId" ' +
204 `OR "videoChannel"."accountId" = CAST("VideoAbuse"."deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) ` +
205 ')' 178 ')'
206 ), 179 ),
207 'countReportsForReportee__video' 180 'countReportsForReporter'
208 ], 181 ],
209 [ 182 [
210 literal( 183 literal(
211 '(' + 184 '(' +
212 'SELECT count(DISTINCT "videoAbuse"."id") ' + 185 'SELECT count("abuse"."id") ' +
213 'FROM "videoAbuse" ' + 186 'FROM "abuse" ' +
214 `WHERE CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = "VideoAbuse->Video->VideoChannel"."accountId" ` + 187 'WHERE "abuse"."flaggedAccountId" = "AbuseModel"."flaggedAccountId"' +
215 `OR CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = ` +
216 `CAST("VideoAbuse"."deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) ` +
217 ')' 188 ')'
218 ), 189 ),
219 'countReportsForReportee__deletedVideo' 190 'countReportsForReportee'
220 ] 191 ]
221 ] 192 ]
222 }, 193 },
@@ -224,13 +195,18 @@ export enum ScopeNames {
224 { 195 {
225 model: AccountModel.scope(AccountScopeNames.SUMMARY), 196 model: AccountModel.scope(AccountScopeNames.SUMMARY),
226 as: 'ReporterAccount', 197 as: 'ReporterAccount',
227 required: true, 198 required: !!options.searchReporter,
228 where: searchAttribute(options.searchReporter, 'name') 199 where: searchAttribute(options.searchReporter, 'name')
229 }, 200 },
230 { 201 {
231 model: AccountModel.scope(AccountScopeNames.SUMMARY), 202 model: AccountModel.scope({
203 method: [
204 AccountScopeNames.SUMMARY,
205 { actorRequired: false } as AccountSummaryOptions
206 ]
207 }),
232 as: 'FlaggedAccount', 208 as: 'FlaggedAccount',
233 required: true, 209 required: !!options.searchReportee,
234 where: searchAttribute(options.searchReportee, 'name') 210 where: searchAttribute(options.searchReportee, 'name')
235 }, 211 },
236 { 212 {
@@ -243,35 +219,36 @@ export enum ScopeNames {
243 include: [ 219 include: [
244 { 220 {
245 model: VideoModel.unscoped(), 221 model: VideoModel.unscoped(),
246 attributes: [ 'name', 'id', 'uuid' ], 222 attributes: [ 'name', 'id', 'uuid' ]
247 required: true
248 } 223 }
249 ] 224 ]
250 } 225 }
251 ] 226 ]
252 }, 227 },
253 { 228 {
254 model: VideoAbuseModel, 229 model: VideoAbuseModel.unscoped(),
255 required: options.filter === 'video' || !!options.videoIs || videoRequired, 230 required: options.filter === 'video' || !!options.videoIs || videoRequired,
256 include: [ 231 include: [
257 { 232 {
258 model: VideoModel, 233 attributes: [ 'id', 'uuid', 'name', 'nsfw' ],
234 model: VideoModel.unscoped(),
259 required: videoRequired, 235 required: videoRequired,
260 where: searchAttribute(options.searchVideo, 'name'), 236 where: searchAttribute(options.searchVideo, 'name'),
261 include: [ 237 include: [
262 { 238 {
239 attributes: [ 'filename', 'fileUrl' ],
263 model: ThumbnailModel 240 model: ThumbnailModel
264 }, 241 },
265 { 242 {
266 model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: false } as SummaryOptions ] }), 243 model: VideoChannelModel.scope({
244 method: [
245 VideoChannelScopeNames.SUMMARY,
246 { withAccount: false, actorRequired: false } as ChannelSummaryOptions
247 ]
248 }),
249
267 where: searchAttribute(options.searchVideoChannel, 'name'), 250 where: searchAttribute(options.searchVideoChannel, 'name'),
268 required: true, 251 required: !!options.searchVideoChannel
269 include: [
270 {
271 model: AccountModel.scope(AccountScopeNames.SUMMARY),
272 required: true
273 }
274 ]
275 }, 252 },
276 { 253 {
277 attributes: [ 'id', 'reason', 'unfederated' ], 254 attributes: [ 'id', 'reason', 'unfederated' ],
@@ -304,19 +281,19 @@ export class AbuseModel extends Model<AbuseModel> {
304 281
305 @AllowNull(false) 282 @AllowNull(false)
306 @Default(null) 283 @Default(null)
307 @Is('VideoAbuseReason', value => throwIfNotValid(value, isAbuseReasonValid, 'reason')) 284 @Is('AbuseReason', value => throwIfNotValid(value, isAbuseReasonValid, 'reason'))
308 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.REASON.max)) 285 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.REASON.max))
309 reason: string 286 reason: string
310 287
311 @AllowNull(false) 288 @AllowNull(false)
312 @Default(null) 289 @Default(null)
313 @Is('VideoAbuseState', value => throwIfNotValid(value, isAbuseStateValid, 'state')) 290 @Is('AbuseState', value => throwIfNotValid(value, isAbuseStateValid, 'state'))
314 @Column 291 @Column
315 state: AbuseState 292 state: AbuseState
316 293
317 @AllowNull(true) 294 @AllowNull(true)
318 @Default(null) 295 @Default(null)
319 @Is('VideoAbuseModerationComment', value => throwIfNotValid(value, isAbuseModerationCommentValid, 'moderationComment', true)) 296 @Is('AbuseModerationComment', value => throwIfNotValid(value, isAbuseModerationCommentValid, 'moderationComment', true))
320 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.MODERATION_COMMENT.max)) 297 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.MODERATION_COMMENT.max))
321 moderationComment: string 298 moderationComment: string
322 299
@@ -486,12 +463,12 @@ export class AbuseModel extends Model<AbuseModel> {
486 463
487 toFormattedJSON (this: MAbuseFormattable): Abuse { 464 toFormattedJSON (this: MAbuseFormattable): Abuse {
488 const predefinedReasons = AbuseModel.getPredefinedReasonsStrings(this.predefinedReasons) 465 const predefinedReasons = AbuseModel.getPredefinedReasonsStrings(this.predefinedReasons)
466
489 const countReportsForVideo = this.get('countReportsForVideo') as number 467 const countReportsForVideo = this.get('countReportsForVideo') as number
490 const nthReportForVideo = this.get('nthReportForVideo') as number 468 const nthReportForVideo = this.get('nthReportForVideo') as number
491 const countReportsForReporterVideo = this.get('countReportsForReporter__video') as number 469
492 const countReportsForReporterDeletedVideo = this.get('countReportsForReporter__deletedVideo') as number 470 const countReportsForReporter = this.get('countReportsForReporter') as number
493 const countReportsForReporteeVideo = this.get('countReportsForReportee__video') as number 471 const countReportsForReportee = this.get('countReportsForReportee') as number
494 const countReportsForReporteeDeletedVideo = this.get('countReportsForReportee__deletedVideo') as number
495 472
496 let video: VideoAbuse 473 let video: VideoAbuse
497 let comment: VideoCommentAbuse 474 let comment: VideoCommentAbuse
@@ -512,7 +489,11 @@ export class AbuseModel extends Model<AbuseModel> {
512 deleted: !abuseModel.Video, 489 deleted: !abuseModel.Video,
513 blacklisted: abuseModel.Video?.isBlacklisted() || false, 490 blacklisted: abuseModel.Video?.isBlacklisted() || false,
514 thumbnailPath: abuseModel.Video?.getMiniatureStaticPath(), 491 thumbnailPath: abuseModel.Video?.getMiniatureStaticPath(),
515 channel: abuseModel.Video?.VideoChannel.toFormattedJSON() || abuseModel.deletedVideo?.channel 492
493 channel: abuseModel.Video?.VideoChannel.toFormattedJSON() || abuseModel.deletedVideo?.channel,
494
495 countReports: countReportsForVideo,
496 nthReport: nthReportForVideo
516 } 497 }
517 } 498 }
518 499
@@ -539,7 +520,13 @@ export class AbuseModel extends Model<AbuseModel> {
539 reason: this.reason, 520 reason: this.reason,
540 predefinedReasons, 521 predefinedReasons,
541 522
542 reporterAccount: this.ReporterAccount.toFormattedJSON(), 523 reporterAccount: this.ReporterAccount
524 ? this.ReporterAccount.toFormattedJSON()
525 : null,
526
527 flaggedAccount: this.FlaggedAccount
528 ? this.FlaggedAccount.toFormattedJSON()
529 : null,
543 530
544 state: { 531 state: {
545 id: this.state, 532 id: this.state,
@@ -553,14 +540,15 @@ export class AbuseModel extends Model<AbuseModel> {
553 540
554 createdAt: this.createdAt, 541 createdAt: this.createdAt,
555 updatedAt: this.updatedAt, 542 updatedAt: this.updatedAt,
556 count: countReportsForVideo || 0, 543
557 nth: nthReportForVideo || 0, 544 countReportsForReporter: (countReportsForReporter || 0),
558 countReportsForReporter: (countReportsForReporterVideo || 0) + (countReportsForReporterDeletedVideo || 0), 545 countReportsForReportee: (countReportsForReportee || 0),
559 countReportsForReportee: (countReportsForReporteeVideo || 0) + (countReportsForReporteeDeletedVideo || 0),
560 546
561 // FIXME: deprecated in 2.3, remove this 547 // FIXME: deprecated in 2.3, remove this
562 startAt: null, 548 startAt: null,
563 endAt: null 549 endAt: null,
550 count: countReportsForVideo || 0,
551 nth: nthReportForVideo || 0
564 } 552 }
565 } 553 }
566 554