1 import * as Bluebird from 'bluebird'
2 import { values } from 'lodash'
3 import * as Sequelize from 'sequelize'
4 import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Model, Table, UpdatedAt } from 'sequelize-typescript'
5 import { FollowState } from '../../../shared/models/accounts'
6 import { FOLLOW_STATES } from '../../initializers/constants'
7 import { ServerModel } from '../server/server'
8 import { getSort } from '../utils'
9 import { AccountModel } from './account'
12 tableName: 'accountFollow',
15 fields: [ 'accountId' ]
18 fields: [ 'targetAccountId' ]
21 fields: [ 'accountId', 'targetAccountId' ],
26 export class AccountFollowModel extends Model<AccountFollowModel> {
29 @Column(DataType.ENUM(values(FOLLOW_STATES)))
38 @ForeignKey(() => AccountModel)
42 @BelongsTo(() => AccountModel, {
47 as: 'AccountFollower',
50 AccountFollower: AccountModel
52 @ForeignKey(() => AccountModel)
54 targetAccountId: number
56 @BelongsTo(() => AccountModel, {
58 name: 'targetAccountId',
61 as: 'AccountFollowing',
64 AccountFollowing: AccountModel
66 static loadByAccountAndTarget (accountId: number, targetAccountId: number, t?: Sequelize.Transaction) {
81 as: 'AccountFollowing'
87 return AccountFollowModel.findOne(query)
90 static listFollowingForApi (id: number, start: number, count: number, sort: string) {
95 order: [ getSort(sort) ],
100 as: 'AccountFollower',
107 as: 'AccountFollowing',
109 include: [ ServerModel ]
114 return AccountFollowModel.findAndCountAll(query)
115 .then(({ rows, count }) => {
123 static listFollowersForApi (id: number, start: number, count: number, sort: string) {
128 order: [ getSort(sort) ],
133 as: 'AccountFollower',
134 include: [ ServerModel ]
138 as: 'AccountFollowing',
147 return AccountFollowModel.findAndCountAll(query)
148 .then(({ rows, count }) => {
156 static listAcceptedFollowerUrlsForApi (accountIds: number[], t: Sequelize.Transaction, start?: number, count?: number) {
157 return AccountFollowModel.createListAcceptedFollowForApiQuery('followers', accountIds, t, start, count)
160 static listAcceptedFollowerSharedInboxUrls (accountIds: number[], t: Sequelize.Transaction) {
161 return AccountFollowModel.createListAcceptedFollowForApiQuery('followers', accountIds, t, undefined, undefined, 'sharedInboxUrl')
164 static listAcceptedFollowingUrlsForApi (accountIds: number[], t: Sequelize.Transaction, start?: number, count?: number) {
165 return AccountFollowModel.createListAcceptedFollowForApiQuery('following', accountIds, t, start, count)
168 private static async createListAcceptedFollowForApiQuery (type: 'followers' | 'following',
169 accountIds: number[],
170 t: Sequelize.Transaction,
174 let firstJoin: string
175 let secondJoin: string
177 if (type === 'followers') {
178 firstJoin = 'targetAccountId'
179 secondJoin = 'accountId'
181 firstJoin = 'accountId'
182 secondJoin = 'targetAccountId'
185 const selections = [ '"Follows"."' + columnUrl + '" AS "url"', 'COUNT(*) AS "total"' ]
186 const tasks: Bluebird<any>[] = []
188 for (const selection of selections) {
189 let query = 'SELECT ' + selection + ' FROM "account" ' +
190 'INNER JOIN "accountFollow" ON "accountFollow"."' + firstJoin + '" = "account"."id" ' +
191 'INNER JOIN "account" AS "Follows" ON "accountFollow"."' + secondJoin + '" = "Follows"."id" ' +
192 'WHERE "account"."id" = ANY ($accountIds) AND "accountFollow"."state" = \'accepted\' '
194 if (count !== undefined) query += 'LIMIT ' + count
195 if (start !== undefined) query += ' OFFSET ' + start
198 bind: { accountIds },
199 type: Sequelize.QueryTypes.SELECT,
202 tasks.push(AccountFollowModel.sequelize.query(query, options))
205 const [ followers, [ { total } ] ] = await
207 const urls: string[] = followers.map(f => f.url)
211 total: parseInt(total, 10)
216 const follower = this.AccountFollower.toFormattedJSON()
217 const following = this.AccountFollowing.toFormattedJSON()
224 createdAt: this.createdAt,
225 updatedAt: this.updatedAt