diff options
author | Chocobozzz <me@florianbigard.com> | 2020-07-07 10:57:04 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2020-07-10 14:02:41 +0200 |
commit | 57f6896f67cfc570cf3605dd94b0778101b2d9b9 (patch) | |
tree | b82d879c46868ce75ff76c3e4d4eed590a87f6c4 /server/models | |
parent | d95d15598847c7f020aa056e7e6e0c02d2bbf732 (diff) | |
download | PeerTube-57f6896f67cfc570cf3605dd94b0778101b2d9b9.tar.gz PeerTube-57f6896f67cfc570cf3605dd94b0778101b2d9b9.tar.zst PeerTube-57f6896f67cfc570cf3605dd94b0778101b2d9b9.zip |
Implement abuses check params
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/abuse/abuse.ts | 91 | ||||
-rw-r--r-- | server/models/abuse/video-comment-abuse.ts | 2 | ||||
-rw-r--r-- | server/models/video/video-comment.ts | 65 | ||||
-rw-r--r-- | server/models/video/video.ts | 4 |
4 files changed, 142 insertions, 20 deletions
diff --git a/server/models/abuse/abuse.ts b/server/models/abuse/abuse.ts index 4f99f9c9b..087c77bd3 100644 --- a/server/models/abuse/abuse.ts +++ b/server/models/abuse/abuse.ts | |||
@@ -19,16 +19,17 @@ import { | |||
19 | import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses' | 19 | import { isAbuseModerationCommentValid, isAbuseReasonValid, isAbuseStateValid } from '@server/helpers/custom-validators/abuses' |
20 | import { | 20 | import { |
21 | Abuse, | 21 | Abuse, |
22 | AbuseFilter, | ||
22 | AbuseObject, | 23 | AbuseObject, |
23 | AbusePredefinedReasons, | 24 | AbusePredefinedReasons, |
24 | abusePredefinedReasonsMap, | 25 | abusePredefinedReasonsMap, |
25 | AbusePredefinedReasonsString, | 26 | AbusePredefinedReasonsString, |
26 | AbuseState, | 27 | AbuseState, |
27 | AbuseVideoIs, | 28 | AbuseVideoIs, |
28 | VideoAbuse | 29 | VideoAbuse, |
30 | VideoCommentAbuse | ||
29 | } from '@shared/models' | 31 | } from '@shared/models' |
30 | import { AbuseFilter } from '@shared/models/moderation/abuse/abuse-filter' | 32 | import { ABUSE_STATES, CONSTRAINTS_FIELDS } from '../../initializers/constants' |
31 | import { CONSTRAINTS_FIELDS, ABUSE_STATES } from '../../initializers/constants' | ||
32 | import { MAbuse, MAbuseAP, MAbuseFormattable, MUserAccountId } from '../../types/models' | 33 | import { MAbuse, MAbuseAP, MAbuseFormattable, MUserAccountId } from '../../types/models' |
33 | import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account' | 34 | import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account' |
34 | import { buildBlockedAccountSQL, getSort, searchAttribute, throwIfNotValid } from '../utils' | 35 | import { buildBlockedAccountSQL, getSort, searchAttribute, throwIfNotValid } from '../utils' |
@@ -38,6 +39,7 @@ import { VideoBlacklistModel } from '../video/video-blacklist' | |||
38 | import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel' | 39 | import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel' |
39 | import { VideoAbuseModel } from './video-abuse' | 40 | import { VideoAbuseModel } from './video-abuse' |
40 | import { VideoCommentAbuseModel } from './video-comment-abuse' | 41 | import { VideoCommentAbuseModel } from './video-comment-abuse' |
42 | import { VideoCommentModel } from '../video/video-comment' | ||
41 | 43 | ||
42 | export enum ScopeNames { | 44 | export enum ScopeNames { |
43 | FOR_API = 'FOR_API' | 45 | FOR_API = 'FOR_API' |
@@ -66,19 +68,18 @@ export enum ScopeNames { | |||
66 | serverAccountId: number | 68 | serverAccountId: number |
67 | userAccountId: number | 69 | userAccountId: number |
68 | }) => { | 70 | }) => { |
69 | const onlyBlacklisted = options.videoIs === 'blacklisted' | 71 | const whereAnd: WhereOptions[] = [] |
70 | const videoRequired = !!(onlyBlacklisted || options.searchVideo || options.searchVideoChannel) | ||
71 | 72 | ||
72 | const where = { | 73 | whereAnd.push({ |
73 | reporterAccountId: { | 74 | reporterAccountId: { |
74 | [Op.notIn]: literal('(' + buildBlockedAccountSQL([ options.serverAccountId, options.userAccountId ]) + ')') | 75 | [Op.notIn]: literal('(' + buildBlockedAccountSQL([ options.serverAccountId, options.userAccountId ]) + ')') |
75 | } | 76 | } |
76 | } | 77 | }) |
77 | 78 | ||
78 | if (options.search) { | 79 | if (options.search) { |
79 | const escapedSearch = AbuseModel.sequelize.escape('%' + options.search + '%') | 80 | const escapedSearch = AbuseModel.sequelize.escape('%' + options.search + '%') |
80 | 81 | ||
81 | Object.assign(where, { | 82 | whereAnd.push({ |
82 | [Op.or]: [ | 83 | [Op.or]: [ |
83 | { | 84 | { |
84 | [Op.and]: [ | 85 | [Op.and]: [ |
@@ -110,11 +111,11 @@ export enum ScopeNames { | |||
110 | }) | 111 | }) |
111 | } | 112 | } |
112 | 113 | ||
113 | if (options.id) Object.assign(where, { id: options.id }) | 114 | if (options.id) whereAnd.push({ id: options.id }) |
114 | if (options.state) Object.assign(where, { state: options.state }) | 115 | if (options.state) whereAnd.push({ state: options.state }) |
115 | 116 | ||
116 | if (options.videoIs === 'deleted') { | 117 | if (options.videoIs === 'deleted') { |
117 | Object.assign(where, { | 118 | whereAnd.push({ |
118 | '$VideoAbuse.deletedVideo$': { | 119 | '$VideoAbuse.deletedVideo$': { |
119 | [Op.not]: null | 120 | [Op.not]: null |
120 | } | 121 | } |
@@ -122,13 +123,23 @@ export enum ScopeNames { | |||
122 | } | 123 | } |
123 | 124 | ||
124 | if (options.predefinedReasonId) { | 125 | if (options.predefinedReasonId) { |
125 | Object.assign(where, { | 126 | whereAnd.push({ |
126 | predefinedReasons: { | 127 | predefinedReasons: { |
127 | [Op.contains]: [ options.predefinedReasonId ] | 128 | [Op.contains]: [ options.predefinedReasonId ] |
128 | } | 129 | } |
129 | }) | 130 | }) |
130 | } | 131 | } |
131 | 132 | ||
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 | |||
132 | return { | 143 | return { |
133 | attributes: { | 144 | attributes: { |
134 | include: [ | 145 | include: [ |
@@ -223,6 +234,23 @@ export enum ScopeNames { | |||
223 | where: searchAttribute(options.searchReportee, 'name') | 234 | where: searchAttribute(options.searchReportee, 'name') |
224 | }, | 235 | }, |
225 | { | 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 | }, | ||
253 | { | ||
226 | model: VideoAbuseModel, | 254 | model: VideoAbuseModel, |
227 | required: options.filter === 'video' || !!options.videoIs || videoRequired, | 255 | required: options.filter === 'video' || !!options.videoIs || videoRequired, |
228 | include: [ | 256 | include: [ |
@@ -241,8 +269,7 @@ export enum ScopeNames { | |||
241 | include: [ | 269 | include: [ |
242 | { | 270 | { |
243 | model: AccountModel.scope(AccountScopeNames.SUMMARY), | 271 | model: AccountModel.scope(AccountScopeNames.SUMMARY), |
244 | required: true, | 272 | required: true |
245 | where: searchAttribute(options.searchReportee, 'name') | ||
246 | } | 273 | } |
247 | ] | 274 | ] |
248 | }, | 275 | }, |
@@ -256,7 +283,9 @@ export enum ScopeNames { | |||
256 | ] | 283 | ] |
257 | } | 284 | } |
258 | ], | 285 | ], |
259 | where | 286 | where: { |
287 | [Op.and]: whereAnd | ||
288 | } | ||
260 | } | 289 | } |
261 | } | 290 | } |
262 | })) | 291 | })) |
@@ -348,6 +377,7 @@ export class AbuseModel extends Model<AbuseModel> { | |||
348 | }) | 377 | }) |
349 | VideoAbuse: VideoAbuseModel | 378 | VideoAbuse: VideoAbuseModel |
350 | 379 | ||
380 | // FIXME: deprecated in 2.3. Remove these validators | ||
351 | static loadByIdAndVideoId (id: number, videoId?: number, uuid?: string): Bluebird<MAbuse> { | 381 | static loadByIdAndVideoId (id: number, videoId?: number, uuid?: string): Bluebird<MAbuse> { |
352 | const videoWhere: WhereOptions = {} | 382 | const videoWhere: WhereOptions = {} |
353 | 383 | ||
@@ -369,6 +399,16 @@ export class AbuseModel extends Model<AbuseModel> { | |||
369 | return AbuseModel.findOne(query) | 399 | return AbuseModel.findOne(query) |
370 | } | 400 | } |
371 | 401 | ||
402 | static loadById (id: number): Bluebird<MAbuse> { | ||
403 | const query = { | ||
404 | where: { | ||
405 | id | ||
406 | } | ||
407 | } | ||
408 | |||
409 | return AbuseModel.findOne(query) | ||
410 | } | ||
411 | |||
372 | static listForApi (parameters: { | 412 | static listForApi (parameters: { |
373 | start: number | 413 | start: number |
374 | count: number | 414 | count: number |
@@ -454,6 +494,7 @@ export class AbuseModel extends Model<AbuseModel> { | |||
454 | const countReportsForReporteeDeletedVideo = this.get('countReportsForReportee__deletedVideo') as number | 494 | const countReportsForReporteeDeletedVideo = this.get('countReportsForReportee__deletedVideo') as number |
455 | 495 | ||
456 | let video: VideoAbuse | 496 | let video: VideoAbuse |
497 | let comment: VideoCommentAbuse | ||
457 | 498 | ||
458 | if (this.VideoAbuse) { | 499 | if (this.VideoAbuse) { |
459 | const abuseModel = this.VideoAbuse | 500 | const abuseModel = this.VideoAbuse |
@@ -475,6 +516,24 @@ export class AbuseModel extends Model<AbuseModel> { | |||
475 | } | 516 | } |
476 | } | 517 | } |
477 | 518 | ||
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 | |||
478 | return { | 537 | return { |
479 | id: this.id, | 538 | id: this.id, |
480 | reason: this.reason, | 539 | reason: this.reason, |
@@ -490,7 +549,7 @@ export class AbuseModel extends Model<AbuseModel> { | |||
490 | moderationComment: this.moderationComment, | 549 | moderationComment: this.moderationComment, |
491 | 550 | ||
492 | video, | 551 | video, |
493 | comment: null, | 552 | comment, |
494 | 553 | ||
495 | createdAt: this.createdAt, | 554 | createdAt: this.createdAt, |
496 | updatedAt: this.updatedAt, | 555 | updatedAt: this.updatedAt, |
diff --git a/server/models/abuse/video-comment-abuse.ts b/server/models/abuse/video-comment-abuse.ts index b4cc2762e..de9f4d5fd 100644 --- a/server/models/abuse/video-comment-abuse.ts +++ b/server/models/abuse/video-comment-abuse.ts | |||
@@ -25,7 +25,7 @@ export class VideoCommentAbuseModel extends Model<VideoCommentAbuseModel> { | |||
25 | @AllowNull(true) | 25 | @AllowNull(true) |
26 | @Default(null) | 26 | @Default(null) |
27 | @Column(DataType.JSONB) | 27 | @Column(DataType.JSONB) |
28 | deletedComment: VideoComment | 28 | deletedComment: VideoComment & { Video: { name: string, id: number, uuid: string }} |
29 | 29 | ||
30 | @ForeignKey(() => AbuseModel) | 30 | @ForeignKey(() => AbuseModel) |
31 | @Column | 31 | @Column |
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index 90625d987..fb6078ed8 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -1,7 +1,22 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { uniq } from 'lodash' | 2 | import { uniq } from 'lodash' |
3 | import { FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction } from 'sequelize' | 3 | import { FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction } from 'sequelize' |
4 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript' | 4 | import { |
5 | AllowNull, | ||
6 | BeforeDestroy, | ||
7 | BelongsTo, | ||
8 | Column, | ||
9 | CreatedAt, | ||
10 | DataType, | ||
11 | ForeignKey, | ||
12 | HasMany, | ||
13 | Is, | ||
14 | Model, | ||
15 | Scopes, | ||
16 | Table, | ||
17 | UpdatedAt | ||
18 | } from 'sequelize-typescript' | ||
19 | import { logger } from '@server/helpers/logger' | ||
5 | import { getServerActor } from '@server/models/application/application' | 20 | import { getServerActor } from '@server/models/application/application' |
6 | import { MAccount, MAccountId, MUserAccountId } from '@server/types/models' | 21 | import { MAccount, MAccountId, MUserAccountId } from '@server/types/models' |
7 | import { VideoPrivacy } from '@shared/models' | 22 | import { VideoPrivacy } from '@shared/models' |
@@ -24,6 +39,7 @@ import { | |||
24 | MCommentOwnerVideoReply, | 39 | MCommentOwnerVideoReply, |
25 | MVideoImmutable | 40 | MVideoImmutable |
26 | } from '../../types/models/video' | 41 | } from '../../types/models/video' |
42 | import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse' | ||
27 | import { AccountModel } from '../account/account' | 43 | import { AccountModel } from '../account/account' |
28 | import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor' | 44 | import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor' |
29 | import { buildBlockedAccountSQL, buildLocalAccountIdsIn, getCommentSort, throwIfNotValid } from '../utils' | 45 | import { buildBlockedAccountSQL, buildLocalAccountIdsIn, getCommentSort, throwIfNotValid } from '../utils' |
@@ -224,6 +240,53 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
224 | }) | 240 | }) |
225 | Account: AccountModel | 241 | Account: AccountModel |
226 | 242 | ||
243 | @HasMany(() => VideoCommentAbuseModel, { | ||
244 | foreignKey: { | ||
245 | name: 'commentId', | ||
246 | allowNull: true | ||
247 | }, | ||
248 | onDelete: 'set null' | ||
249 | }) | ||
250 | CommentAbuses: VideoCommentAbuseModel[] | ||
251 | |||
252 | @BeforeDestroy | ||
253 | static async saveEssentialDataToAbuses (instance: VideoCommentModel, options) { | ||
254 | const tasks: Promise<any>[] = [] | ||
255 | |||
256 | if (!Array.isArray(instance.CommentAbuses)) { | ||
257 | instance.CommentAbuses = await instance.$get('CommentAbuses') | ||
258 | |||
259 | if (instance.CommentAbuses.length === 0) return undefined | ||
260 | } | ||
261 | |||
262 | if (!instance.Video) { | ||
263 | instance.Video = await instance.$get('Video') | ||
264 | } | ||
265 | |||
266 | logger.info('Saving video comment %s for abuse.', instance.url) | ||
267 | |||
268 | const details = Object.assign(instance.toFormattedJSON(), { | ||
269 | Video: { | ||
270 | id: instance.Video.id, | ||
271 | name: instance.Video.name, | ||
272 | uuid: instance.Video.uuid | ||
273 | } | ||
274 | }) | ||
275 | |||
276 | for (const abuse of instance.CommentAbuses) { | ||
277 | abuse.deletedComment = details | ||
278 | |||
279 | tasks.push(abuse.save({ transaction: options.transaction })) | ||
280 | } | ||
281 | |||
282 | Promise.all(tasks) | ||
283 | .catch(err => { | ||
284 | logger.error('Some errors when saving details of comment %s in its abuses before destroy hook.', instance.url, { err }) | ||
285 | }) | ||
286 | |||
287 | return undefined | ||
288 | } | ||
289 | |||
227 | static loadById (id: number, t?: Transaction): Bluebird<MComment> { | 290 | static loadById (id: number, t?: Transaction): Bluebird<MComment> { |
228 | const query: FindOptions = { | 291 | const query: FindOptions = { |
229 | where: { | 292 | where: { |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 272bba0e1..43609587c 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -803,14 +803,14 @@ export class VideoModel extends Model<VideoModel> { | |||
803 | static async saveEssentialDataToAbuses (instance: VideoModel, options) { | 803 | static async saveEssentialDataToAbuses (instance: VideoModel, options) { |
804 | const tasks: Promise<any>[] = [] | 804 | const tasks: Promise<any>[] = [] |
805 | 805 | ||
806 | logger.info('Saving video abuses details of video %s.', instance.url) | ||
807 | |||
808 | if (!Array.isArray(instance.VideoAbuses)) { | 806 | if (!Array.isArray(instance.VideoAbuses)) { |
809 | instance.VideoAbuses = await instance.$get('VideoAbuses') | 807 | instance.VideoAbuses = await instance.$get('VideoAbuses') |
810 | 808 | ||
811 | if (instance.VideoAbuses.length === 0) return undefined | 809 | if (instance.VideoAbuses.length === 0) return undefined |
812 | } | 810 | } |
813 | 811 | ||
812 | logger.info('Saving video abuses details of video %s.', instance.url) | ||
813 | |||
814 | const details = instance.toFormattedDetailsJSON() | 814 | const details = instance.toFormattedDetailsJSON() |
815 | 815 | ||
816 | for (const abuse of instance.VideoAbuses) { | 816 | for (const abuse of instance.VideoAbuses) { |