X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Fmodels%2Factor%2Factor-follow.ts;h=566bb5f319b0b45a17d081d34aa7251360d73312;hb=927fa4b11f692174d6296aa096d7a74bacdeea8b;hp=fc1cc7499cc78481dd955d95521ab8c1a545dffb;hpb=f0ab2aed3d98240c53e952ada2d2a1d18a5ba23f;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/models/actor/actor-follow.ts b/server/models/actor/actor-follow.ts index fc1cc7499..566bb5f31 100644 --- a/server/models/actor/actor-follow.ts +++ b/server/models/actor/actor-follow.ts @@ -1,5 +1,5 @@ import { difference, values } from 'lodash' -import { IncludeOptions, Op, QueryTypes, Transaction, WhereOptions } from 'sequelize' +import { Attributes, FindOptions, Includeable, IncludeOptions, Op, QueryTypes, Transaction, WhereAttributeHash } from 'sequelize' import { AfterCreate, AfterDestroy, @@ -30,18 +30,19 @@ import { MActorFollowFormattable, MActorFollowSubscriptions } from '@server/types/models' -import { AttributesOnly } from '@shared/core-utils' -import { ActivityPubActorType } from '@shared/models' +import { AttributesOnly } from '@shared/typescript-utils' import { FollowState } from '../../../shared/models/actors' import { ActorFollow } from '../../../shared/models/actors/follow.model' import { logger } from '../../helpers/logger' -import { ACTOR_FOLLOW_SCORE, CONSTRAINTS_FIELDS, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants' +import { ACTOR_FOLLOW_SCORE, CONSTRAINTS_FIELDS, FOLLOW_STATES, SERVER_ACTOR_NAME, SORTABLE_COLUMNS } 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 { createSafeIn, getSort, searchAttribute, throwIfNotValid } from '../utils' import { VideoChannelModel } from '../video/video-channel' import { ActorModel, unusedActorAttributesForAPI } from './actor' +import { InstanceListFollowersQueryBuilder, ListFollowersOptions } from './sql/instance-list-followers-query-builder' +import { InstanceListFollowingQueryBuilder, ListFollowingOptions } from './sql/instance-list-following-query-builder' @Table({ tableName: 'actorFollow', @@ -143,7 +144,7 @@ export class ActorFollowModel extends Model { + static loadByActorAndTargetNameAndHostForAPI (options: { + actorId: number + targetName: string + targetHost: string + state?: FollowState + transaction?: Transaction + }): Promise { + const { actorId, targetHost, targetName, state, transaction } = options + const actorFollowingPartInclude: IncludeOptions = { model: ActorModel, required: true, @@ -270,10 +276,11 @@ export class ActorFollowModel extends Model> = { actorId} + if (state) where.state = state + + const query: FindOptions> = { + where, include: [ actorFollowingPartInclude, { @@ -282,13 +289,13 @@ export class ActorFollowModel extends Model { + static listSubscriptionsOf (actorId: number, targets: { name: string, host?: string }[]): Promise { const whereTab = targets .map(t => { if (t.host) { @@ -324,6 +331,7 @@ export class ActorFollowModel extends Model(query) - .then(({ rows, count }) => { - return { - data: rows, - total: count - } - }) + static listInstanceFollowingForApi (options: ListFollowingOptions) { + return Promise.all([ + new InstanceListFollowingQueryBuilder(this.sequelize, options).countFollowing(), + new InstanceListFollowingQueryBuilder(this.sequelize, options).listFollowing() + ]).then(([ total, data ]) => ({ total, data })) } - static listFollowersForApi (options: { - actorId: number - start: number - count: number - sort: string - state?: FollowState - actorType?: ActivityPubActorType - search?: string - }) { - const { actorId, start, count, sort, search, state, actorType } = options - - const followWhere = state ? { state } : {} - const followerWhere: WhereOptions = {} - - if (search) { - Object.assign(followWhere, { - [Op.or]: [ - searchAttribute(search, '$ActorFollower.preferredUsername$'), - searchAttribute(search, '$ActorFollower.Server.host$') - ] - }) - } - - if (actorType) { - Object.assign(followerWhere, { type: actorType }) - } - - const query = { - distinct: true, - offset: start, - limit: count, - order: getFollowsSort(sort), - where: followWhere, - include: [ - { - model: ActorModel, - required: true, - as: 'ActorFollower', - where: followerWhere, - include: [ - { - model: ServerModel, - required: true - } - ] - }, - { - model: ActorModel, - as: 'ActorFollowing', - required: true, - where: { - id: actorId - } - } - ] - } - - return ActorFollowModel.findAndCountAll(query) - .then(({ rows, count }) => { - return { - data: rows, - total: count - } - }) + static listFollowersForApi (options: ListFollowersOptions) { + return Promise.all([ + new InstanceListFollowersQueryBuilder(this.sequelize, options).countFollowers(), + new InstanceListFollowersQueryBuilder(this.sequelize, options).listFollowers() + ]).then(([ total, data ]) => ({ total, data })) } static listSubscriptionsForApi (options: { @@ -489,7 +379,8 @@ export class ActorFollowModel extends Model { + let channelInclude: Includeable[] = [] + + if (forCount !== true) { + channelInclude = [ + { + attributes: { + exclude: unusedActorAttributesForAPI + }, + model: ActorModel, + required: true + }, + { + model: AccountModel.unscoped(), + required: true, + include: [ + { + attributes: { + exclude: unusedActorAttributesForAPI }, - { - model: AccountModel.unscoped(), - required: true, - include: [ - { - attributes: { - exclude: unusedActorAttributesForAPI - }, - model: ActorModel, - required: true - } - ] - } - ] - } - ] - } - ] + model: ActorModel, + required: true + } + ] + } + ] + } + + return { + attributes: forCount === true + ? [] + : SORTABLE_COLUMNS.USER_SUBSCRIPTIONS, + distinct: true, + offset: start, + limit: count, + order: getSort(sort), + where, + include: [ + { + attributes: [ 'id' ], + model: ActorModel.unscoped(), + as: 'ActorFollowing', + required: true, + include: [ + { + model: VideoChannelModel.unscoped(), + required: true, + include: channelInclude + } + ] + } + ] + } } - return ActorFollowModel.findAndCountAll(query) - .then(({ rows, count }) => { - return { - data: rows.map(r => r.ActorFollowing.VideoChannel), - total: count - } - }) + return Promise.all([ + ActorFollowModel.count(getQuery(true)), + ActorFollowModel.findAll(getQuery(false)) + ]).then(([ total, rows ]) => ({ + total, + data: rows.map(r => r.ActorFollowing.VideoChannel) + })) } static async keepUnfollowedInstance (hosts: string[]) { @@ -619,13 +520,15 @@ export class ActorFollowModel extends Model