]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/models/video/video-abuse.ts
ea985621317a5b9d142df807c4a1c653193b06a4
[github/Chocobozzz/PeerTube.git] / server / models / video / video-abuse.ts
1 import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
2 import { VideoAbuseObject } from '../../../shared/models/activitypub/objects'
3 import { VideoAbuse } from '../../../shared/models/videos'
4 import {
5 isVideoAbuseModerationCommentValid,
6 isVideoAbuseReasonValid,
7 isVideoAbuseStateValid
8 } from '../../helpers/custom-validators/video-abuses'
9 import { AccountModel } from '../account/account'
10 import { buildBlockedAccountSQL, getSort, throwIfNotValid } from '../utils'
11 import { VideoModel } from './video'
12 import { VideoAbuseState, Video } from '../../../shared'
13 import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants'
14 import { MUserAccountId, MVideoAbuse, MVideoAbuseFormattable, MVideoAbuseVideo } from '../../typings/models'
15 import * as Bluebird from 'bluebird'
16 import { literal, Op } from 'sequelize'
17
18 @Table({
19 tableName: 'videoAbuse',
20 indexes: [
21 {
22 fields: [ 'videoId' ]
23 },
24 {
25 fields: [ 'reporterAccountId' ]
26 }
27 ]
28 })
29 export class VideoAbuseModel extends Model<VideoAbuseModel> {
30
31 @AllowNull(false)
32 @Default(null)
33 @Is('VideoAbuseReason', value => throwIfNotValid(value, isVideoAbuseReasonValid, 'reason'))
34 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_ABUSES.REASON.max))
35 reason: string
36
37 @AllowNull(false)
38 @Default(null)
39 @Is('VideoAbuseState', value => throwIfNotValid(value, isVideoAbuseStateValid, 'state'))
40 @Column
41 state: VideoAbuseState
42
43 @AllowNull(true)
44 @Default(null)
45 @Is('VideoAbuseModerationComment', value => throwIfNotValid(value, isVideoAbuseModerationCommentValid, 'moderationComment', true))
46 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_ABUSES.MODERATION_COMMENT.max))
47 moderationComment: string
48
49 @AllowNull(true)
50 @Default(null)
51 @Column(DataType.JSONB)
52 deletedVideo: Video
53
54 @CreatedAt
55 createdAt: Date
56
57 @UpdatedAt
58 updatedAt: Date
59
60 @ForeignKey(() => AccountModel)
61 @Column
62 reporterAccountId: number
63
64 @BelongsTo(() => AccountModel, {
65 foreignKey: {
66 allowNull: true
67 },
68 onDelete: 'set null'
69 })
70 Account: AccountModel
71
72 @ForeignKey(() => VideoModel)
73 @Column
74 videoId: number
75
76 @BelongsTo(() => VideoModel, {
77 foreignKey: {
78 allowNull: true
79 },
80 onDelete: 'set null'
81 })
82 Video: VideoModel
83
84 static loadByIdAndVideoId (id: number, videoId?: number, uuid?: string): Bluebird<MVideoAbuse> {
85 const videoAttributes = {}
86 if (videoId) videoAttributes['videoId'] = videoId
87 if (uuid) videoAttributes['deletedVideo'] = { uuid }
88
89 const query = {
90 where: {
91 id,
92 ...videoAttributes
93 }
94 }
95 return VideoAbuseModel.findOne(query)
96 }
97
98 static listForApi (parameters: {
99 start: number
100 count: number
101 sort: string
102 serverAccountId: number
103 user?: MUserAccountId
104 }) {
105 const { start, count, sort, user, serverAccountId } = parameters
106 const userAccountId = user ? user.Account.id : undefined
107
108 const query = {
109 offset: start,
110 limit: count,
111 order: getSort(sort),
112 where: {
113 reporterAccountId: {
114 [Op.notIn]: literal('(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')')
115 }
116 },
117 include: [
118 {
119 model: AccountModel,
120 required: true
121 },
122 {
123 model: VideoModel,
124 required: false
125 }
126 ]
127 }
128
129 return VideoAbuseModel.findAndCountAll(query)
130 .then(({ rows, count }) => {
131 return { total: count, data: rows }
132 })
133 }
134
135 toFormattedJSON (this: MVideoAbuseFormattable): VideoAbuse {
136 const video = this.Video
137 ? this.Video
138 : this.deletedVideo
139
140 return {
141 id: this.id,
142 reason: this.reason,
143 reporterAccount: this.Account.toFormattedJSON(),
144 state: {
145 id: this.state,
146 label: VideoAbuseModel.getStateLabel(this.state)
147 },
148 moderationComment: this.moderationComment,
149 video: {
150 id: video.id,
151 uuid: video.uuid,
152 name: video.name,
153 nsfw: video.nsfw,
154 deleted: !this.Video
155 },
156 createdAt: this.createdAt
157 }
158 }
159
160 toActivityPubObject (this: MVideoAbuseVideo): VideoAbuseObject {
161 return {
162 type: 'Flag' as 'Flag',
163 content: this.reason,
164 object: this.Video.url
165 }
166 }
167
168 private static getStateLabel (id: number) {
169 return VIDEO_ABUSE_STATES[id] || 'Unknown'
170 }
171 }