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