]>
Commit | Line | Data |
---|---|---|
7a7724e6 | 1 | import { values } from 'lodash' |
e4f97bab C |
2 | import * as Sequelize from 'sequelize' |
3 | ||
51548b31 | 4 | import { addMethodsToModel, getSort } from '../utils' |
7a7724e6 C |
5 | import { AccountFollowAttributes, AccountFollowInstance, AccountFollowMethods } from './account-follow-interface' |
6 | import { FOLLOW_STATES } from '../../initializers/constants' | |
e4f97bab C |
7 | |
8 | let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> | |
7a7724e6 | 9 | let loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget |
51548b31 C |
10 | let listFollowingForApi: AccountFollowMethods.ListFollowingForApi |
11 | let listFollowersForApi: AccountFollowMethods.ListFollowersForApi | |
12 | let listAcceptedFollowerUrlsForApi: AccountFollowMethods.ListAcceptedFollowerUrlsForApi | |
13 | let listAcceptedFollowingUrlsForApi: AccountFollowMethods.ListAcceptedFollowingUrlsForApi | |
efc32059 | 14 | let listAcceptedFollowerSharedInboxUrls: AccountFollowMethods.ListAcceptedFollowerSharedInboxUrls |
7e9334c3 | 15 | let toFormattedJSON: AccountFollowMethods.ToFormattedJSON |
e4f97bab C |
16 | |
17 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | |
18 | AccountFollow = sequelize.define<AccountFollowInstance, AccountFollowAttributes>('AccountFollow', | |
7a7724e6 C |
19 | { |
20 | state: { | |
21 | type: DataTypes.ENUM(values(FOLLOW_STATES)), | |
22 | allowNull: false | |
23 | } | |
24 | }, | |
e4f97bab C |
25 | { |
26 | indexes: [ | |
27 | { | |
350e31d6 C |
28 | fields: [ 'accountId' ] |
29 | }, | |
30 | { | |
31 | fields: [ 'targetAccountId' ] | |
e4f97bab C |
32 | }, |
33 | { | |
350e31d6 | 34 | fields: [ 'accountId', 'targetAccountId' ], |
e4f97bab C |
35 | unique: true |
36 | } | |
37 | ] | |
38 | } | |
39 | ) | |
40 | ||
41 | const classMethods = [ | |
350e31d6 | 42 | associate, |
51548b31 C |
43 | loadByAccountAndTarget, |
44 | listFollowingForApi, | |
45 | listFollowersForApi, | |
46 | listAcceptedFollowerUrlsForApi, | |
efc32059 C |
47 | listAcceptedFollowingUrlsForApi, |
48 | listAcceptedFollowerSharedInboxUrls | |
e4f97bab | 49 | ] |
7e9334c3 C |
50 | const instanceMethods = [ |
51 | toFormattedJSON | |
52 | ] | |
53 | addMethodsToModel(AccountFollow, classMethods, instanceMethods) | |
e4f97bab C |
54 | |
55 | return AccountFollow | |
56 | } | |
57 | ||
58 | // ------------------------------ STATICS ------------------------------ | |
59 | ||
60 | function associate (models) { | |
61 | AccountFollow.belongsTo(models.Account, { | |
62 | foreignKey: { | |
63 | name: 'accountId', | |
64 | allowNull: false | |
65 | }, | |
51548b31 | 66 | as: 'AccountFollower', |
e4f97bab C |
67 | onDelete: 'CASCADE' |
68 | }) | |
69 | ||
70 | AccountFollow.belongsTo(models.Account, { | |
71 | foreignKey: { | |
72 | name: 'targetAccountId', | |
73 | allowNull: false | |
74 | }, | |
51548b31 | 75 | as: 'AccountFollowing', |
e4f97bab C |
76 | onDelete: 'CASCADE' |
77 | }) | |
78 | } | |
7a7724e6 | 79 | |
7e9334c3 C |
80 | toFormattedJSON = function (this: AccountFollowInstance) { |
81 | const follower = this.AccountFollower.toFormattedJSON() | |
82 | const following = this.AccountFollowing.toFormattedJSON() | |
83 | ||
84 | const json = { | |
85 | id: this.id, | |
86 | follower, | |
87 | following, | |
88 | state: this.state, | |
89 | createdAt: this.createdAt, | |
90 | updatedAt: this.updatedAt | |
91 | } | |
92 | ||
93 | return json | |
94 | } | |
95 | ||
0032ebe9 | 96 | loadByAccountAndTarget = function (accountId: number, targetAccountId: number, t?: Sequelize.Transaction) { |
7a7724e6 C |
97 | const query = { |
98 | where: { | |
99 | accountId, | |
100 | targetAccountId | |
54141398 C |
101 | }, |
102 | include: [ | |
103 | { | |
104 | model: AccountFollow[ 'sequelize' ].models.Account, | |
105 | required: true, | |
106 | as: 'AccountFollower' | |
107 | }, | |
108 | { | |
109 | model: AccountFollow['sequelize'].models.Account, | |
110 | required: true, | |
111 | as: 'AccountFollowing' | |
112 | } | |
0032ebe9 C |
113 | ], |
114 | transaction: t | |
7a7724e6 C |
115 | } |
116 | ||
117 | return AccountFollow.findOne(query) | |
118 | } | |
51548b31 C |
119 | |
120 | listFollowingForApi = function (id: number, start: number, count: number, sort: string) { | |
121 | const query = { | |
122 | distinct: true, | |
123 | offset: start, | |
124 | limit: count, | |
125 | order: [ getSort(sort) ], | |
126 | include: [ | |
127 | { | |
128 | model: AccountFollow[ 'sequelize' ].models.Account, | |
129 | required: true, | |
130 | as: 'AccountFollower', | |
131 | where: { | |
132 | id | |
133 | } | |
134 | }, | |
135 | { | |
136 | model: AccountFollow['sequelize'].models.Account, | |
137 | as: 'AccountFollowing', | |
138 | required: true, | |
60862425 | 139 | include: [ AccountFollow['sequelize'].models.Server ] |
51548b31 C |
140 | } |
141 | ] | |
142 | } | |
143 | ||
144 | return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { | |
145 | return { | |
7e9334c3 | 146 | data: rows, |
51548b31 C |
147 | total: count |
148 | } | |
149 | }) | |
150 | } | |
151 | ||
152 | listFollowersForApi = function (id: number, start: number, count: number, sort: string) { | |
153 | const query = { | |
154 | distinct: true, | |
155 | offset: start, | |
156 | limit: count, | |
157 | order: [ getSort(sort) ], | |
158 | include: [ | |
159 | { | |
160 | model: AccountFollow[ 'sequelize' ].models.Account, | |
161 | required: true, | |
162 | as: 'AccountFollower', | |
60862425 | 163 | include: [ AccountFollow['sequelize'].models.Server ] |
51548b31 C |
164 | }, |
165 | { | |
166 | model: AccountFollow['sequelize'].models.Account, | |
167 | as: 'AccountFollowing', | |
168 | required: true, | |
169 | where: { | |
170 | id | |
171 | } | |
172 | } | |
173 | ] | |
174 | } | |
175 | ||
176 | return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { | |
177 | return { | |
7e9334c3 | 178 | data: rows, |
51548b31 C |
179 | total: count |
180 | } | |
181 | }) | |
182 | } | |
183 | ||
efc32059 C |
184 | listAcceptedFollowerUrlsForApi = function (accountIds: number[], start?: number, count?: number) { |
185 | return createListAcceptedFollowForApiQuery('followers', accountIds, start, count) | |
51548b31 C |
186 | } |
187 | ||
efc32059 C |
188 | listAcceptedFollowerSharedInboxUrls = function (accountIds: number[]) { |
189 | return createListAcceptedFollowForApiQuery('followers', accountIds, undefined, undefined, 'sharedInboxUrl') | |
190 | } | |
191 | ||
192 | listAcceptedFollowingUrlsForApi = function (accountIds: number[], start?: number, count?: number) { | |
193 | return createListAcceptedFollowForApiQuery('following', accountIds, start, count) | |
51548b31 C |
194 | } |
195 | ||
196 | // ------------------------------ UTILS ------------------------------ | |
197 | ||
efc32059 C |
198 | async function createListAcceptedFollowForApiQuery ( |
199 | type: 'followers' | 'following', | |
200 | accountIds: number[], | |
201 | start?: number, | |
202 | count?: number, | |
203 | columnUrl = 'url' | |
204 | ) { | |
51548b31 C |
205 | let firstJoin: string |
206 | let secondJoin: string | |
207 | ||
208 | if (type === 'followers') { | |
209 | firstJoin = 'targetAccountId' | |
210 | secondJoin = 'accountId' | |
211 | } else { | |
212 | firstJoin = 'accountId' | |
213 | secondJoin = 'targetAccountId' | |
214 | } | |
215 | ||
efc32059 | 216 | const selections = [ '"Follows"."' + columnUrl + '" AS "url"', 'COUNT(*) AS "total"' ] |
51548b31 C |
217 | const tasks: Promise<any>[] = [] |
218 | ||
219 | for (const selection of selections) { | |
8e10cf1a C |
220 | let query = 'SELECT ' + selection + ' FROM "Accounts" ' + |
221 | 'INNER JOIN "AccountFollows" ON "AccountFollows"."' + firstJoin + '" = "Accounts"."id" ' + | |
222 | 'INNER JOIN "Accounts" AS "Follows" ON "AccountFollows"."' + secondJoin + '" = "Follows"."id" ' + | |
d7d5611c | 223 | 'WHERE "Accounts"."id" = ANY ($accountIds) AND "AccountFollows"."state" = \'accepted\' ' |
51548b31 | 224 | |
e71bcc0f C |
225 | if (count !== undefined) query += 'LIMIT ' + count |
226 | if (start !== undefined) query += ' OFFSET ' + start | |
51548b31 C |
227 | |
228 | const options = { | |
d7d5611c | 229 | bind: { accountIds }, |
51548b31 C |
230 | type: Sequelize.QueryTypes.SELECT |
231 | } | |
232 | tasks.push(AccountFollow['sequelize'].query(query, options)) | |
233 | } | |
234 | ||
235 | const [ followers, [ { total } ]] = await Promise.all(tasks) | |
236 | const urls: string[] = followers.map(f => f.url) | |
237 | ||
238 | return { | |
239 | data: urls, | |
240 | total: parseInt(total, 10) | |
241 | } | |
242 | } |