Init commit
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import { ActivityPubActorType, FollowState } from '@peertube/peertube-models'
|
||||
import { AbstractListQueryOptions } from '@server/models/shared/abstract-list-query.js'
|
||||
import { Sequelize } from 'sequelize'
|
||||
import { InstanceListFollowsQueryBuilder } from './shared/instance-list-follows-query-builder.js'
|
||||
|
||||
export interface ListFollowersOptions extends AbstractListQueryOptions {
|
||||
actorIds: number[]
|
||||
state?: FollowState
|
||||
actorType?: ActivityPubActorType
|
||||
search?: string
|
||||
}
|
||||
|
||||
export class InstanceListFollowersQueryBuilder extends InstanceListFollowsQueryBuilder<ListFollowersOptions> {
|
||||
constructor (
|
||||
protected readonly sequelize: Sequelize,
|
||||
protected readonly options: ListFollowersOptions
|
||||
) {
|
||||
super(sequelize, options)
|
||||
}
|
||||
|
||||
protected buildSubQueryWhere () {
|
||||
this.buildActorFollowingJoin()
|
||||
|
||||
this.subQueryWhere = 'WHERE "ActorFollowing"."id" IN (:actorIds) '
|
||||
this.replacements.actorIds = this.options.actorIds
|
||||
|
||||
if (this.options.state) {
|
||||
this.subQueryWhere += 'AND "ActorFollowModel"."state" = :state '
|
||||
this.replacements.state = this.options.state
|
||||
}
|
||||
|
||||
if (this.options.search) {
|
||||
const escapedLikeSearch = this.sequelize.escape('%' + this.options.search + '%')
|
||||
|
||||
this.subQueryWhere += `AND (` +
|
||||
`"ActorFollower->Server"."host" ILIKE ${escapedLikeSearch} ` +
|
||||
`OR "ActorFollower"."preferredUsername" ILIKE ${escapedLikeSearch} ` +
|
||||
`)`
|
||||
}
|
||||
|
||||
if (this.options.actorType) {
|
||||
this.subQueryWhere += `AND "ActorFollower"."type" = :actorType `
|
||||
this.replacements.actorType = this.options.actorType
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { ActivityPubActorType, FollowState } from '@peertube/peertube-models'
|
||||
import { AbstractListQueryOptions } from '@server/models/shared/abstract-list-query.js'
|
||||
import { Sequelize } from 'sequelize'
|
||||
import { InstanceListFollowsQueryBuilder } from './shared/instance-list-follows-query-builder.js'
|
||||
|
||||
export interface ListFollowingOptions extends AbstractListQueryOptions {
|
||||
followerId: number
|
||||
state?: FollowState
|
||||
actorType?: ActivityPubActorType
|
||||
search?: string
|
||||
}
|
||||
|
||||
export class InstanceListFollowingQueryBuilder extends InstanceListFollowsQueryBuilder<ListFollowingOptions> {
|
||||
constructor (
|
||||
protected readonly sequelize: Sequelize,
|
||||
protected readonly options: ListFollowingOptions
|
||||
) {
|
||||
super(sequelize, options)
|
||||
}
|
||||
|
||||
protected buildSubQueryWhere () {
|
||||
this.buildActorFollowingJoin()
|
||||
|
||||
this.subQueryWhere = 'WHERE "ActorFollowModel"."actorId" = :followerId '
|
||||
this.replacements.followerId = this.options.followerId
|
||||
|
||||
if (this.options.state) {
|
||||
this.subQueryWhere += 'AND "ActorFollowModel"."state" = :state '
|
||||
this.replacements.state = this.options.state
|
||||
}
|
||||
|
||||
if (this.options.search) {
|
||||
const escapedLikeSearch = this.sequelize.escape('%' + this.options.search + '%')
|
||||
|
||||
this.subQueryWhere += `AND (` +
|
||||
`"ActorFollowing->Server"."host" ILIKE ${escapedLikeSearch} ` +
|
||||
`OR "ActorFollowing"."preferredUsername" ILIKE ${escapedLikeSearch} ` +
|
||||
`)`
|
||||
}
|
||||
|
||||
if (this.options.actorType) {
|
||||
this.subQueryWhere += `AND "ActorFollowing"."type" = :actorType `
|
||||
this.replacements.actorType = this.options.actorType
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Memoize } from '@server/helpers/memoize.js'
|
||||
import { ServerModel } from '@server/models/server/server.js'
|
||||
import { ActorModel } from '../../actor.js'
|
||||
import { ActorFollowModel } from '../../actor-follow.js'
|
||||
import { ActorImageModel } from '../../actor-image.js'
|
||||
|
||||
export class ActorFollowTableAttributes {
|
||||
@Memoize()
|
||||
getFollowAttributes () {
|
||||
return ActorFollowModel.getSQLAttributes('ActorFollowModel').join(', ')
|
||||
}
|
||||
|
||||
@Memoize()
|
||||
getActorAttributes (actorTableName: string) {
|
||||
return ActorModel.getSQLAPIAttributes(actorTableName, `${actorTableName}.`).join(', ')
|
||||
}
|
||||
|
||||
@Memoize()
|
||||
getServerAttributes (actorTableName: string) {
|
||||
return ServerModel.getSQLAttributes(`${actorTableName}->Server`, `${actorTableName}.Server.`).join(', ')
|
||||
}
|
||||
|
||||
@Memoize()
|
||||
getAvatarAttributes (actorTableName: string) {
|
||||
return ActorImageModel.getSQLAttributes(`${actorTableName}->Avatars`, `${actorTableName}.Avatars.`).join(', ')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { ActorImageType } from '@peertube/peertube-models'
|
||||
import { AbstractListQuery, AbstractListQueryOptions } from '@server/models/shared/abstract-list-query.js'
|
||||
import { Sequelize } from 'sequelize'
|
||||
import { getInstanceFollowsSort } from '../../../shared/index.js'
|
||||
import { ActorFollowTableAttributes } from './actor-follow-table-attributes.js'
|
||||
|
||||
export abstract class InstanceListFollowsQueryBuilder<T extends AbstractListQueryOptions> extends AbstractListQuery {
|
||||
protected readonly tableAttributes = new ActorFollowTableAttributes()
|
||||
|
||||
private builtActorFollowingJoin = false
|
||||
|
||||
constructor (
|
||||
protected readonly sequelize: Sequelize,
|
||||
protected readonly options: T
|
||||
) {
|
||||
super(sequelize, { modelName: 'ActorFollowModel', tableName: 'actorFollow' }, options)
|
||||
}
|
||||
|
||||
protected buildQueryJoin () {
|
||||
this.join += this.getAvatarsJoin('ActorFollower')
|
||||
this.join += this.getAvatarsJoin('ActorFollowing')
|
||||
}
|
||||
|
||||
protected buildQueryAttributes () {
|
||||
this.attributes = [
|
||||
...this.attributes,
|
||||
|
||||
this.tableAttributes.getAvatarAttributes('ActorFollower'),
|
||||
this.tableAttributes.getAvatarAttributes('ActorFollowing')
|
||||
]
|
||||
}
|
||||
|
||||
protected buildSubQueryJoin () {
|
||||
this.buildActorFollowingJoin()
|
||||
}
|
||||
|
||||
protected buildSubQueryAttributes () {
|
||||
this.subQueryAttributes = [
|
||||
...this.subQueryAttributes,
|
||||
|
||||
this.tableAttributes.getFollowAttributes(),
|
||||
this.tableAttributes.getActorAttributes('ActorFollower'),
|
||||
this.tableAttributes.getActorAttributes('ActorFollowing'),
|
||||
this.tableAttributes.getServerAttributes('ActorFollower'),
|
||||
this.tableAttributes.getServerAttributes('ActorFollowing')
|
||||
]
|
||||
}
|
||||
|
||||
protected getSort (sort: string) {
|
||||
return getInstanceFollowsSort(sort)
|
||||
}
|
||||
|
||||
protected buildActorFollowingJoin () {
|
||||
if (this.builtActorFollowingJoin) return
|
||||
|
||||
this.subQueryJoin += 'INNER JOIN "actor" "ActorFollower" ON "ActorFollower"."id" = "ActorFollowModel"."actorId" ' +
|
||||
'INNER JOIN "actor" "ActorFollowing" ON "ActorFollowing"."id" = "ActorFollowModel"."targetActorId" '
|
||||
|
||||
this.subQueryJoin += this.getServerJoin('ActorFollowing')
|
||||
this.subQueryJoin += this.getServerJoin('ActorFollower')
|
||||
|
||||
this.builtActorFollowingJoin = true
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
private getServerJoin (actorName: string) {
|
||||
return `LEFT JOIN "server" "${actorName}->Server" ON "${actorName}"."serverId" = "${actorName}->Server"."id" `
|
||||
}
|
||||
|
||||
private getAvatarsJoin (actorName: string) {
|
||||
return `LEFT JOIN "actorImage" "${actorName}->Avatars" ON "${actorName}.id" = "${actorName}->Avatars"."actorId" ` +
|
||||
`AND "${actorName}->Avatars"."type" = ${ActorImageType.AVATAR} `
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user