X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Fvideo%2Fvideo-import.ts;h=da6b92c7a1e6672dffbc3135ff713cba2c8a2d06;hb=a3b472a12ec6e57dbe2f650419f8064864686eab;hp=fbe0ee0a740844ae5094b538951f4645ed32be69;hpb=62068f4153cb1e67fe30a7f92947c3f2ec058c73;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts index fbe0ee0a7..da6b92c7a 100644 --- a/server/models/video/video-import.ts +++ b/server/models/video/video-import.ts @@ -1,3 +1,4 @@ +import { IncludeOptions, Op, WhereOptions } from 'sequelize' import { AfterUpdate, AllowNull, @@ -13,15 +14,25 @@ import { Table, UpdatedAt } from 'sequelize-typescript' -import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers/constants' -import { getSort, throwIfNotValid } from '../utils' -import { ScopeNames as VideoModelScopeNames, VideoModel } from './video' +import { afterCommitIfTransaction } from '@server/helpers/database-utils' +import { MVideoImportDefault, MVideoImportFormattable } from '@server/types/models/video/video-import' +import { VideoImport, VideoImportState } from '@shared/models' +import { AttributesOnly } from '@shared/typescript-utils' import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../helpers/custom-validators/video-imports' -import { VideoImport, VideoImportState } from '../../../shared' import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos' -import { UserModel } from '../account/user' -import * as Bluebird from 'bluebird' -import { MVideoImportDefault, MVideoImportFormattable } from '@server/typings/models/video/video-import' +import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers/constants' +import { UserModel } from '../user/user' +import { getSort, searchAttribute, throwIfNotValid } from '../utils' +import { ScopeNames as VideoModelScopeNames, VideoModel } from './video' +import { VideoChannelSyncModel } from './video-channel-sync' + +const defaultVideoScope = () => { + return VideoModel.scope([ + VideoModelScopeNames.WITH_ACCOUNT_DETAILS, + VideoModelScopeNames.WITH_TAGS, + VideoModelScopeNames.WITH_THUMBNAILS + ]) +} @DefaultScope(() => ({ include: [ @@ -30,11 +41,11 @@ import { MVideoImportDefault, MVideoImportFormattable } from '@server/typings/mo required: true }, { - model: VideoModel.scope([ - VideoModelScopeNames.WITH_ACCOUNT_DETAILS, - VideoModelScopeNames.WITH_TAGS, - VideoModelScopeNames.WITH_THUMBNAILS - ]), + model: defaultVideoScope(), + required: false + }, + { + model: VideoChannelSyncModel.unscoped(), required: false } ] @@ -52,7 +63,7 @@ import { MVideoImportDefault, MVideoImportFormattable } from '@server/typings/mo } ] }) -export class VideoImportModel extends Model { +export class VideoImportModel extends Model>> { @CreatedAt createdAt: Date @@ -111,44 +122,107 @@ export class VideoImportModel extends Model { }) Video: VideoModel + @ForeignKey(() => VideoChannelSyncModel) + @Column + videoChannelSyncId: number + + @BelongsTo(() => VideoChannelSyncModel, { + foreignKey: { + allowNull: true + }, + onDelete: 'set null' + }) + VideoChannelSync: VideoChannelSyncModel + @AfterUpdate static deleteVideoIfFailed (instance: VideoImportModel, options) { if (instance.state === VideoImportState.FAILED) { - return instance.Video.destroy({ transaction: options.transaction }) + return afterCommitIfTransaction(options.transaction, () => instance.Video.destroy()) } return undefined } - static loadAndPopulateVideo (id: number): Bluebird { + static loadAndPopulateVideo (id: number): Promise { return VideoImportModel.findByPk(id) } - static listUserVideoImportsForApi (userId: number, start: number, count: number, sort: string) { + static listUserVideoImportsForApi (options: { + userId: number + start: number + count: number + sort: string + + search?: string + targetUrl?: string + videoChannelSyncId?: number + }) { + const { userId, start, count, sort, targetUrl, videoChannelSyncId, search } = options + + const where: WhereOptions = { userId } + const include: IncludeOptions[] = [ + { + attributes: [ 'id' ], + model: UserModel.unscoped(), // FIXME: Without this, sequelize try to COUNT(DISTINCT(*)) which is an invalid SQL query + required: true + }, + { + model: VideoChannelSyncModel.unscoped(), + required: false + } + ] + + if (targetUrl) where['targetUrl'] = targetUrl + if (videoChannelSyncId) where['videoChannelSyncId'] = videoChannelSyncId + + if (search) { + include.push({ + model: defaultVideoScope(), + required: true, + where: searchAttribute(search, 'name') + }) + } else { + include.push({ + model: defaultVideoScope(), + required: false + }) + } + const query = { distinct: true, - include: [ - { - attributes: [ 'id' ], - model: UserModel.unscoped(), // FIXME: Without this, sequelize try to COUNT(DISTINCT(*)) which is an invalid SQL query - required: true - } - ], + include, offset: start, limit: count, order: getSort(sort), - where: { - userId - } + where } - return VideoImportModel.findAndCountAll(query) - .then(({ rows, count }) => { - return { - data: rows, - total: count - } - }) + return Promise.all([ + VideoImportModel.unscoped().count(query), + VideoImportModel.findAll(query) + ]).then(([ total, data ]) => ({ total, data })) + } + + static async urlAlreadyImported (channelId: number, targetUrl: string): Promise { + const element = await VideoImportModel.unscoped().findOne({ + where: { + targetUrl, + state: { + [Op.in]: [ VideoImportState.PENDING, VideoImportState.PROCESSING, VideoImportState.SUCCESS ] + } + }, + include: [ + { + model: VideoModel, + required: true, + where: { + channelId + } + } + ] + }) + + return !!element } getTargetIdentifier () { @@ -164,6 +238,10 @@ export class VideoImportModel extends Model { ? Object.assign(this.Video.toFormattedJSON(videoFormatOptions), { tags: this.Video.Tags.map(t => t.name) }) : undefined + const videoChannelSync = this.VideoChannelSync + ? { id: this.VideoChannelSync.id, externalChannelUrl: this.VideoChannelSync.externalChannelUrl } + : undefined + return { id: this.id, @@ -178,7 +256,8 @@ export class VideoImportModel extends Model { error: this.error, updatedAt: this.updatedAt.toISOString(), createdAt: this.createdAt.toISOString(), - video + video, + videoChannelSync } }