]>
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 | |
81 | } | |
82 | } | |
83 | ||
84 | return AccountFollow.findOne(query) | |
85 | } | |
51548b31 C |
86 | |
87 | listFollowingForApi = function (id: number, start: number, count: number, sort: string) { | |
88 | const query = { | |
89 | distinct: true, | |
90 | offset: start, | |
91 | limit: count, | |
92 | order: [ getSort(sort) ], | |
93 | include: [ | |
94 | { | |
95 | model: AccountFollow[ 'sequelize' ].models.Account, | |
96 | required: true, | |
97 | as: 'AccountFollower', | |
98 | where: { | |
99 | id | |
100 | } | |
101 | }, | |
102 | { | |
103 | model: AccountFollow['sequelize'].models.Account, | |
104 | as: 'AccountFollowing', | |
105 | required: true, | |
60862425 | 106 | include: [ AccountFollow['sequelize'].models.Server ] |
51548b31 C |
107 | } |
108 | ] | |
109 | } | |
110 | ||
111 | return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { | |
112 | return { | |
113 | data: rows.map(r => r.AccountFollowing), | |
114 | total: count | |
115 | } | |
116 | }) | |
117 | } | |
118 | ||
119 | listFollowersForApi = 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', | |
60862425 | 130 | include: [ AccountFollow['sequelize'].models.Server ] |
51548b31 C |
131 | }, |
132 | { | |
133 | model: AccountFollow['sequelize'].models.Account, | |
134 | as: 'AccountFollowing', | |
135 | required: true, | |
136 | where: { | |
137 | id | |
138 | } | |
139 | } | |
140 | ] | |
141 | } | |
142 | ||
143 | return AccountFollow.findAndCountAll(query).then(({ rows, count }) => { | |
144 | return { | |
145 | data: rows.map(r => r.AccountFollower), | |
146 | total: count | |
147 | } | |
148 | }) | |
149 | } | |
150 | ||
efc32059 C |
151 | listAcceptedFollowerUrlsForApi = function (accountIds: number[], start?: number, count?: number) { |
152 | return createListAcceptedFollowForApiQuery('followers', accountIds, start, count) | |
51548b31 C |
153 | } |
154 | ||
efc32059 C |
155 | listAcceptedFollowerSharedInboxUrls = function (accountIds: number[]) { |
156 | return createListAcceptedFollowForApiQuery('followers', accountIds, undefined, undefined, 'sharedInboxUrl') | |
157 | } | |
158 | ||
159 | listAcceptedFollowingUrlsForApi = function (accountIds: number[], start?: number, count?: number) { | |
160 | return createListAcceptedFollowForApiQuery('following', accountIds, start, count) | |
51548b31 C |
161 | } |
162 | ||
163 | // ------------------------------ UTILS ------------------------------ | |
164 | ||
efc32059 C |
165 | async function createListAcceptedFollowForApiQuery ( |
166 | type: 'followers' | 'following', | |
167 | accountIds: number[], | |
168 | start?: number, | |
169 | count?: number, | |
170 | columnUrl = 'url' | |
171 | ) { | |
51548b31 C |
172 | let firstJoin: string |
173 | let secondJoin: string | |
174 | ||
175 | if (type === 'followers') { | |
176 | firstJoin = 'targetAccountId' | |
177 | secondJoin = 'accountId' | |
178 | } else { | |
179 | firstJoin = 'accountId' | |
180 | secondJoin = 'targetAccountId' | |
181 | } | |
182 | ||
efc32059 | 183 | const selections = [ '"Follows"."' + columnUrl + '" AS "url"', 'COUNT(*) AS "total"' ] |
51548b31 C |
184 | const tasks: Promise<any>[] = [] |
185 | ||
186 | for (const selection of selections) { | |
8e10cf1a C |
187 | let query = 'SELECT ' + selection + ' FROM "Accounts" ' + |
188 | 'INNER JOIN "AccountFollows" ON "AccountFollows"."' + firstJoin + '" = "Accounts"."id" ' + | |
189 | 'INNER JOIN "Accounts" AS "Follows" ON "AccountFollows"."' + secondJoin + '" = "Follows"."id" ' + | |
d7d5611c | 190 | 'WHERE "Accounts"."id" = ANY ($accountIds) AND "AccountFollows"."state" = \'accepted\' ' |
51548b31 | 191 | |
8e10cf1a | 192 | if (start !== undefined) query += 'LIMIT ' + start |
51548b31 C |
193 | if (count !== undefined) query += ', ' + count |
194 | ||
195 | const options = { | |
d7d5611c | 196 | bind: { accountIds }, |
51548b31 C |
197 | type: Sequelize.QueryTypes.SELECT |
198 | } | |
199 | tasks.push(AccountFollow['sequelize'].query(query, options)) | |
200 | } | |
201 | ||
202 | const [ followers, [ { total } ]] = await Promise.all(tasks) | |
203 | const urls: string[] = followers.map(f => f.url) | |
204 | ||
205 | return { | |
206 | data: urls, | |
207 | total: parseInt(total, 10) | |
208 | } | |
209 | } |