]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/models/video/video-import.ts
Cleaner warning of IP address leaking on embedded videos (#2034)
[github/Chocobozzz/PeerTube.git] / server / models / video / video-import.ts
CommitLineData
fbad87b0 1import {
ed31c059 2 AfterUpdate,
fbad87b0
C
3 AllowNull,
4 BelongsTo,
5 Column,
6 CreatedAt,
7 DataType,
8 Default,
9 DefaultScope,
10 ForeignKey,
11 Is,
12 Model,
13 Table,
14 UpdatedAt
15} from 'sequelize-typescript'
74dc3bca 16import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers/constants'
ed31c059 17import { getSort, throwIfNotValid } from '../utils'
a84b8fa5 18import { ScopeNames as VideoModelScopeNames, VideoModel } from './video'
fbad87b0
C
19import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports'
20import { VideoImport, VideoImportState } from '../../../shared'
ce33919c 21import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos'
a84b8fa5 22import { UserModel } from '../account/user'
fbad87b0 23
3acc5084 24@DefaultScope(() => ({
fbad87b0
C
25 include: [
26 {
3acc5084 27 model: UserModel.unscoped(),
a84b8fa5
C
28 required: true
29 },
30 {
3acc5084 31 model: VideoModel.scope([ VideoModelScopeNames.WITH_ACCOUNT_DETAILS, VideoModelScopeNames.WITH_TAGS]),
a84b8fa5 32 required: false
fbad87b0
C
33 }
34 ]
3acc5084 35}))
fbad87b0
C
36
37@Table({
38 tableName: 'videoImport',
39 indexes: [
40 {
41 fields: [ 'videoId' ],
42 unique: true
a84b8fa5
C
43 },
44 {
45 fields: [ 'userId' ]
fbad87b0
C
46 }
47 ]
48})
49export class VideoImportModel extends Model<VideoImportModel> {
50 @CreatedAt
51 createdAt: Date
52
53 @UpdatedAt
54 updatedAt: Date
55
ce33919c
C
56 @AllowNull(true)
57 @Default(null)
1735c825 58 @Is('VideoImportTargetUrl', value => throwIfNotValid(value, isVideoImportTargetUrlValid, 'targetUrl', true))
fbad87b0
C
59 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max))
60 targetUrl: string
61
ce33919c
C
62 @AllowNull(true)
63 @Default(null)
1735c825 64 @Is('VideoImportMagnetUri', value => throwIfNotValid(value, isVideoMagnetUriValid, 'magnetUri', true))
ce33919c
C
65 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) // Use the same constraints than URLs
66 magnetUri: string
67
68 @AllowNull(true)
69 @Default(null)
70 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_NAME.max))
71 torrentName: string
72
fbad87b0
C
73 @AllowNull(false)
74 @Default(null)
75 @Is('VideoImportState', value => throwIfNotValid(value, isVideoImportStateValid, 'state'))
76 @Column
77 state: VideoImportState
78
79 @AllowNull(true)
80 @Default(null)
81 @Column(DataType.TEXT)
82 error: string
83
a84b8fa5
C
84 @ForeignKey(() => UserModel)
85 @Column
86 userId: number
87
88 @BelongsTo(() => UserModel, {
89 foreignKey: {
90 allowNull: false
91 },
92 onDelete: 'cascade'
93 })
94 User: UserModel
95
fbad87b0
C
96 @ForeignKey(() => VideoModel)
97 @Column
98 videoId: number
99
100 @BelongsTo(() => VideoModel, {
101 foreignKey: {
ed31c059 102 allowNull: true
fbad87b0 103 },
ed31c059 104 onDelete: 'set null'
fbad87b0
C
105 })
106 Video: VideoModel
107
ed31c059
C
108 @AfterUpdate
109 static deleteVideoIfFailed (instance: VideoImportModel, options) {
110 if (instance.state === VideoImportState.FAILED) {
111 return instance.Video.destroy({ transaction: options.transaction })
112 }
113
114 return undefined
115 }
116
fbad87b0 117 static loadAndPopulateVideo (id: number) {
9b39106d 118 return VideoImportModel.findByPk(id)
fbad87b0
C
119 }
120
a84b8fa5 121 static listUserVideoImportsForApi (userId: number, start: number, count: number, sort: string) {
ed31c059 122 const query = {
590fb506 123 distinct: true,
ed31c059
C
124 include: [
125 {
a84b8fa5
C
126 model: UserModel.unscoped(), // FIXME: Without this, sequelize try to COUNT(DISTINCT(*)) which is an invalid SQL query
127 required: true
ed31c059 128 }
a84b8fa5
C
129 ],
130 offset: start,
131 limit: count,
132 order: getSort(sort),
133 where: {
134 userId
135 }
ed31c059
C
136 }
137
a84b8fa5 138 return VideoImportModel.findAndCountAll(query)
ed31c059
C
139 .then(({ rows, count }) => {
140 return {
141 data: rows,
142 total: count
143 }
144 })
145 }
146
dc133480
C
147 getTargetIdentifier () {
148 return this.targetUrl || this.magnetUri || this.torrentName
149 }
150
fbad87b0
C
151 toFormattedJSON (): VideoImport {
152 const videoFormatOptions = {
c39e86b8 153 completeDescription: true,
fbad87b0
C
154 additionalAttributes: { state: true, waitTranscoding: true, scheduledUpdate: true }
155 }
ed31c059 156 const video = this.Video
c39e86b8 157 ? Object.assign(this.Video.toFormattedJSON(videoFormatOptions), { tags: this.Video.Tags.map(t => t.name) })
ed31c059 158 : undefined
fbad87b0
C
159
160 return {
d7f83948 161 id: this.id,
990b6a0b 162
fbad87b0 163 targetUrl: this.targetUrl,
990b6a0b
C
164 magnetUri: this.magnetUri,
165 torrentName: this.torrentName,
166
ed31c059
C
167 state: {
168 id: this.state,
169 label: VideoImportModel.getStateLabel(this.state)
170 },
d7f83948 171 error: this.error,
ed31c059
C
172 updatedAt: this.updatedAt.toISOString(),
173 createdAt: this.createdAt.toISOString(),
fbad87b0
C
174 video
175 }
176 }
268eebed 177
ed31c059
C
178 private static getStateLabel (id: number) {
179 return VIDEO_IMPORT_STATES[id] || 'Unknown'
180 }
fbad87b0 181}