X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Factor%2Factor-follow.ts;h=006282530b4cf2c19c3faa65eee56c56e7ece351;hb=5cad2ca9db9b9d138f8a33058d10b94a9fd50c69;hp=4c5f376202b7fbb207b03bad70ef7d11beb0316e;hpb=7d9ba5c08999c6482f0bc5e0c09c6f55b7724090;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/actor/actor-follow.ts b/server/models/actor/actor-follow.ts index 4c5f37620..006282530 100644 --- a/server/models/actor/actor-follow.ts +++ b/server/models/actor/actor-follow.ts @@ -19,15 +19,18 @@ import { UpdatedAt } from 'sequelize-typescript' import { isActivityPubUrlValid } from '@server/helpers/custom-validators/activitypub/misc' +import { afterCommitIfTransaction } from '@server/helpers/database-utils' import { getServerActor } from '@server/models/application/application' -import { VideoModel } from '@server/models/video/video' import { + MActor, + MActorFollowActors, MActorFollowActorsDefault, MActorFollowActorsDefaultSubscription, MActorFollowFollowingHost, MActorFollowFormattable, MActorFollowSubscriptions } from '@server/types/models' +import { AttributesOnly } from '@shared/typescript-utils' import { ActivityPubActorType } from '@shared/models' import { FollowState } from '../../../shared/models/actors' import { ActorFollow } from '../../../shared/models/actors/follow.model' @@ -35,6 +38,7 @@ import { logger } from '../../helpers/logger' import { ACTOR_FOLLOW_SCORE, CONSTRAINTS_FIELDS, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants' import { AccountModel } from '../account/account' import { ServerModel } from '../server/server' +import { doesExist } from '../shared/query' import { createSafeIn, getFollowsSort, getSort, searchAttribute, throwIfNotValid } from '../utils' import { VideoChannelModel } from '../video/video-channel' import { ActorModel, unusedActorAttributesForAPI } from './actor' @@ -61,7 +65,7 @@ import { ActorModel, unusedActorAttributesForAPI } from './actor' } ] }) -export class ActorFollowModel extends Model { +export class ActorFollowModel extends Model>> { @AllowNull(false) @Column(DataType.ENUM(...values(FOLLOW_STATES))) @@ -117,20 +121,60 @@ export class ActorFollowModel extends Model { @AfterCreate @AfterUpdate static incrementFollowerAndFollowingCount (instance: ActorFollowModel, options: any) { - if (instance.state !== 'accepted') return undefined - - return Promise.all([ - ActorModel.rebuildFollowsCount(instance.actorId, 'following', options.transaction), - ActorModel.rebuildFollowsCount(instance.targetActorId, 'followers', options.transaction) - ]) + return afterCommitIfTransaction(options.transaction, () => { + return Promise.all([ + ActorModel.rebuildFollowsCount(instance.actorId, 'following'), + ActorModel.rebuildFollowsCount(instance.targetActorId, 'followers') + ]) + }) } @AfterDestroy static decrementFollowerAndFollowingCount (instance: ActorFollowModel, options: any) { - return Promise.all([ - ActorModel.rebuildFollowsCount(instance.actorId, 'following', options.transaction), - ActorModel.rebuildFollowsCount(instance.targetActorId, 'followers', options.transaction) - ]) + return afterCommitIfTransaction(options.transaction, () => { + return Promise.all([ + ActorModel.rebuildFollowsCount(instance.actorId, 'following'), + ActorModel.rebuildFollowsCount(instance.targetActorId, 'followers') + ]) + }) + } + + /* + * @deprecated Use `findOrCreateCustom` instead + */ + static findOrCreate (): any { + throw new Error('Must not be called') + } + + // findOrCreate has issues with actor follow hooks + static async findOrCreateCustom (options: { + byActor: MActor + targetActor: MActor + activityId: string + state: FollowState + transaction: Transaction + }): Promise<[ MActorFollowActors, boolean ]> { + const { byActor, targetActor, activityId, state, transaction } = options + + let created = false + let actorFollow: MActorFollowActors = await ActorFollowModel.loadByActorAndTarget(byActor.id, targetActor.id, transaction) + + if (!actorFollow) { + created = true + + actorFollow = await ActorFollowModel.create({ + actorId: byActor.id, + targetActorId: targetActor.id, + url: activityId, + + state + }, { transaction }) + + actorFollow.ActorFollowing = targetActor + actorFollow.ActorFollower = byActor + } + + return [ actorFollow, created ] } static removeFollowsOf (actorId: number, t?: Transaction) { @@ -165,14 +209,8 @@ export class ActorFollowModel extends Model { static isFollowedBy (actorId: number, followerActorId: number) { const query = 'SELECT 1 FROM "actorFollow" WHERE "actorId" = $followerActorId AND "targetActorId" = $actorId LIMIT 1' - const options = { - type: QueryTypes.SELECT as QueryTypes.SELECT, - bind: { actorId, followerActorId }, - raw: true - } - return VideoModel.sequelize.query(query, options) - .then(results => results.length === 1) + return doesExist(query, { actorId, followerActorId }) } static loadByActorAndTarget (actorId: number, targetActorId: number, t?: Transaction): Promise { @@ -250,7 +288,7 @@ export class ActorFollowModel extends Model { return ActorFollowModel.findOne(query) } - static listSubscribedIn (actorId: number, targets: { name: string, host?: string }[]): Promise { + static listSubscriptionsOf (actorId: number, targets: { name: string, host?: string }[]): Promise { const whereTab = targets .map(t => { if (t.host) { @@ -310,7 +348,7 @@ export class ActorFollowModel extends Model { return ActorFollowModel.findAll(query) } - static listFollowingForApi (options: { + static listInstanceFollowingForApi (options: { id: number start: number count: number @@ -323,13 +361,13 @@ export class ActorFollowModel extends Model { const followWhere = state ? { state } : {} const followingWhere: WhereOptions = {} - const followingServerWhere: WhereOptions = {} if (search) { - Object.assign(followingServerWhere, { - host: { - [Op.iLike]: '%' + search + '%' - } + Object.assign(followWhere, { + [Op.or]: [ + searchAttribute(options.search, '$ActorFollowing.preferredUsername$'), + searchAttribute(options.search, '$ActorFollowing.Server.host$') + ] }) } @@ -360,8 +398,7 @@ export class ActorFollowModel extends Model { include: [ { model: ServerModel, - required: true, - where: followingServerWhere + required: true } ] } @@ -378,7 +415,7 @@ export class ActorFollowModel extends Model { } static listFollowersForApi (options: { - actorId: number + actorIds: number[] start: number count: number sort: string @@ -386,17 +423,17 @@ export class ActorFollowModel extends Model { actorType?: ActivityPubActorType search?: string }) { - const { actorId, start, count, sort, search, state, actorType } = options + const { actorIds, start, count, sort, search, state, actorType } = options const followWhere = state ? { state } : {} const followerWhere: WhereOptions = {} - const followerServerWhere: WhereOptions = {} if (search) { - Object.assign(followerServerWhere, { - host: { - [Op.iLike]: '%' + search + '%' - } + Object.assign(followWhere, { + [Op.or]: [ + searchAttribute(search, '$ActorFollower.preferredUsername$'), + searchAttribute(search, '$ActorFollower.Server.host$') + ] }) } @@ -415,21 +452,16 @@ export class ActorFollowModel extends Model { model: ActorModel, required: true, as: 'ActorFollower', - where: followerWhere, - include: [ - { - model: ServerModel, - required: true, - where: followerServerWhere - } - ] + where: followerWhere }, { model: ActorModel, as: 'ActorFollowing', required: true, where: { - id: actorId + id: { + [Op.in]: actorIds + } } } ] @@ -619,7 +651,7 @@ export class ActorFollowModel extends Model { if (serverIds.length === 0) return const me = await getServerActor() - const serverIdsString = createSafeIn(ActorFollowModel, serverIds) + const serverIdsString = createSafeIn(ActorFollowModel.sequelize, serverIds) const query = `UPDATE "actorFollow" SET "score" = LEAST("score" + ${value}, ${ACTOR_FOLLOW_SCORE.MAX}) ` + 'WHERE id IN (' +