import * as Sequelize from 'sequelize' import { isVideoChannelNameValid, isVideoChannelDescriptionValid } from '../../helpers' import { removeVideoChannelToFriends } from '../../lib' import { addMethodsToModel, getSort } from '../utils' import { VideoChannelInstance, VideoChannelAttributes, VideoChannelMethods } from './video-channel-interface' let VideoChannel: Sequelize.Model let toFormattedJSON: VideoChannelMethods.ToFormattedJSON let toAddRemoteJSON: VideoChannelMethods.ToAddRemoteJSON let toUpdateRemoteJSON: VideoChannelMethods.ToUpdateRemoteJSON let isOwned: VideoChannelMethods.IsOwned let countByAuthor: VideoChannelMethods.CountByAuthor let listOwned: VideoChannelMethods.ListOwned let listForApi: VideoChannelMethods.ListForApi let listByAuthor: VideoChannelMethods.ListByAuthor let loadByIdAndAuthor: VideoChannelMethods.LoadByIdAndAuthor let loadByUUID: VideoChannelMethods.LoadByUUID let loadAndPopulateAuthor: VideoChannelMethods.LoadAndPopulateAuthor let loadByUUIDAndPopulateAuthor: VideoChannelMethods.LoadByUUIDAndPopulateAuthor let loadByHostAndUUID: VideoChannelMethods.LoadByHostAndUUID let loadAndPopulateAuthorAndVideos: VideoChannelMethods.LoadAndPopulateAuthorAndVideos export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { VideoChannel = sequelize.define('VideoChannel', { uuid: { type: DataTypes.UUID, defaultValue: DataTypes.UUIDV4, allowNull: false, validate: { isUUID: 4 } }, name: { type: DataTypes.STRING, allowNull: false, validate: { nameValid: value => { const res = isVideoChannelNameValid(value) if (res === false) throw new Error('Video channel name is not valid.') } } }, description: { type: DataTypes.STRING, allowNull: true, validate: { descriptionValid: value => { const res = isVideoChannelDescriptionValid(value) if (res === false) throw new Error('Video channel description is not valid.') } } }, remote: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: false } }, { indexes: [ { fields: [ 'authorId' ] } ], hooks: { afterDestroy } } ) const classMethods = [ associate, listForApi, listByAuthor, listOwned, loadByIdAndAuthor, loadAndPopulateAuthor, loadByUUIDAndPopulateAuthor, loadByUUID, loadByHostAndUUID, loadAndPopulateAuthorAndVideos, countByAuthor ] const instanceMethods = [ isOwned, toFormattedJSON, toAddRemoteJSON, toUpdateRemoteJSON ] addMethodsToModel(VideoChannel, classMethods, instanceMethods) return VideoChannel } // ------------------------------ METHODS ------------------------------ isOwned = function (this: VideoChannelInstance) { return this.remote === false } toFormattedJSON = function (this: VideoChannelInstance) { const json = { id: this.id, uuid: this.uuid, name: this.name, description: this.description, isLocal: this.isOwned(), createdAt: this.createdAt, updatedAt: this.updatedAt } if (this.Author !== undefined) { json['owner'] = { name: this.Author.name, uuid: this.Author.uuid } } if (Array.isArray(this.Videos)) { json['videos'] = this.Videos.map(v => v.toFormattedJSON()) } return json } toAddRemoteJSON = function (this: VideoChannelInstance) { const json = { uuid: this.uuid, name: this.name, description: this.description, createdAt: this.createdAt, updatedAt: this.updatedAt, ownerUUID: this.Author.uuid } return json } toUpdateRemoteJSON = function (this: VideoChannelInstance) { const json = { uuid: this.uuid, name: this.name, description: this.description, createdAt: this.createdAt, updatedAt: this.updatedAt, ownerUUID: this.Author.uuid } return json } // ------------------------------ STATICS ------------------------------ function associate (models) { VideoChannel.belongsTo(models.Author, { foreignKey: { name: 'authorId', allowNull: false }, onDelete: 'CASCADE' }) VideoChannel.hasMany(models.Video, { foreignKey: { name: 'channelId', allowNull: false }, onDelete: 'CASCADE' }) } function afterDestroy (videoChannel: VideoChannelInstance, options: { transaction: Sequelize.Transaction }) { if (videoChannel.isOwned()) { const removeVideoChannelToFriendsParams = { uuid: videoChannel.uuid } return removeVideoChannelToFriends(removeVideoChannelToFriendsParams, options.transaction) } return undefined } countByAuthor = function (authorId: number) { const query = { where: { authorId } } return VideoChannel.count(query) } listOwned = function () { const query = { where: { remote: false }, include: [ VideoChannel['sequelize'].models.Author ] } return VideoChannel.findAll(query) } listForApi = function (start: number, count: number, sort: string) { const query = { offset: start, limit: count, order: [ getSort(sort) ], include: [ { model: VideoChannel['sequelize'].models.Author, required: true, include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] } ] } return VideoChannel.findAndCountAll(query).then(({ rows, count }) => { return { total: count, data: rows } }) } listByAuthor = function (authorId: number) { const query = { order: [ getSort('createdAt') ], include: [ { model: VideoChannel['sequelize'].models.Author, where: { id: authorId }, required: true, include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] } ] } return VideoChannel.findAndCountAll(query).then(({ rows, count }) => { return { total: count, data: rows } }) } loadByUUID = function (uuid: string, t?: Sequelize.Transaction) { const query: Sequelize.FindOptions = { where: { uuid } } if (t !== undefined) query.transaction = t return VideoChannel.findOne(query) } loadByHostAndUUID = function (fromHost: string, uuid: string, t?: Sequelize.Transaction) { const query: Sequelize.FindOptions = { where: { uuid }, include: [ { model: VideoChannel['sequelize'].models.Author, include: [ { model: VideoChannel['sequelize'].models.Pod, required: true, where: { host: fromHost } } ] } ] } if (t !== undefined) query.transaction = t return VideoChannel.findOne(query) } loadByIdAndAuthor = function (id: number, authorId: number) { const options = { where: { id, authorId }, include: [ { model: VideoChannel['sequelize'].models.Author, include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] } ] } return VideoChannel.findOne(options) } loadAndPopulateAuthor = function (id: number) { const options = { include: [ { model: VideoChannel['sequelize'].models.Author, include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] } ] } return VideoChannel.findById(id, options) } loadByUUIDAndPopulateAuthor = function (uuid: string) { const options = { where: { uuid }, include: [ { model: VideoChannel['sequelize'].models.Author, include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] } ] } return VideoChannel.findOne(options) } loadAndPopulateAuthorAndVideos = function (id: number) { const options = { include: [ { model: VideoChannel['sequelize'].models.Author, include: [ { model: VideoChannel['sequelize'].models.Pod, required: false } ] }, VideoChannel['sequelize'].models.Video ] } return VideoChannel.findById(id, options) }