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