X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Faccount%2Faccount-video-rate.ts;h=78a897a65a738693e21585849f67a6425f6f3c62;hb=e8bafea35bc930cb8ac5b2d521a188642a1adffe;hp=7f7c976068a39f2c5b64625dbdd714f904bc434e;hpb=e4f97babf701481b55cc10fb3448feab5f97c867;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts index 7f7c97606..78a897a65 100644 --- a/server/models/account/account-video-rate.ts +++ b/server/models/account/account-video-rate.ts @@ -1,78 +1,229 @@ +import { values } from 'lodash' +import { Transaction, Op } from 'sequelize' +import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' +import { IFindOptions } from 'sequelize-typescript/lib/interfaces/IFindOptions' +import { VideoRateType } from '../../../shared/models/videos' +import { CONSTRAINTS_FIELDS, VIDEO_RATE_TYPES } from '../../initializers/constants' +import { VideoModel } from '../video/video' +import { AccountModel } from './account' +import { ActorModel } from '../activitypub/actor' +import { throwIfNotValid, getSort } from '../utils' +import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' +import { AccountVideoRate } from '../../../shared' +import { VideoChannelModel, ScopeNames as VideoChannelScopeNames } from '../video/video-channel' + /* Account rates per video. */ -import { values } from 'lodash' -import * as Sequelize from 'sequelize' - -import { VIDEO_RATE_TYPES } from '../../initializers' - -import { addMethodsToModel } from '../utils' -import { - AccountVideoRateInstance, - AccountVideoRateAttributes, - - AccountVideoRateMethods -} from './account-video-rate-interface' - -let AccountVideoRate: Sequelize.Model -let load: AccountVideoRateMethods.Load - -export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { - AccountVideoRate = sequelize.define('AccountVideoRate', +@Table({ + tableName: 'accountVideoRate', + indexes: [ { - type: { - type: DataTypes.ENUM(values(VIDEO_RATE_TYPES)), - allowNull: false - } + fields: [ 'videoId', 'accountId' ], + unique: true }, { - indexes: [ - { - fields: [ 'videoId', 'accountId', 'type' ], - unique: true - } - ] + fields: [ 'videoId' ] + }, + { + fields: [ 'accountId' ] + }, + { + fields: [ 'videoId', 'type' ] + }, + { + fields: [ 'url' ], + unique: true } - ) + ] +}) +export class AccountVideoRateModel extends Model { - const classMethods = [ - associate, + @AllowNull(false) + @Column(DataType.ENUM(values(VIDEO_RATE_TYPES))) + type: VideoRateType - load - ] - addMethodsToModel(AccountVideoRate, classMethods) + @AllowNull(false) + @Is('AccountVideoRateUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_RATES.URL.max)) + url: string - return AccountVideoRate -} + @CreatedAt + createdAt: Date + + @UpdatedAt + updatedAt: Date -// ------------------------------ STATICS ------------------------------ + @ForeignKey(() => VideoModel) + @Column + videoId: number -function associate (models) { - AccountVideoRate.belongsTo(models.Video, { + @BelongsTo(() => VideoModel, { foreignKey: { - name: 'videoId', allowNull: false }, onDelete: 'CASCADE' }) + Video: VideoModel - AccountVideoRate.belongsTo(models.Account, { + @ForeignKey(() => AccountModel) + @Column + accountId: number + + @BelongsTo(() => AccountModel, { foreignKey: { - name: 'accountId', allowNull: false }, onDelete: 'CASCADE' }) -} + Account: AccountModel -load = function (accountId: number, videoId: number, transaction: Sequelize.Transaction) { - const options: Sequelize.FindOptions = { - where: { - accountId, - videoId + static load (accountId: number, videoId: number, transaction?: Transaction) { + const options: IFindOptions = { + where: { + accountId, + videoId + } } + if (transaction) options.transaction = transaction + + return AccountVideoRateModel.findOne(options) } - if (transaction) options.transaction = transaction - return AccountVideoRate.findOne(options) + static listByAccountForApi (options: { + start: number, + count: number, + sort: string, + type?: string, + accountId: number + }) { + const query: IFindOptions = { + offset: options.start, + limit: options.count, + order: getSort(options.sort), + where: { + accountId: options.accountId + }, + include: [ + { + model: VideoModel, + required: true, + include: [ + { + model: VideoChannelModel.scope({ method: [VideoChannelScopeNames.SUMMARY, true] }), + required: true + } + ] + } + ] + } + if (options.type) query.where['type'] = options.type + + return AccountVideoRateModel.findAndCountAll(query) + } + + static loadLocalAndPopulateVideo (rateType: VideoRateType, accountName: string, videoId: number, transaction?: Transaction) { + const options: IFindOptions = { + where: { + videoId, + type: rateType + }, + include: [ + { + model: AccountModel.unscoped(), + required: true, + include: [ + { + attributes: [ 'id', 'url', 'preferredUsername' ], + model: ActorModel.unscoped(), + required: true, + where: { + preferredUsername: accountName + } + } + ] + }, + { + model: VideoModel.unscoped(), + required: true + } + ] + } + if (transaction) options.transaction = transaction + + return AccountVideoRateModel.findOne(options) + } + + static loadByUrl (url: string, transaction: Transaction) { + const options: IFindOptions = { + where: { + url + } + } + if (transaction) options.transaction = transaction + + return AccountVideoRateModel.findOne(options) + } + + static listAndCountAccountUrlsByVideoId (rateType: VideoRateType, videoId: number, start: number, count: number, t?: Transaction) { + const query = { + offset: start, + limit: count, + where: { + videoId, + type: rateType + }, + transaction: t, + include: [ + { + attributes: [ 'actorId' ], + model: AccountModel.unscoped(), + required: true, + include: [ + { + attributes: [ 'url' ], + model: ActorModel.unscoped(), + required: true + } + ] + } + ] + } + + return AccountVideoRateModel.findAndCountAll(query) + } + + static cleanOldRatesOf (videoId: number, type: VideoRateType, beforeUpdatedAt: Date) { + return AccountVideoRateModel.sequelize.transaction(async t => { + const query = { + where: { + updatedAt: { + [Op.lt]: beforeUpdatedAt + }, + videoId, + type + }, + transaction: t + } + + const deleted = await AccountVideoRateModel.destroy(query) + + const options = { + transaction: t, + where: { + id: videoId + } + } + + if (type === 'like') await VideoModel.increment({ likes: -deleted }, options) + else if (type === 'dislike') await VideoModel.increment({ dislikes: -deleted }, options) + }) + } + + toFormattedJSON (): AccountVideoRate { + return { + video: this.Video.toFormattedJSON(), + rating: this.type + } + } }