Init commit

This commit is contained in:
ShreejitPanchal
2026-05-19 19:56:02 +08:00
commit 6601501eff
4047 changed files with 2185372 additions and 0 deletions

View File

@@ -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
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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(', ')
}
}

View File

@@ -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} `
}
}