]>
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 | ||
7a7724e6 C |
96 | loadByAccountAndTarget = function (accountId: number, targetAccountId: number) { |
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 | } | |
113 | ] | |
7a7724e6 C |
114 | } |
115 | ||
116 | return AccountFollow.findOne(query) | |
117 | } | |
51548b31 C |
118 | |
119 | listFollowingForApi = function (id: number, start: number, count: number, sort: string) { | |
120 | const query = { | |
121 | distinct: true, | |
122 | offset: start, | |
123 | limit: count, | |
124 | order: [ getSort(sort) ], | |
125 | include: [ | |
126 | { | |
127 | model: AccountFollow[ 'sequelize' ].models.Account, | |
128 | required: true, | |
129 | as: 'AccountFollower', | |
130 | where: { | |
131 | id | |
132 | } | |
133 | }, | |
134 | { | |
135 | model: AccountFollow['sequelize'].models.Account, | |
136 | as: 'AccountFollowing', | |
137 | required: true, | |
60862425 | 138 | include: [ AccountFollow['sequelize'].models.Server ] |
51548b31 C |
139 | } |
140 | ] | |
141 | } | |
142 | ||
143 | return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { | |
144 | return { | |
7e9334c3 | 145 | data: rows, |
51548b31 C |
146 | total: count |
147 | } | |
148 | }) | |
149 | } | |
150 | ||
151 | listFollowersForApi = function (id: number, start: number, count: number, sort: string) { | |
152 | const query = { | |
153 | distinct: true, | |
154 | offset: start, | |
155 | limit: count, | |
156 | order: [ getSort(sort) ], | |
157 | include: [ | |
158 | { | |
159 | model: AccountFollow[ 'sequelize' ].models.Account, | |
160 | required: true, | |
161 | as: 'AccountFollower', | |
60862425 | 162 | include: [ AccountFollow['sequelize'].models.Server ] |
51548b31 C |
163 | }, |
164 | { | |
165 | model: AccountFollow['sequelize'].models.Account, | |
166 | as: 'AccountFollowing', | |
167 | required: true, | |
168 | where: { | |
169 | id | |
170 | } | |
171 | } | |
172 | ] | |
173 | } | |
174 | ||
175 | return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { | |
176 | return { | |
7e9334c3 | 177 | data: rows, |
51548b31 C |
178 | total: count |
179 | } | |
180 | }) | |
181 | } | |
182 | ||
efc32059 C |
183 | listAcceptedFollowerUrlsForApi = function (accountIds: number[], start?: number, count?: number) { |
184 | return createListAcceptedFollowForApiQuery('followers', accountIds, start, count) | |
51548b31 C |
185 | } |
186 | ||
efc32059 C |
187 | listAcceptedFollowerSharedInboxUrls = function (accountIds: number[]) { |
188 | return createListAcceptedFollowForApiQuery('followers', accountIds, undefined, undefined, 'sharedInboxUrl') | |
189 | } | |
190 | ||
191 | listAcceptedFollowingUrlsForApi = function (accountIds: number[], start?: number, count?: number) { | |
192 | return createListAcceptedFollowForApiQuery('following', accountIds, start, count) | |
51548b31 C |
193 | } |
194 | ||
195 | // ------------------------------ UTILS ------------------------------ | |
196 | ||
efc32059 C |
197 | async function createListAcceptedFollowForApiQuery ( |
198 | type: 'followers' | 'following', | |
199 | accountIds: number[], | |
200 | start?: number, | |
201 | count?: number, | |
202 | columnUrl = 'url' | |
203 | ) { | |
51548b31 C |
204 | let firstJoin: string |
205 | let secondJoin: string | |
206 | ||
207 | if (type === 'followers') { | |
208 | firstJoin = 'targetAccountId' | |
209 | secondJoin = 'accountId' | |
210 | } else { | |
211 | firstJoin = 'accountId' | |
212 | secondJoin = 'targetAccountId' | |
213 | } | |
214 | ||
efc32059 | 215 | const selections = [ '"Follows"."' + columnUrl + '" AS "url"', 'COUNT(*) AS "total"' ] |
51548b31 C |
216 | const tasks: Promise<any>[] = [] |
217 | ||
218 | for (const selection of selections) { | |
8e10cf1a C |
219 | let query = 'SELECT ' + selection + ' FROM "Accounts" ' + |
220 | 'INNER JOIN "AccountFollows" ON "AccountFollows"."' + firstJoin + '" = "Accounts"."id" ' + | |
221 | 'INNER JOIN "Accounts" AS "Follows" ON "AccountFollows"."' + secondJoin + '" = "Follows"."id" ' + | |
d7d5611c | 222 | 'WHERE "Accounts"."id" = ANY ($accountIds) AND "AccountFollows"."state" = \'accepted\' ' |
51548b31 | 223 | |
e71bcc0f C |
224 | if (count !== undefined) query += 'LIMIT ' + count |
225 | if (start !== undefined) query += ' OFFSET ' + start | |
51548b31 C |
226 | |
227 | const options = { | |
d7d5611c | 228 | bind: { accountIds }, |
51548b31 C |
229 | type: Sequelize.QueryTypes.SELECT |
230 | } | |
231 | tasks.push(AccountFollow['sequelize'].query(query, options)) | |
232 | } | |
233 | ||
234 | const [ followers, [ { total } ]] = await Promise.all(tasks) | |
235 | const urls: string[] = followers.map(f => f.url) | |
236 | ||
237 | return { | |
238 | data: urls, | |
239 | total: parseInt(total, 10) | |
240 | } | |
241 | } |