]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/models/video/video-import.ts
Merge branch 'release/v1.2.0'
[github/Chocobozzz/PeerTube.git] / server / models / video / video-import.ts
1 import {
2 AfterUpdate,
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'
16 import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers'
17 import { getSort, throwIfNotValid } from '../utils'
18 import { ScopeNames as VideoModelScopeNames, VideoModel } from './video'
19 import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports'
20 import { VideoImport, VideoImportState } from '../../../shared'
21 import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos'
22 import { UserModel } from '../account/user'
23
24 @DefaultScope({
25 include: [
26 {
27 model: () => UserModel.unscoped(),
28 required: true
29 },
30 {
31 model: () => VideoModel.scope([ VideoModelScopeNames.WITH_ACCOUNT_DETAILS, VideoModelScopeNames.WITH_TAGS]),
32 required: false
33 }
34 ]
35 })
36
37 @Table({
38 tableName: 'videoImport',
39 indexes: [
40 {
41 fields: [ 'videoId' ],
42 unique: true
43 },
44 {
45 fields: [ 'userId' ]
46 }
47 ]
48 })
49 export class VideoImportModel extends Model<VideoImportModel> {
50 @CreatedAt
51 createdAt: Date
52
53 @UpdatedAt
54 updatedAt: Date
55
56 @AllowNull(true)
57 @Default(null)
58 @Is('VideoImportTargetUrl', value => throwIfNotValid(value, isVideoImportTargetUrlValid, 'targetUrl'))
59 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max))
60 targetUrl: string
61
62 @AllowNull(true)
63 @Default(null)
64 @Is('VideoImportMagnetUri', value => throwIfNotValid(value, isVideoMagnetUriValid, 'magnetUri'))
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
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
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
96 @ForeignKey(() => VideoModel)
97 @Column
98 videoId: number
99
100 @BelongsTo(() => VideoModel, {
101 foreignKey: {
102 allowNull: true
103 },
104 onDelete: 'set null'
105 })
106 Video: VideoModel
107
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
117 static loadAndPopulateVideo (id: number) {
118 return VideoImportModel.findById(id)
119 }
120
121 static listUserVideoImportsForApi (userId: number, start: number, count: number, sort: string) {
122 const query = {
123 distinct: true,
124 include: [
125 {
126 model: UserModel.unscoped(), // FIXME: Without this, sequelize try to COUNT(DISTINCT(*)) which is an invalid SQL query
127 required: true
128 }
129 ],
130 offset: start,
131 limit: count,
132 order: getSort(sort),
133 where: {
134 userId
135 }
136 }
137
138 return VideoImportModel.findAndCountAll(query)
139 .then(({ rows, count }) => {
140 return {
141 data: rows,
142 total: count
143 }
144 })
145 }
146
147 getTargetIdentifier () {
148 return this.targetUrl || this.magnetUri || this.torrentName
149 }
150
151 toFormattedJSON (): VideoImport {
152 const videoFormatOptions = {
153 completeDescription: true,
154 additionalAttributes: { state: true, waitTranscoding: true, scheduledUpdate: true }
155 }
156 const video = this.Video
157 ? Object.assign(this.Video.toFormattedJSON(videoFormatOptions), { tags: this.Video.Tags.map(t => t.name) })
158 : undefined
159
160 return {
161 id: this.id,
162
163 targetUrl: this.targetUrl,
164 magnetUri: this.magnetUri,
165 torrentName: this.torrentName,
166
167 state: {
168 id: this.state,
169 label: VideoImportModel.getStateLabel(this.state)
170 },
171 error: this.error,
172 updatedAt: this.updatedAt.toISOString(),
173 createdAt: this.createdAt.toISOString(),
174 video
175 }
176 }
177
178 private static getStateLabel (id: number) {
179 return VIDEO_IMPORT_STATES[id] || 'Unknown'
180 }
181 }