]>
Commit | Line | Data |
---|---|---|
feb34f6b | 1 | import * as Bluebird from 'bluebird' |
d95d1559 C |
2 | import { invert } from 'lodash' |
3 | import { literal, Op, WhereOptions } from 'sequelize' | |
86521a67 | 4 | import { |
feb34f6b C |
5 | AllowNull, |
6 | BelongsTo, | |
7 | Column, | |
8 | CreatedAt, | |
9 | DataType, | |
10 | Default, | |
11 | ForeignKey, | |
d95d1559 | 12 | HasOne, |
feb34f6b C |
13 | Is, |
14 | Model, | |
15 | Scopes, | |
16 | Table, | |
17 | UpdatedAt | |
86521a67 | 18 | } from 'sequelize-typescript' |
d95d1559 | 19 | import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses' |
268eebed | 20 | import { |
d95d1559 | 21 | Abuse, |
57f6896f | 22 | AbuseFilter, |
d95d1559 C |
23 | AbuseObject, |
24 | AbusePredefinedReasons, | |
25 | abusePredefinedReasonsMap, | |
26 | AbusePredefinedReasonsString, | |
27 | AbuseState, | |
28 | AbuseVideoIs, | |
57f6896f C |
29 | VideoAbuse, |
30 | VideoCommentAbuse | |
d95d1559 | 31 | } from '@shared/models' |
57f6896f | 32 | import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants' |
d95d1559 C |
33 | import { MAbuse, MAbuseAP, MAbuseFormattable, MUserAccountId } from '../../types/models' |
34 | import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account' | |
feb34f6b | 35 | import { buildBlockedAccountSQL, getSort, searchAttribute, throwIfNotValid } from '../utils' |
d95d1559 C |
36 | import { ThumbnailModel } from '../video/thumbnail' |
37 | import { VideoModel } from '../video/video' | |
38 | import { VideoBlacklistModel } from '../video/video-blacklist' | |
39 | import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel' | |
40 | import { VideoAbuseModel } from './video-abuse' | |
41 | import { VideoCommentAbuseModel } from './video-comment-abuse' | |
57f6896f | 42 | import { VideoCommentModel } from '../video/video-comment' |
3fd3ab2d | 43 | |
844db39e RK |
44 | export enum ScopeNames { |
45 | FOR_API = 'FOR_API' | |
46 | } | |
47 | ||
48 | @Scopes(() => ({ | |
49 | [ScopeNames.FOR_API]: (options: { | |
0d3a2982 | 50 | // search |
844db39e RK |
51 | search?: string |
52 | searchReporter?: string | |
0d3a2982 | 53 | searchReportee?: string |
d95d1559 C |
54 | |
55 | // video releated | |
844db39e RK |
56 | searchVideo?: string |
57 | searchVideoChannel?: string | |
d95d1559 | 58 | videoIs?: AbuseVideoIs |
fc8aabd0 | 59 | |
0d3a2982 RK |
60 | // filters |
61 | id?: number | |
1ebddadd | 62 | predefinedReasonId?: number |
d95d1559 | 63 | filter?: AbuseFilter |
feb34f6b | 64 | |
d95d1559 | 65 | state?: AbuseState |
fc8aabd0 | 66 | |
0d3a2982 | 67 | // accountIds |
844db39e | 68 | serverAccountId: number |
0251197e | 69 | userAccountId: number |
844db39e | 70 | }) => { |
57f6896f | 71 | const whereAnd: WhereOptions[] = [] |
d95d1559 | 72 | |
57f6896f | 73 | whereAnd.push({ |
844db39e | 74 | reporterAccountId: { |
696d83fd | 75 | [Op.notIn]: literal('(' + buildBlockedAccountSQL([ options.serverAccountId, options.userAccountId ]) + ')') |
844db39e | 76 | } |
57f6896f | 77 | }) |
844db39e RK |
78 | |
79 | if (options.search) { | |
d95d1559 C |
80 | const escapedSearch = AbuseModel.sequelize.escape('%' + options.search + '%') |
81 | ||
57f6896f | 82 | whereAnd.push({ |
844db39e RK |
83 | [Op.or]: [ |
84 | { | |
85 | [Op.and]: [ | |
d95d1559 C |
86 | { '$VideoAbuse.videoId$': { [Op.not]: null } }, |
87 | searchAttribute(options.search, '$VideoAbuse.Video.name$') | |
844db39e RK |
88 | ] |
89 | }, | |
90 | { | |
91 | [Op.and]: [ | |
d95d1559 C |
92 | { '$VideoAbuse.videoId$': { [Op.not]: null } }, |
93 | searchAttribute(options.search, '$VideoAbuse.Video.VideoChannel.name$') | |
844db39e RK |
94 | ] |
95 | }, | |
96 | { | |
97 | [Op.and]: [ | |
d95d1559 C |
98 | { '$VideoAbuse.deletedVideo$': { [Op.not]: null } }, |
99 | literal(`"VideoAbuse"."deletedVideo"->>'name' ILIKE ${escapedSearch}`) | |
844db39e RK |
100 | ] |
101 | }, | |
102 | { | |
103 | [Op.and]: [ | |
d95d1559 C |
104 | { '$VideoAbuse.deletedVideo$': { [Op.not]: null } }, |
105 | literal(`"VideoAbuse"."deletedVideo"->'channel'->>'displayName' ILIKE ${escapedSearch}`) | |
844db39e RK |
106 | ] |
107 | }, | |
d95d1559 C |
108 | searchAttribute(options.search, '$ReporterAccount.name$'), |
109 | searchAttribute(options.search, '$FlaggedAccount.name$') | |
844db39e RK |
110 | ] |
111 | }) | |
112 | } | |
113 | ||
57f6896f C |
114 | if (options.id) whereAnd.push({ id: options.id }) |
115 | if (options.state) whereAnd.push({ state: options.state }) | |
0d3a2982 | 116 | |
feb34f6b | 117 | if (options.videoIs === 'deleted') { |
57f6896f | 118 | whereAnd.push({ |
d95d1559 | 119 | '$VideoAbuse.deletedVideo$': { |
feb34f6b C |
120 | [Op.not]: null |
121 | } | |
0d3a2982 RK |
122 | }) |
123 | } | |
124 | ||
1ebddadd | 125 | if (options.predefinedReasonId) { |
57f6896f | 126 | whereAnd.push({ |
1ebddadd RK |
127 | predefinedReasons: { |
128 | [Op.contains]: [ options.predefinedReasonId ] | |
129 | } | |
130 | }) | |
131 | } | |
132 | ||
57f6896f C |
133 | if (options.filter === 'account') { |
134 | whereAnd.push({ | |
135 | videoId: null, | |
136 | commentId: null | |
137 | }) | |
138 | } | |
139 | ||
140 | const onlyBlacklisted = options.videoIs === 'blacklisted' | |
141 | const videoRequired = !!(onlyBlacklisted || options.searchVideo || options.searchVideoChannel) | |
142 | ||
844db39e | 143 | return { |
5fd4ca00 RK |
144 | attributes: { |
145 | include: [ | |
146 | [ | |
efa012ed | 147 | // we don't care about this count for deleted videos, so there are not included |
5fd4ca00 RK |
148 | literal( |
149 | '(' + | |
0251197e RK |
150 | 'SELECT count(*) ' + |
151 | 'FROM "videoAbuse" ' + | |
d95d1559 | 152 | 'WHERE "videoId" = "VideoAbuse"."videoId" ' + |
5fd4ca00 RK |
153 | ')' |
154 | ), | |
155 | 'countReportsForVideo' | |
156 | ], | |
157 | [ | |
efa012ed | 158 | // we don't care about this count for deleted videos, so there are not included |
5fd4ca00 RK |
159 | literal( |
160 | '(' + | |
161 | 'SELECT t.nth ' + | |
162 | 'FROM ( ' + | |
163 | 'SELECT id, ' + | |
164 | 'row_number() OVER (PARTITION BY "videoId" ORDER BY "createdAt") AS nth ' + | |
165 | 'FROM "videoAbuse" ' + | |
166 | ') t ' + | |
d95d1559 | 167 | 'WHERE t.id = "VideoAbuse".id' + |
5fd4ca00 RK |
168 | ')' |
169 | ), | |
170 | 'nthReportForVideo' | |
171 | ], | |
172 | [ | |
173 | literal( | |
174 | '(' + | |
175 | 'SELECT count("videoAbuse"."id") ' + | |
176 | 'FROM "videoAbuse" ' + | |
177 | 'INNER JOIN "video" ON "video"."id" = "videoAbuse"."videoId" ' + | |
178 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | |
179 | 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' + | |
d95d1559 | 180 | 'WHERE "account"."id" = "AbuseModel"."reporterAccountId" ' + |
5fd4ca00 RK |
181 | ')' |
182 | ), | |
efa012ed RK |
183 | 'countReportsForReporter__video' |
184 | ], | |
185 | [ | |
186 | literal( | |
187 | '(' + | |
188 | 'SELECT count(DISTINCT "videoAbuse"."id") ' + | |
189 | 'FROM "videoAbuse" ' + | |
d95d1559 | 190 | `WHERE CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = "AbuseModel"."reporterAccountId" ` + |
efa012ed RK |
191 | ')' |
192 | ), | |
193 | 'countReportsForReporter__deletedVideo' | |
5fd4ca00 RK |
194 | ], |
195 | [ | |
196 | literal( | |
197 | '(' + | |
0251197e | 198 | 'SELECT count(DISTINCT "videoAbuse"."id") ' + |
5fd4ca00 RK |
199 | 'FROM "videoAbuse" ' + |
200 | 'INNER JOIN "video" ON "video"."id" = "videoAbuse"."videoId" ' + | |
201 | 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' + | |
efa012ed | 202 | 'INNER JOIN "account" ON ' + |
d95d1559 C |
203 | '"videoChannel"."accountId" = "VideoAbuse->Video->VideoChannel"."accountId" ' + |
204 | `OR "videoChannel"."accountId" = CAST("VideoAbuse"."deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) ` + | |
efa012ed RK |
205 | ')' |
206 | ), | |
207 | 'countReportsForReportee__video' | |
208 | ], | |
209 | [ | |
210 | literal( | |
211 | '(' + | |
212 | 'SELECT count(DISTINCT "videoAbuse"."id") ' + | |
213 | 'FROM "videoAbuse" ' + | |
d95d1559 | 214 | `WHERE CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = "VideoAbuse->Video->VideoChannel"."accountId" ` + |
197876ea | 215 | `OR CAST("deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) = ` + |
d95d1559 | 216 | `CAST("VideoAbuse"."deletedVideo"->'channel'->'ownerAccount'->>'id' AS INTEGER) ` + |
5fd4ca00 RK |
217 | ')' |
218 | ), | |
efa012ed | 219 | 'countReportsForReportee__deletedVideo' |
5fd4ca00 RK |
220 | ] |
221 | ] | |
222 | }, | |
86521a67 RK |
223 | include: [ |
224 | { | |
d95d1559 C |
225 | model: AccountModel.scope(AccountScopeNames.SUMMARY), |
226 | as: 'ReporterAccount', | |
844db39e | 227 | required: true, |
0251197e | 228 | where: searchAttribute(options.searchReporter, 'name') |
86521a67 RK |
229 | }, |
230 | { | |
d95d1559 C |
231 | model: AccountModel.scope(AccountScopeNames.SUMMARY), |
232 | as: 'FlaggedAccount', | |
233 | required: true, | |
234 | where: searchAttribute(options.searchReportee, 'name') | |
235 | }, | |
57f6896f C |
236 | { |
237 | model: VideoCommentAbuseModel.unscoped(), | |
238 | required: options.filter === 'comment', | |
239 | include: [ | |
240 | { | |
241 | model: VideoCommentModel.unscoped(), | |
242 | required: false, | |
243 | include: [ | |
244 | { | |
245 | model: VideoModel.unscoped(), | |
246 | attributes: [ 'name', 'id', 'uuid' ], | |
247 | required: true | |
248 | } | |
249 | ] | |
250 | } | |
251 | ] | |
252 | }, | |
d95d1559 C |
253 | { |
254 | model: VideoAbuseModel, | |
255 | required: options.filter === 'video' || !!options.videoIs || videoRequired, | |
86521a67 RK |
256 | include: [ |
257 | { | |
d95d1559 C |
258 | model: VideoModel, |
259 | required: videoRequired, | |
260 | where: searchAttribute(options.searchVideo, 'name'), | |
0d3a2982 RK |
261 | include: [ |
262 | { | |
d95d1559 C |
263 | model: ThumbnailModel |
264 | }, | |
265 | { | |
266 | model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: false } as SummaryOptions ] }), | |
267 | where: searchAttribute(options.searchVideoChannel, 'name'), | |
268 | required: true, | |
269 | include: [ | |
270 | { | |
271 | model: AccountModel.scope(AccountScopeNames.SUMMARY), | |
57f6896f | 272 | required: true |
d95d1559 C |
273 | } |
274 | ] | |
275 | }, | |
276 | { | |
277 | attributes: [ 'id', 'reason', 'unfederated' ], | |
278 | model: VideoBlacklistModel, | |
279 | required: onlyBlacklisted | |
0d3a2982 RK |
280 | } |
281 | ] | |
86521a67 RK |
282 | } |
283 | ] | |
86521a67 | 284 | } |
844db39e | 285 | ], |
57f6896f C |
286 | where: { |
287 | [Op.and]: whereAnd | |
288 | } | |
86521a67 | 289 | } |
844db39e | 290 | } |
86521a67 | 291 | })) |
3fd3ab2d | 292 | @Table({ |
d95d1559 | 293 | tableName: 'abuse', |
3fd3ab2d | 294 | indexes: [ |
55fa55a9 | 295 | { |
d95d1559 | 296 | fields: [ 'reporterAccountId' ] |
55fa55a9 C |
297 | }, |
298 | { | |
d95d1559 | 299 | fields: [ 'flaggedAccountId' ] |
55fa55a9 | 300 | } |
e02643f3 | 301 | ] |
3fd3ab2d | 302 | }) |
d95d1559 | 303 | export class AbuseModel extends Model<AbuseModel> { |
e02643f3 | 304 | |
3fd3ab2d | 305 | @AllowNull(false) |
1506307f | 306 | @Default(null) |
d95d1559 C |
307 | @Is('VideoAbuseReason', value => throwIfNotValid(value, isAbuseReasonValid, 'reason')) |
308 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.REASON.max)) | |
3fd3ab2d | 309 | reason: string |
21e0727a | 310 | |
268eebed C |
311 | @AllowNull(false) |
312 | @Default(null) | |
d95d1559 | 313 | @Is('VideoAbuseState', value => throwIfNotValid(value, isAbuseStateValid, 'state')) |
268eebed | 314 | @Column |
d95d1559 | 315 | state: AbuseState |
268eebed C |
316 | |
317 | @AllowNull(true) | |
318 | @Default(null) | |
d95d1559 C |
319 | @Is('VideoAbuseModerationComment', value => throwIfNotValid(value, isAbuseModerationCommentValid, 'moderationComment', true)) |
320 | @Column(DataType.STRING(CONSTRAINTS_FIELDS.ABUSES.MODERATION_COMMENT.max)) | |
268eebed C |
321 | moderationComment: string |
322 | ||
1ebddadd RK |
323 | @AllowNull(true) |
324 | @Default(null) | |
325 | @Column(DataType.ARRAY(DataType.INTEGER)) | |
d95d1559 | 326 | predefinedReasons: AbusePredefinedReasons[] |
1ebddadd | 327 | |
3fd3ab2d C |
328 | @CreatedAt |
329 | createdAt: Date | |
21e0727a | 330 | |
3fd3ab2d C |
331 | @UpdatedAt |
332 | updatedAt: Date | |
e02643f3 | 333 | |
3fd3ab2d C |
334 | @ForeignKey(() => AccountModel) |
335 | @Column | |
336 | reporterAccountId: number | |
55fa55a9 | 337 | |
3fd3ab2d | 338 | @BelongsTo(() => AccountModel, { |
55fa55a9 | 339 | foreignKey: { |
d95d1559 | 340 | name: 'reporterAccountId', |
68d19a0a | 341 | allowNull: true |
55fa55a9 | 342 | }, |
d95d1559 | 343 | as: 'ReporterAccount', |
68d19a0a | 344 | onDelete: 'set null' |
55fa55a9 | 345 | }) |
d95d1559 | 346 | ReporterAccount: AccountModel |
3fd3ab2d | 347 | |
d95d1559 | 348 | @ForeignKey(() => AccountModel) |
3fd3ab2d | 349 | @Column |
d95d1559 | 350 | flaggedAccountId: number |
55fa55a9 | 351 | |
d95d1559 | 352 | @BelongsTo(() => AccountModel, { |
55fa55a9 | 353 | foreignKey: { |
d95d1559 | 354 | name: 'flaggedAccountId', |
68d19a0a | 355 | allowNull: true |
55fa55a9 | 356 | }, |
d95d1559 | 357 | as: 'FlaggedAccount', |
68d19a0a | 358 | onDelete: 'set null' |
55fa55a9 | 359 | }) |
d95d1559 C |
360 | FlaggedAccount: AccountModel |
361 | ||
362 | @HasOne(() => VideoCommentAbuseModel, { | |
363 | foreignKey: { | |
364 | name: 'abuseId', | |
365 | allowNull: false | |
366 | }, | |
367 | onDelete: 'cascade' | |
368 | }) | |
369 | VideoCommentAbuse: VideoCommentAbuseModel | |
3fd3ab2d | 370 | |
d95d1559 C |
371 | @HasOne(() => VideoAbuseModel, { |
372 | foreignKey: { | |
373 | name: 'abuseId', | |
374 | allowNull: false | |
375 | }, | |
376 | onDelete: 'cascade' | |
377 | }) | |
378 | VideoAbuse: VideoAbuseModel | |
379 | ||
57f6896f | 380 | // FIXME: deprecated in 2.3. Remove these validators |
d95d1559 C |
381 | static loadByIdAndVideoId (id: number, videoId?: number, uuid?: string): Bluebird<MAbuse> { |
382 | const videoWhere: WhereOptions = {} | |
383 | ||
384 | if (videoId) videoWhere.videoId = videoId | |
385 | if (uuid) videoWhere.deletedVideo = { uuid } | |
68d19a0a | 386 | |
268eebed | 387 | const query = { |
d95d1559 C |
388 | include: [ |
389 | { | |
390 | model: VideoAbuseModel, | |
391 | required: true, | |
392 | where: videoWhere | |
393 | } | |
394 | ], | |
268eebed | 395 | where: { |
d95d1559 | 396 | id |
268eebed C |
397 | } |
398 | } | |
d95d1559 | 399 | return AbuseModel.findOne(query) |
268eebed C |
400 | } |
401 | ||
57f6896f C |
402 | static loadById (id: number): Bluebird<MAbuse> { |
403 | const query = { | |
404 | where: { | |
405 | id | |
406 | } | |
407 | } | |
408 | ||
409 | return AbuseModel.findOne(query) | |
410 | } | |
411 | ||
f0a47bc9 | 412 | static listForApi (parameters: { |
a1587156 C |
413 | start: number |
414 | count: number | |
415 | sort: string | |
feb34f6b | 416 | |
d95d1559 C |
417 | filter?: AbuseFilter |
418 | ||
f0a47bc9 C |
419 | serverAccountId: number |
420 | user?: MUserAccountId | |
feb34f6b C |
421 | |
422 | id?: number | |
d95d1559 C |
423 | predefinedReason?: AbusePredefinedReasonsString |
424 | state?: AbuseState | |
425 | videoIs?: AbuseVideoIs | |
feb34f6b C |
426 | |
427 | search?: string | |
428 | searchReporter?: string | |
429 | searchReportee?: string | |
430 | searchVideo?: string | |
431 | searchVideoChannel?: string | |
f0a47bc9 | 432 | }) { |
feb34f6b C |
433 | const { |
434 | start, | |
435 | count, | |
436 | sort, | |
437 | search, | |
438 | user, | |
439 | serverAccountId, | |
440 | state, | |
441 | videoIs, | |
1ebddadd | 442 | predefinedReason, |
feb34f6b C |
443 | searchReportee, |
444 | searchVideo, | |
d95d1559 | 445 | filter, |
feb34f6b C |
446 | searchVideoChannel, |
447 | searchReporter, | |
448 | id | |
449 | } = parameters | |
450 | ||
f0a47bc9 | 451 | const userAccountId = user ? user.Account.id : undefined |
d95d1559 | 452 | const predefinedReasonId = predefinedReason ? abusePredefinedReasonsMap[predefinedReason] : undefined |
f0a47bc9 | 453 | |
3fd3ab2d C |
454 | const query = { |
455 | offset: start, | |
456 | limit: count, | |
3bb6c526 | 457 | order: getSort(sort), |
d95d1559 | 458 | col: 'AbuseModel.id', |
86521a67 | 459 | distinct: true |
3fd3ab2d | 460 | } |
55fa55a9 | 461 | |
844db39e | 462 | const filters = { |
feb34f6b | 463 | id, |
d95d1559 | 464 | filter, |
1ebddadd | 465 | predefinedReasonId, |
feb34f6b C |
466 | search, |
467 | state, | |
468 | videoIs, | |
469 | searchReportee, | |
470 | searchVideo, | |
471 | searchVideoChannel, | |
472 | searchReporter, | |
844db39e RK |
473 | serverAccountId, |
474 | userAccountId | |
475 | } | |
476 | ||
d95d1559 | 477 | return AbuseModel |
1ebddadd RK |
478 | .scope([ |
479 | { method: [ ScopeNames.FOR_API, filters ] } | |
480 | ]) | |
844db39e | 481 | .findAndCountAll(query) |
3fd3ab2d C |
482 | .then(({ rows, count }) => { |
483 | return { total: count, data: rows } | |
484 | }) | |
55fa55a9 C |
485 | } |
486 | ||
d95d1559 C |
487 | toFormattedJSON (this: MAbuseFormattable): Abuse { |
488 | const predefinedReasons = AbuseModel.getPredefinedReasonsStrings(this.predefinedReasons) | |
5fd4ca00 RK |
489 | const countReportsForVideo = this.get('countReportsForVideo') as number |
490 | const nthReportForVideo = this.get('nthReportForVideo') as number | |
efa012ed RK |
491 | const countReportsForReporterVideo = this.get('countReportsForReporter__video') as number |
492 | const countReportsForReporterDeletedVideo = this.get('countReportsForReporter__deletedVideo') as number | |
493 | const countReportsForReporteeVideo = this.get('countReportsForReportee__video') as number | |
494 | const countReportsForReporteeDeletedVideo = this.get('countReportsForReportee__deletedVideo') as number | |
5fd4ca00 | 495 | |
d95d1559 | 496 | let video: VideoAbuse |
57f6896f | 497 | let comment: VideoCommentAbuse |
d95d1559 C |
498 | |
499 | if (this.VideoAbuse) { | |
500 | const abuseModel = this.VideoAbuse | |
501 | const entity = abuseModel.Video || abuseModel.deletedVideo | |
502 | ||
503 | video = { | |
504 | id: entity.id, | |
505 | uuid: entity.uuid, | |
506 | name: entity.name, | |
507 | nsfw: entity.nsfw, | |
508 | ||
509 | startAt: abuseModel.startAt, | |
510 | endAt: abuseModel.endAt, | |
511 | ||
512 | deleted: !abuseModel.Video, | |
513 | blacklisted: abuseModel.Video?.isBlacklisted() || false, | |
514 | thumbnailPath: abuseModel.Video?.getMiniatureStaticPath(), | |
515 | channel: abuseModel.Video?.VideoChannel.toFormattedJSON() || abuseModel.deletedVideo?.channel | |
516 | } | |
517 | } | |
68d19a0a | 518 | |
57f6896f C |
519 | if (this.VideoCommentAbuse) { |
520 | const abuseModel = this.VideoCommentAbuse | |
521 | const entity = abuseModel.VideoComment || abuseModel.deletedComment | |
522 | ||
523 | comment = { | |
524 | id: entity.id, | |
525 | text: entity.text, | |
526 | ||
527 | deleted: !abuseModel.VideoComment, | |
528 | ||
529 | video: { | |
530 | id: entity.Video.id, | |
531 | name: entity.Video.name, | |
532 | uuid: entity.Video.uuid | |
533 | } | |
534 | } | |
535 | } | |
536 | ||
3fd3ab2d C |
537 | return { |
538 | id: this.id, | |
539 | reason: this.reason, | |
1ebddadd | 540 | predefinedReasons, |
d95d1559 C |
541 | |
542 | reporterAccount: this.ReporterAccount.toFormattedJSON(), | |
543 | ||
268eebed C |
544 | state: { |
545 | id: this.state, | |
d95d1559 | 546 | label: AbuseModel.getStateLabel(this.state) |
268eebed | 547 | }, |
d95d1559 | 548 | |
268eebed | 549 | moderationComment: this.moderationComment, |
d95d1559 C |
550 | |
551 | video, | |
57f6896f | 552 | comment, |
d95d1559 | 553 | |
5fd4ca00 RK |
554 | createdAt: this.createdAt, |
555 | updatedAt: this.updatedAt, | |
556 | count: countReportsForVideo || 0, | |
557 | nth: nthReportForVideo || 0, | |
efa012ed | 558 | countReportsForReporter: (countReportsForReporterVideo || 0) + (countReportsForReporterDeletedVideo || 0), |
d95d1559 C |
559 | countReportsForReportee: (countReportsForReporteeVideo || 0) + (countReportsForReporteeDeletedVideo || 0), |
560 | ||
561 | // FIXME: deprecated in 2.3, remove this | |
562 | startAt: null, | |
563 | endAt: null | |
3fd3ab2d C |
564 | } |
565 | } | |
566 | ||
d95d1559 C |
567 | toActivityPubObject (this: MAbuseAP): AbuseObject { |
568 | const predefinedReasons = AbuseModel.getPredefinedReasonsStrings(this.predefinedReasons) | |
569 | ||
570 | const object = this.VideoAbuse?.Video?.url || this.VideoCommentAbuse?.VideoComment?.url || this.FlaggedAccount.Actor.url | |
1ebddadd | 571 | |
d95d1559 C |
572 | const startAt = this.VideoAbuse?.startAt |
573 | const endAt = this.VideoAbuse?.endAt | |
1ebddadd | 574 | |
3fd3ab2d C |
575 | return { |
576 | type: 'Flag' as 'Flag', | |
577 | content: this.reason, | |
d95d1559 | 578 | object, |
1ebddadd RK |
579 | tag: predefinedReasons.map(r => ({ |
580 | type: 'Hashtag' as 'Hashtag', | |
581 | name: r | |
582 | })), | |
583 | startAt, | |
584 | endAt | |
3fd3ab2d C |
585 | } |
586 | } | |
268eebed C |
587 | |
588 | private static getStateLabel (id: number) { | |
d95d1559 | 589 | return ABUSE_STATES[id] || 'Unknown' |
268eebed | 590 | } |
1ebddadd | 591 | |
d95d1559 | 592 | private static getPredefinedReasonsStrings (predefinedReasons: AbusePredefinedReasons[]): AbusePredefinedReasonsString[] { |
1ebddadd | 593 | return (predefinedReasons || []) |
d95d1559 C |
594 | .filter(r => r in AbusePredefinedReasons) |
595 | .map(r => invert(abusePredefinedReasonsMap)[r] as AbusePredefinedReasonsString) | |
1ebddadd | 596 | } |
55fa55a9 | 597 | } |