X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Fvideo%2Fvideo-import.ts;h=b794d83244af4361e234673d822af2ea2b24b875;hb=eacb25c4366bcc8fba20f98f93f004fabc6d5578;hp=89eeafd6a1603c0940b619b13c8678d10d8339e2;hpb=fbad87b0472f574409f7aa3ae7f8b54927d0cdd6;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts index 89eeafd6a..b794d8324 100644 --- a/server/models/video/video-import.ts +++ b/server/models/video/video-import.ts @@ -1,4 +1,5 @@ import { + AfterUpdate, AllowNull, BelongsTo, Column, @@ -12,31 +13,23 @@ import { Table, UpdatedAt } from 'sequelize-typescript' -import { CONSTRAINTS_FIELDS } from '../../initializers' -import { throwIfNotValid } from '../utils' -import { VideoModel } from './video' +import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers' +import { getSort, throwIfNotValid } from '../utils' +import { ScopeNames as VideoModelScopeNames, VideoModel } from './video' import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports' import { VideoImport, VideoImportState } from '../../../shared' -import { VideoChannelModel } from './video-channel' -import { AccountModel } from '../account/account' +import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos' +import { UserModel } from '../account/user' @DefaultScope({ include: [ { - model: () => VideoModel, - required: true, - include: [ - { - model: () => VideoChannelModel, - required: true, - include: [ - { - model: () => AccountModel, - required: true - } - ] - } - ] + model: () => UserModel.unscoped(), + required: true + }, + { + model: () => VideoModel.scope([ VideoModelScopeNames.WITH_ACCOUNT_DETAILS, VideoModelScopeNames.WITH_TAGS]), + required: false } ] }) @@ -47,6 +40,9 @@ import { AccountModel } from '../account/account' { fields: [ 'videoId' ], unique: true + }, + { + fields: [ 'userId' ] } ] }) @@ -57,11 +53,23 @@ export class VideoImportModel extends Model { @UpdatedAt updatedAt: Date - @AllowNull(false) + @AllowNull(true) + @Default(null) @Is('VideoImportTargetUrl', value => throwIfNotValid(value, isVideoImportTargetUrlValid, 'targetUrl')) @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) targetUrl: string + @AllowNull(true) + @Default(null) + @Is('VideoImportMagnetUri', value => throwIfNotValid(value, isVideoMagnetUriValid, 'magnetUri')) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.URL.max)) // Use the same constraints than URLs + magnetUri: string + + @AllowNull(true) + @Default(null) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_NAME.max)) + torrentName: string + @AllowNull(false) @Default(null) @Is('VideoImportState', value => throwIfNotValid(value, isVideoImportStateValid, 'state')) @@ -73,33 +81,97 @@ export class VideoImportModel extends Model { @Column(DataType.TEXT) error: string + @ForeignKey(() => UserModel) + @Column + userId: number + + @BelongsTo(() => UserModel, { + foreignKey: { + allowNull: false + }, + onDelete: 'cascade' + }) + User: UserModel + @ForeignKey(() => VideoModel) @Column videoId: number @BelongsTo(() => VideoModel, { foreignKey: { - allowNull: false + allowNull: true }, - onDelete: 'CASCADE' + onDelete: 'set null' }) Video: VideoModel + @AfterUpdate + static deleteVideoIfFailed (instance: VideoImportModel, options) { + if (instance.state === VideoImportState.FAILED) { + return instance.Video.destroy({ transaction: options.transaction }) + } + + return undefined + } + static loadAndPopulateVideo (id: number) { return VideoImportModel.findById(id) } + static listUserVideoImportsForApi (userId: number, start: number, count: number, sort: string) { + const query = { + distinct: true, + include: [ + { + model: UserModel.unscoped(), // FIXME: Without this, sequelize try to COUNT(DISTINCT(*)) which is an invalid SQL query + required: true + } + ], + offset: start, + limit: count, + order: getSort(sort), + where: { + userId + } + } + + return VideoImportModel.findAndCountAll(query) + .then(({ rows, count }) => { + return { + data: rows, + total: count + } + }) + } + toFormattedJSON (): VideoImport { const videoFormatOptions = { additionalAttributes: { state: true, waitTranscoding: true, scheduledUpdate: true } } - const video = Object.assign(this.Video.toFormattedJSON(videoFormatOptions), { - tags: this.Video.Tags.map(t => t.name) - }) + const video = this.Video + ? Object.assign(this.Video.toFormattedJSON(videoFormatOptions), { + tags: this.Video.Tags.map(t => t.name) + }) + : undefined return { + id: this.id, + targetUrl: this.targetUrl, + magnetUri: this.magnetUri, + torrentName: this.torrentName, + + state: { + id: this.state, + label: VideoImportModel.getStateLabel(this.state) + }, + error: this.error, + updatedAt: this.updatedAt.toISOString(), + createdAt: this.createdAt.toISOString(), video } } + private static getStateLabel (id: number) { + return VIDEO_IMPORT_STATES[id] || 'Unknown' + } }