aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/video-abuse.ts
diff options
context:
space:
mode:
authorRigel Kent <sendmemail@rigelk.eu>2020-06-22 13:00:39 +0200
committerGitHub <noreply@github.com>2020-06-22 13:00:39 +0200
commit1ebddadd0704812a4600c39cabe2268321e88331 (patch)
tree1cc8560e5b63e9976aa5411ba800a62cfe7b8ea9 /server/models/video/video-abuse.ts
parent07aea1a2642fc9868cb01e30c322514029d5b95a (diff)
downloadPeerTube-1ebddadd0704812a4600c39cabe2268321e88331.tar.gz
PeerTube-1ebddadd0704812a4600c39cabe2268321e88331.tar.zst
PeerTube-1ebddadd0704812a4600c39cabe2268321e88331.zip
predefined report reasons & improved reporter UI (#2842)
- added `startAt` and `endAt` optional timestamps to help pin down reported sections of a video - added predefined report reasons - added video player with report modal
Diffstat (limited to 'server/models/video/video-abuse.ts')
-rw-r--r--server/models/video/video-abuse.ts64
1 files changed, 61 insertions, 3 deletions
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts
index b2f111337..1319332f0 100644
--- a/server/models/video/video-abuse.ts
+++ b/server/models/video/video-abuse.ts
@@ -15,7 +15,13 @@ import {
15 UpdatedAt 15 UpdatedAt
16} from 'sequelize-typescript' 16} from 'sequelize-typescript'
17import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type' 17import { VideoAbuseVideoIs } from '@shared/models/videos/abuse/video-abuse-video-is.type'
18import { VideoAbuseState, VideoDetails } from '../../../shared' 18import {
19 VideoAbuseState,
20 VideoDetails,
21 VideoAbusePredefinedReasons,
22 VideoAbusePredefinedReasonsString,
23 videoAbusePredefinedReasonsMap
24} from '../../../shared'
19import { VideoAbuseObject } from '../../../shared/models/activitypub/objects' 25import { VideoAbuseObject } from '../../../shared/models/activitypub/objects'
20import { VideoAbuse } from '../../../shared/models/videos' 26import { VideoAbuse } from '../../../shared/models/videos'
21import { 27import {
@@ -31,6 +37,7 @@ import { ThumbnailModel } from './thumbnail'
31import { VideoModel } from './video' 37import { VideoModel } from './video'
32import { VideoBlacklistModel } from './video-blacklist' 38import { VideoBlacklistModel } from './video-blacklist'
33import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel' 39import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel'
40import { invert } from 'lodash'
34 41
35export enum ScopeNames { 42export enum ScopeNames {
36 FOR_API = 'FOR_API' 43 FOR_API = 'FOR_API'
@@ -47,6 +54,7 @@ export enum ScopeNames {
47 54
48 // filters 55 // filters
49 id?: number 56 id?: number
57 predefinedReasonId?: number
50 58
51 state?: VideoAbuseState 59 state?: VideoAbuseState
52 videoIs?: VideoAbuseVideoIs 60 videoIs?: VideoAbuseVideoIs
@@ -104,6 +112,14 @@ export enum ScopeNames {
104 }) 112 })
105 } 113 }
106 114
115 if (options.predefinedReasonId) {
116 Object.assign(where, {
117 predefinedReasons: {
118 [Op.contains]: [ options.predefinedReasonId ]
119 }
120 })
121 }
122
107 const onlyBlacklisted = options.videoIs === 'blacklisted' 123 const onlyBlacklisted = options.videoIs === 'blacklisted'
108 124
109 return { 125 return {
@@ -258,6 +274,21 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
258 @Column(DataType.JSONB) 274 @Column(DataType.JSONB)
259 deletedVideo: VideoDetails 275 deletedVideo: VideoDetails
260 276
277 @AllowNull(true)
278 @Default(null)
279 @Column(DataType.ARRAY(DataType.INTEGER))
280 predefinedReasons: VideoAbusePredefinedReasons[]
281
282 @AllowNull(true)
283 @Default(null)
284 @Column
285 startAt: number
286
287 @AllowNull(true)
288 @Default(null)
289 @Column
290 endAt: number
291
261 @CreatedAt 292 @CreatedAt
262 createdAt: Date 293 createdAt: Date
263 294
@@ -311,6 +342,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
311 user?: MUserAccountId 342 user?: MUserAccountId
312 343
313 id?: number 344 id?: number
345 predefinedReason?: VideoAbusePredefinedReasonsString
314 state?: VideoAbuseState 346 state?: VideoAbuseState
315 videoIs?: VideoAbuseVideoIs 347 videoIs?: VideoAbuseVideoIs
316 348
@@ -329,6 +361,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
329 serverAccountId, 361 serverAccountId,
330 state, 362 state,
331 videoIs, 363 videoIs,
364 predefinedReason,
332 searchReportee, 365 searchReportee,
333 searchVideo, 366 searchVideo,
334 searchVideoChannel, 367 searchVideoChannel,
@@ -337,6 +370,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
337 } = parameters 370 } = parameters
338 371
339 const userAccountId = user ? user.Account.id : undefined 372 const userAccountId = user ? user.Account.id : undefined
373 const predefinedReasonId = predefinedReason ? videoAbusePredefinedReasonsMap[predefinedReason] : undefined
340 374
341 const query = { 375 const query = {
342 offset: start, 376 offset: start,
@@ -348,6 +382,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
348 382
349 const filters = { 383 const filters = {
350 id, 384 id,
385 predefinedReasonId,
351 search, 386 search,
352 state, 387 state,
353 videoIs, 388 videoIs,
@@ -360,7 +395,9 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
360 } 395 }
361 396
362 return VideoAbuseModel 397 return VideoAbuseModel
363 .scope({ method: [ ScopeNames.FOR_API, filters ] }) 398 .scope([
399 { method: [ ScopeNames.FOR_API, filters ] }
400 ])
364 .findAndCountAll(query) 401 .findAndCountAll(query)
365 .then(({ rows, count }) => { 402 .then(({ rows, count }) => {
366 return { total: count, data: rows } 403 return { total: count, data: rows }
@@ -368,6 +405,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
368 } 405 }
369 406
370 toFormattedJSON (this: MVideoAbuseFormattable): VideoAbuse { 407 toFormattedJSON (this: MVideoAbuseFormattable): VideoAbuse {
408 const predefinedReasons = VideoAbuseModel.getPredefinedReasonsStrings(this.predefinedReasons)
371 const countReportsForVideo = this.get('countReportsForVideo') as number 409 const countReportsForVideo = this.get('countReportsForVideo') as number
372 const nthReportForVideo = this.get('nthReportForVideo') as number 410 const nthReportForVideo = this.get('nthReportForVideo') as number
373 const countReportsForReporterVideo = this.get('countReportsForReporter__video') as number 411 const countReportsForReporterVideo = this.get('countReportsForReporter__video') as number
@@ -382,6 +420,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
382 return { 420 return {
383 id: this.id, 421 id: this.id,
384 reason: this.reason, 422 reason: this.reason,
423 predefinedReasons,
385 reporterAccount: this.Account.toFormattedJSON(), 424 reporterAccount: this.Account.toFormattedJSON(),
386 state: { 425 state: {
387 id: this.state, 426 id: this.state,
@@ -400,6 +439,8 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
400 }, 439 },
401 createdAt: this.createdAt, 440 createdAt: this.createdAt,
402 updatedAt: this.updatedAt, 441 updatedAt: this.updatedAt,
442 startAt: this.startAt,
443 endAt: this.endAt,
403 count: countReportsForVideo || 0, 444 count: countReportsForVideo || 0,
404 nth: nthReportForVideo || 0, 445 nth: nthReportForVideo || 0,
405 countReportsForReporter: (countReportsForReporterVideo || 0) + (countReportsForReporterDeletedVideo || 0), 446 countReportsForReporter: (countReportsForReporterVideo || 0) + (countReportsForReporterDeletedVideo || 0),
@@ -408,14 +449,31 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
408 } 449 }
409 450
410 toActivityPubObject (this: MVideoAbuseVideo): VideoAbuseObject { 451 toActivityPubObject (this: MVideoAbuseVideo): VideoAbuseObject {
452 const predefinedReasons = VideoAbuseModel.getPredefinedReasonsStrings(this.predefinedReasons)
453
454 const startAt = this.startAt
455 const endAt = this.endAt
456
411 return { 457 return {
412 type: 'Flag' as 'Flag', 458 type: 'Flag' as 'Flag',
413 content: this.reason, 459 content: this.reason,
414 object: this.Video.url 460 object: this.Video.url,
461 tag: predefinedReasons.map(r => ({
462 type: 'Hashtag' as 'Hashtag',
463 name: r
464 })),
465 startAt,
466 endAt
415 } 467 }
416 } 468 }
417 469
418 private static getStateLabel (id: number) { 470 private static getStateLabel (id: number) {
419 return VIDEO_ABUSE_STATES[id] || 'Unknown' 471 return VIDEO_ABUSE_STATES[id] || 'Unknown'
420 } 472 }
473
474 private static getPredefinedReasonsStrings (predefinedReasons: VideoAbusePredefinedReasons[]): VideoAbusePredefinedReasonsString[] {
475 return (predefinedReasons || [])
476 .filter(r => r in VideoAbusePredefinedReasons)
477 .map(r => invert(videoAbusePredefinedReasonsMap)[r] as VideoAbusePredefinedReasonsString)
478 }
421} 479}