aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/actor/actor-follow.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/actor/actor-follow.ts')
-rw-r--r--server/models/actor/actor-follow.ts146
1 files changed, 10 insertions, 136 deletions
diff --git a/server/models/actor/actor-follow.ts b/server/models/actor/actor-follow.ts
index 0f4d3c0a6..af1d85e9f 100644
--- a/server/models/actor/actor-follow.ts
+++ b/server/models/actor/actor-follow.ts
@@ -1,5 +1,5 @@
1import { difference, values } from 'lodash' 1import { difference, values } from 'lodash'
2import { Includeable, IncludeOptions, literal, Op, QueryTypes, Transaction, WhereOptions } from 'sequelize' 2import { Includeable, IncludeOptions, Op, QueryTypes, Transaction } from 'sequelize'
3import { 3import {
4 AfterCreate, 4 AfterCreate,
5 AfterDestroy, 5 AfterDestroy,
@@ -30,7 +30,6 @@ import {
30 MActorFollowFormattable, 30 MActorFollowFormattable,
31 MActorFollowSubscriptions 31 MActorFollowSubscriptions
32} from '@server/types/models' 32} from '@server/types/models'
33import { ActivityPubActorType } from '@shared/models'
34import { AttributesOnly } from '@shared/typescript-utils' 33import { AttributesOnly } from '@shared/typescript-utils'
35import { FollowState } from '../../../shared/models/actors' 34import { FollowState } from '../../../shared/models/actors'
36import { ActorFollow } from '../../../shared/models/actors/follow.model' 35import { ActorFollow } from '../../../shared/models/actors/follow.model'
@@ -39,9 +38,11 @@ import { ACTOR_FOLLOW_SCORE, CONSTRAINTS_FIELDS, FOLLOW_STATES, SERVER_ACTOR_NAM
39import { AccountModel } from '../account/account' 38import { AccountModel } from '../account/account'
40import { ServerModel } from '../server/server' 39import { ServerModel } from '../server/server'
41import { doesExist } from '../shared/query' 40import { doesExist } from '../shared/query'
42import { createSafeIn, getFollowsSort, getSort, searchAttribute, throwIfNotValid } from '../utils' 41import { createSafeIn, getSort, searchAttribute, throwIfNotValid } from '../utils'
43import { VideoChannelModel } from '../video/video-channel' 42import { VideoChannelModel } from '../video/video-channel'
44import { ActorModel, unusedActorAttributesForAPI } from './actor' 43import { ActorModel, unusedActorAttributesForAPI } from './actor'
44import { InstanceListFollowersQueryBuilder, ListFollowersOptions } from './sql/instance-list-followers-query-builder'
45import { InstanceListFollowingQueryBuilder, ListFollowingOptions } from './sql/instance-list-following-query-builder'
45 46
46@Table({ 47@Table({
47 tableName: 'actorFollow', 48 tableName: 'actorFollow',
@@ -348,144 +349,17 @@ export class ActorFollowModel extends Model<Partial<AttributesOnly<ActorFollowMo
348 return ActorFollowModel.findAll(query) 349 return ActorFollowModel.findAll(query)
349 } 350 }
350 351
351 static listInstanceFollowingForApi (options: { 352 static listInstanceFollowingForApi (options: ListFollowingOptions) {
352 id: number
353 start: number
354 count: number
355 sort: string
356 state?: FollowState
357 actorType?: ActivityPubActorType
358 search?: string
359 }) {
360 const { id, start, count, sort, search, state, actorType } = options
361
362 const followWhere = state ? { state } : {}
363 const followingWhere: WhereOptions = {}
364
365 if (search) {
366 Object.assign(followWhere, {
367 [Op.or]: [
368 searchAttribute(options.search, '$ActorFollowing.preferredUsername$'),
369 searchAttribute(options.search, '$ActorFollowing.Server.host$')
370 ]
371 })
372 }
373
374 if (actorType) {
375 Object.assign(followingWhere, { type: actorType })
376 }
377
378 const getQuery = (forCount: boolean) => {
379 const actorModel = forCount
380 ? ActorModel.unscoped()
381 : ActorModel
382
383 return {
384 distinct: true,
385 offset: start,
386 limit: count,
387 order: getFollowsSort(sort),
388 where: followWhere,
389 include: [
390 {
391 model: actorModel,
392 required: true,
393 as: 'ActorFollower',
394 where: {
395 id
396 }
397 },
398 {
399 model: actorModel,
400 as: 'ActorFollowing',
401 required: true,
402 where: followingWhere,
403 include: [
404 {
405 model: ServerModel,
406 required: true
407 }
408 ]
409 }
410 ]
411 }
412 }
413
414 return Promise.all([ 353 return Promise.all([
415 ActorFollowModel.count(getQuery(true)), 354 new InstanceListFollowingQueryBuilder(this.sequelize, options).countFollowing(),
416 ActorFollowModel.findAll<MActorFollowActorsDefault>(getQuery(false)) 355 new InstanceListFollowingQueryBuilder(this.sequelize, options).listFollowing()
417 ]).then(([ total, data ]) => ({ total, data })) 356 ]).then(([ total, data ]) => ({ total, data }))
418 } 357 }
419 358
420 static listFollowersForApi (options: { 359 static listFollowersForApi (options: ListFollowersOptions) {
421 actorIds: number[]
422 start: number
423 count: number
424 sort: string
425 state?: FollowState
426 actorType?: ActivityPubActorType
427 search?: string
428 }) {
429 const { actorIds, start, count, sort, search, state, actorType } = options
430
431 const followWhere = state ? { state } : {}
432 const followerWhere: WhereOptions = {}
433
434 if (search) {
435 const escapedSearch = ActorFollowModel.sequelize.escape('%' + search + '%')
436
437 Object.assign(followerWhere, {
438 id: {
439 [Op.in]: literal(
440 `(` +
441 `SELECT "actor".id FROM actor LEFT JOIN server on server.id = actor."serverId" ` +
442 `WHERE "preferredUsername" ILIKE ${escapedSearch} OR "host" ILIKE ${escapedSearch}` +
443 `)`
444 )
445 }
446 })
447 }
448
449 if (actorType) {
450 Object.assign(followerWhere, { type: actorType })
451 }
452
453 const getQuery = (forCount: boolean) => {
454 const actorModel = forCount
455 ? ActorModel.unscoped()
456 : ActorModel
457
458 return {
459 distinct: true,
460
461 offset: start,
462 limit: count,
463 order: getFollowsSort(sort),
464 where: followWhere,
465 include: [
466 {
467 model: actorModel,
468 required: true,
469 as: 'ActorFollower',
470 where: followerWhere
471 },
472 {
473 model: actorModel,
474 as: 'ActorFollowing',
475 required: true,
476 where: {
477 id: {
478 [Op.in]: actorIds
479 }
480 }
481 }
482 ]
483 }
484 }
485
486 return Promise.all([ 360 return Promise.all([
487 ActorFollowModel.count(getQuery(true)), 361 new InstanceListFollowersQueryBuilder(this.sequelize, options).countFollowers(),
488 ActorFollowModel.findAll<MActorFollowActorsDefault>(getQuery(false)) 362 new InstanceListFollowersQueryBuilder(this.sequelize, options).listFollowers()
489 ]).then(([ total, data ]) => ({ total, data })) 363 ]).then(([ total, data ]) => ({ total, data }))
490 } 364 }
491 365