X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=server%2Fmodels%2Faccount%2Faccount-video-rate.ts;h=5064987dc448672ed8a2fcad2b8e2912cbb8bf4b;hb=26d6bf6533023326fa017812cf31bbe20c752d36;hp=9c19ec7488d46bc269fe281f101a24a94197c456;hpb=9a4a9b6c4e193739d542f73ee85cd305067f2aea;p=oweals%2Fpeertube.git diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts index 9c19ec748..5064987dc 100644 --- a/server/models/account/account-video-rate.ts +++ b/server/models/account/account-video-rate.ts @@ -1,12 +1,22 @@ import { values } from 'lodash' -import { Transaction } from 'sequelize' -import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript' -import { IFindOptions } from 'sequelize-typescript/lib/interfaces/IFindOptions' +import { FindOptions, Op, Transaction } from 'sequelize' +import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' import { VideoRateType } from '../../../shared/models/videos' -import { VIDEO_RATE_TYPES } from '../../initializers' +import { CONSTRAINTS_FIELDS, VIDEO_RATE_TYPES } from '../../initializers/constants' import { VideoModel } from '../video/video' import { AccountModel } from './account' import { ActorModel } from '../activitypub/actor' +import { buildLocalAccountIdsIn, getSort, throwIfNotValid } from '../utils' +import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' +import { AccountVideoRate } from '../../../shared' +import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel' +import * as Bluebird from 'bluebird' +import { + MAccountVideoRate, + MAccountVideoRateAccountUrl, + MAccountVideoRateAccountVideo, + MAccountVideoRateFormattable +} from '@server/types/models/video/video-rate' /* Account rates per video. @@ -17,15 +27,33 @@ import { ActorModel } from '../activitypub/actor' { fields: [ 'videoId', 'accountId' ], unique: true + }, + { + fields: [ 'videoId' ] + }, + { + fields: [ 'accountId' ] + }, + { + fields: [ 'videoId', 'type' ] + }, + { + fields: [ 'url' ], + unique: true } ] }) export class AccountVideoRateModel extends Model { @AllowNull(false) - @Column(DataType.ENUM(values(VIDEO_RATE_TYPES))) + @Column(DataType.ENUM(...values(VIDEO_RATE_TYPES))) type: VideoRateType + @AllowNull(false) + @Is('AccountVideoRateUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url')) + @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_RATES.URL.max)) + url: string + @CreatedAt createdAt: Date @@ -56,8 +84,8 @@ export class AccountVideoRateModel extends Model { }) Account: AccountModel - static load (accountId: number, videoId: number, transaction: Transaction) { - const options: IFindOptions = { + static load (accountId: number, videoId: number, transaction?: Transaction): Bluebird { + const options: FindOptions = { where: { accountId, videoId @@ -68,6 +96,105 @@ export class AccountVideoRateModel extends Model { return AccountVideoRateModel.findOne(options) } + static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird { + const options: FindOptions = { + where: { + [Op.or]: [ + { + accountId, + videoId + }, + { + url + } + ] + } + } + if (t) options.transaction = t + + return AccountVideoRateModel.findOne(options) + } + + static listByAccountForApi (options: { + start: number + count: number + sort: string + type?: string + accountId: number + }) { + const query: FindOptions = { + 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, { withAccount: true } as SummaryOptions ] }), + required: true + } + ] + } + ] + } + if (options.type) query.where['type'] = options.type + + return AccountVideoRateModel.findAndCountAll(query) + } + + static loadLocalAndPopulateVideo ( + rateType: VideoRateType, + accountName: string, + videoId: number | string, + t?: Transaction + ): Bluebird { + const options: FindOptions = { + where: { + videoId, + type: rateType + }, + include: [ + { + model: AccountModel.unscoped(), + required: true, + include: [ + { + attributes: [ 'id', 'url', 'followersUrl', 'preferredUsername' ], + model: ActorModel.unscoped(), + required: true, + where: { + preferredUsername: accountName + } + } + ] + }, + { + model: VideoModel.unscoped(), + required: true + } + ] + } + if (t) options.transaction = t + + return AccountVideoRateModel.findOne(options) + } + + static loadByUrl (url: string, transaction: Transaction) { + const options: FindOptions = { + 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, @@ -93,6 +220,43 @@ export class AccountVideoRateModel extends Model { ] } - return AccountVideoRateModel.findAndCountAll(query) + 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, + accountId: { + [Op.notIn]: buildLocalAccountIdsIn() + } + }, + 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 (this: MAccountVideoRateFormattable): AccountVideoRate { + return { + video: this.Video.toFormattedJSON(), + rating: this.type + } } }