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/core-utils'
+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'
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'
@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) {
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<MActorFollowActorsDefault> {
return ActorFollowModel.findOne(query)
}
- static listSubscribedIn (actorId: number, targets: { name: string, host?: string }[]): Promise<MActorFollowFollowingHost[]> {
+ static listSubscriptionsOf (actorId: number, targets: { name: string, host?: string }[]): Promise<MActorFollowFollowingHost[]> {
const whereTab = targets
.map(t => {
if (t.host) {
return ActorFollowModel.findAll(query)
}
- static listFollowingForApi (options: {
+ static listInstanceFollowingForApi (options: {
id: number
start: number
count: number
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$')
+ ]
})
}
include: [
{
model: ServerModel,
- required: true,
- where: followingServerWhere
+ required: true
}
]
}
}
static listFollowersForApi (options: {
- actorId: number
+ actorIds: number[]
start: number
count: number
sort: string
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$')
+ ]
})
}
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
+ }
}
}
]