aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2017-11-15 10:10:41 +0100
committerChocobozzz <florian.bigard@gmail.com>2017-11-27 19:40:51 +0100
commit51548b31815c6f96f314ae96588a9adca150519d (patch)
treeb3298447b7ac128823016fdec92d083e07d9432e /server
parent350e31d6b64e4973dfa5e9f7b46841cb09aeb1ad (diff)
downloadPeerTube-51548b31815c6f96f314ae96588a9adca150519d.tar.gz
PeerTube-51548b31815c6f96f314ae96588a9adca150519d.tar.zst
PeerTube-51548b31815c6f96f314ae96588a9adca150519d.zip
Add follow tabs
Following Follow Followers
Diffstat (limited to 'server')
-rw-r--r--server/controllers/activitypub/client.ts4
-rw-r--r--server/controllers/activitypub/index.ts5
-rw-r--r--server/controllers/api/application/follows.ts (renamed from server/controllers/api/pods.ts)50
-rw-r--r--server/controllers/api/application/index.ts12
-rw-r--r--server/controllers/api/index.ts4
-rw-r--r--server/controllers/webfinger.ts2
-rw-r--r--server/lib/activitypub/send-request.ts2
-rw-r--r--server/models/account/account-follow-interface.ts16
-rw-r--r--server/models/account/account-follow.ts130
-rw-r--r--server/models/account/account-interface.ts8
-rw-r--r--server/models/account/account.ts132
11 files changed, 193 insertions, 172 deletions
diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts
index 56a4054fa..49dd24e79 100644
--- a/server/controllers/activitypub/client.ts
+++ b/server/controllers/activitypub/client.ts
@@ -46,7 +46,7 @@ async function accountFollowersController (req: express.Request, res: express.Re
46 const page = req.params.page || 1 46 const page = req.params.page || 1
47 const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE) 47 const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE)
48 48
49 const result = await db.Account.listAcceptedFollowerUrlsForApi(account.id, start, count) 49 const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(account.id, start, count)
50 const activityPubResult = activityPubCollectionPagination(req.url, page, result) 50 const activityPubResult = activityPubCollectionPagination(req.url, page, result)
51 51
52 return res.json(activityPubResult) 52 return res.json(activityPubResult)
@@ -58,7 +58,7 @@ async function accountFollowingController (req: express.Request, res: express.Re
58 const page = req.params.page || 1 58 const page = req.params.page || 1
59 const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE) 59 const { start, count } = pageToStartAndCount(page, ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE)
60 60
61 const result = await db.Account.listAcceptedFollowingUrlsForApi(account.id, start, count) 61 const result = await db.AccountFollow.listAcceptedFollowingUrlsForApi(account.id, start, count)
62 const activityPubResult = activityPubCollectionPagination(req.url, page, result) 62 const activityPubResult = activityPubCollectionPagination(req.url, page, result)
63 63
64 return res.json(activityPubResult) 64 return res.json(activityPubResult)
diff --git a/server/controllers/activitypub/index.ts b/server/controllers/activitypub/index.ts
index 0c8574ef7..c5bec6448 100644
--- a/server/controllers/activitypub/index.ts
+++ b/server/controllers/activitypub/index.ts
@@ -1,14 +1,11 @@
1import * as express from 'express' 1import * as express from 'express'
2
3import { badRequest } from '../../helpers'
4import { inboxRouter } from './inbox'
5import { activityPubClientRouter } from './client' 2import { activityPubClientRouter } from './client'
3import { inboxRouter } from './inbox'
6 4
7const activityPubRouter = express.Router() 5const activityPubRouter = express.Router()
8 6
9activityPubRouter.use('/', inboxRouter) 7activityPubRouter.use('/', inboxRouter)
10activityPubRouter.use('/', activityPubClientRouter) 8activityPubRouter.use('/', activityPubClientRouter)
11activityPubRouter.use('/*', badRequest)
12 9
13// --------------------------------------------------------------------------- 10// ---------------------------------------------------------------------------
14 11
diff --git a/server/controllers/api/pods.ts b/server/controllers/api/application/follows.ts
index 0bd6971bb..000bbd23e 100644
--- a/server/controllers/api/pods.ts
+++ b/server/controllers/api/application/follows.ts
@@ -1,23 +1,23 @@
1import * as express from 'express' 1import * as express from 'express'
2import { UserRight } from '../../../shared/models/users/user-right.enum' 2import { UserRight } from '../../../../shared/models/users/user-right.enum'
3import { getFormattedObjects } from '../../helpers' 3import { getFormattedObjects } from '../../../helpers'
4import { logger } from '../../helpers/logger' 4import { logger } from '../../../helpers/logger'
5import { getApplicationAccount } from '../../helpers/utils' 5import { getApplicationAccount } from '../../../helpers/utils'
6import { getAccountFromWebfinger } from '../../helpers/webfinger' 6import { getAccountFromWebfinger } from '../../../helpers/webfinger'
7import { SERVER_ACCOUNT_NAME } from '../../initializers/constants' 7import { SERVER_ACCOUNT_NAME } from '../../../initializers/constants'
8import { database as db } from '../../initializers/database' 8import { database as db } from '../../../initializers/database'
9import { sendFollow } from '../../lib/activitypub/send-request' 9import { sendFollow } from '../../../lib/activitypub/send-request'
10import { asyncMiddleware, paginationValidator, setFollowersSort, setPagination } from '../../middlewares' 10import { asyncMiddleware, paginationValidator, setFollowersSort, setPagination } from '../../../middlewares'
11import { authenticate } from '../../middlewares/oauth' 11import { authenticate } from '../../../middlewares/oauth'
12import { setBodyHostsPort } from '../../middlewares/pods' 12import { setBodyHostsPort } from '../../../middlewares/pods'
13import { setFollowingSort } from '../../middlewares/sort' 13import { setFollowingSort } from '../../../middlewares/sort'
14import { ensureUserHasRight } from '../../middlewares/user-right' 14import { ensureUserHasRight } from '../../../middlewares/user-right'
15import { followValidator } from '../../middlewares/validators/pods' 15import { followValidator } from '../../../middlewares/validators/pods'
16import { followersSortValidator, followingSortValidator } from '../../middlewares/validators/sort' 16import { followersSortValidator, followingSortValidator } from '../../../middlewares/validators/sort'
17 17
18const podsRouter = express.Router() 18const applicationFollowsRouter = express.Router()
19 19
20podsRouter.get('/following', 20applicationFollowsRouter.get('/following',
21 paginationValidator, 21 paginationValidator,
22 followingSortValidator, 22 followingSortValidator,
23 setFollowingSort, 23 setFollowingSort,
@@ -25,15 +25,15 @@ podsRouter.get('/following',
25 asyncMiddleware(listFollowing) 25 asyncMiddleware(listFollowing)
26) 26)
27 27
28podsRouter.post('/follow', 28applicationFollowsRouter.post('/follow',
29 authenticate, 29 authenticate,
30 ensureUserHasRight(UserRight.MANAGE_PEERTUBE_FOLLOW), 30 ensureUserHasRight(UserRight.MANAGE_APPLICATION_FOLLOW),
31 followValidator, 31 followValidator,
32 setBodyHostsPort, 32 setBodyHostsPort,
33 asyncMiddleware(follow) 33 asyncMiddleware(follow)
34) 34)
35 35
36podsRouter.get('/followers', 36applicationFollowsRouter.get('/followers',
37 paginationValidator, 37 paginationValidator,
38 followersSortValidator, 38 followersSortValidator,
39 setFollowersSort, 39 setFollowersSort,
@@ -44,21 +44,21 @@ podsRouter.get('/followers',
44// --------------------------------------------------------------------------- 44// ---------------------------------------------------------------------------
45 45
46export { 46export {
47 podsRouter 47 applicationFollowsRouter
48} 48}
49 49
50// --------------------------------------------------------------------------- 50// ---------------------------------------------------------------------------
51 51
52async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) { 52async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) {
53 const applicationAccount = await getApplicationAccount() 53 const applicationAccount = await getApplicationAccount()
54 const resultList = await db.Account.listFollowingForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort) 54 const resultList = await db.AccountFollow.listFollowingForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort)
55 55
56 return res.json(getFormattedObjects(resultList.data, resultList.total)) 56 return res.json(getFormattedObjects(resultList.data, resultList.total))
57} 57}
58 58
59async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) { 59async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) {
60 const applicationAccount = await getApplicationAccount() 60 const applicationAccount = await getApplicationAccount()
61 const resultList = await db.Account.listFollowersForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort) 61 const resultList = await db.AccountFollow.listFollowersForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort)
62 62
63 return res.json(getFormattedObjects(resultList.data, resultList.total)) 63 return res.json(getFormattedObjects(resultList.data, resultList.total))
64} 64}
diff --git a/server/controllers/api/application/index.ts b/server/controllers/api/application/index.ts
new file mode 100644
index 000000000..011b971ed
--- /dev/null
+++ b/server/controllers/api/application/index.ts
@@ -0,0 +1,12 @@
1import * as express from 'express'
2import { applicationFollowsRouter } from './follows'
3
4const applicationRouter = express.Router()
5
6applicationRouter.use('/', applicationFollowsRouter)
7
8// ---------------------------------------------------------------------------
9
10export {
11 applicationRouter
12}
diff --git a/server/controllers/api/index.ts b/server/controllers/api/index.ts
index 2e949d531..a22c78cce 100644
--- a/server/controllers/api/index.ts
+++ b/server/controllers/api/index.ts
@@ -4,15 +4,15 @@ import { badRequest } from '../../helpers'
4 4
5import { oauthClientsRouter } from './oauth-clients' 5import { oauthClientsRouter } from './oauth-clients'
6import { configRouter } from './config' 6import { configRouter } from './config'
7import { podsRouter } from './pods' 7import { applicationRouter } from './application'
8import { usersRouter } from './users' 8import { usersRouter } from './users'
9import { videosRouter } from './videos' 9import { videosRouter } from './videos'
10 10
11const apiRouter = express.Router() 11const apiRouter = express.Router()
12 12
13apiRouter.use('/application', applicationRouter)
13apiRouter.use('/oauth-clients', oauthClientsRouter) 14apiRouter.use('/oauth-clients', oauthClientsRouter)
14apiRouter.use('/config', configRouter) 15apiRouter.use('/config', configRouter)
15apiRouter.use('/pods', podsRouter)
16apiRouter.use('/users', usersRouter) 16apiRouter.use('/users', usersRouter)
17apiRouter.use('/videos', videosRouter) 17apiRouter.use('/videos', videosRouter)
18apiRouter.use('/ping', pong) 18apiRouter.use('/ping', pong)
diff --git a/server/controllers/webfinger.ts b/server/controllers/webfinger.ts
index 1c726f0cb..102ac0937 100644
--- a/server/controllers/webfinger.ts
+++ b/server/controllers/webfinger.ts
@@ -8,7 +8,7 @@ import { AccountInstance } from '../models/account/account-interface'
8 8
9const webfingerRouter = express.Router() 9const webfingerRouter = express.Router()
10 10
11webfingerRouter.use('/.well-known/webfinger', 11webfingerRouter.get('/.well-known/webfinger',
12 webfingerValidator, 12 webfingerValidator,
13 webfingerController 13 webfingerController
14) 14)
diff --git a/server/lib/activitypub/send-request.ts b/server/lib/activitypub/send-request.ts
index d47040d6d..f942a2eba 100644
--- a/server/lib/activitypub/send-request.ts
+++ b/server/lib/activitypub/send-request.ts
@@ -85,7 +85,7 @@ export {
85// --------------------------------------------------------------------------- 85// ---------------------------------------------------------------------------
86 86
87async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) { 87async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) {
88 const result = await db.Account.listAcceptedFollowerUrlsForApi(fromAccount.id, 0) 88 const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(fromAccount.id, 0)
89 89
90 const jobPayload = { 90 const jobPayload = {
91 uris: result.data, 91 uris: result.data,
diff --git a/server/models/account/account-follow-interface.ts b/server/models/account/account-follow-interface.ts
index efdff915e..413dad190 100644
--- a/server/models/account/account-follow-interface.ts
+++ b/server/models/account/account-follow-interface.ts
@@ -1,13 +1,26 @@
1import * as Sequelize from 'sequelize' 1import * as Sequelize from 'sequelize'
2import * as Bluebird from 'bluebird' 2import * as Bluebird from 'bluebird'
3import { FollowState } from '../../../shared/models/accounts/follow.model' 3import { FollowState } from '../../../shared/models/accounts/follow.model'
4import { ResultList } from '../../../shared/models/result-list.model'
5import { AccountInstance } from './account-interface'
4 6
5export namespace AccountFollowMethods { 7export namespace AccountFollowMethods {
6 export type LoadByAccountAndTarget = (accountId: number, targetAccountId: number) => Bluebird<AccountFollowInstance> 8 export type LoadByAccountAndTarget = (accountId: number, targetAccountId: number) => Bluebird<AccountFollowInstance>
9
10 export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
11 export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
12
13 export type ListAcceptedFollowerUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
14 export type ListAcceptedFollowingUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
7} 15}
8 16
9export interface AccountFollowClass { 17export interface AccountFollowClass {
10 loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget 18 loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget
19 listFollowersForApi: AccountFollowMethods.ListFollowersForApi
20 listFollowingForApi: AccountFollowMethods.ListFollowingForApi
21
22 listAcceptedFollowerUrlsForApi: AccountFollowMethods.ListAcceptedFollowerUrlsForApi
23 listAcceptedFollowingUrlsForApi: AccountFollowMethods.ListAcceptedFollowingUrlsForApi
11} 24}
12 25
13export interface AccountFollowAttributes { 26export interface AccountFollowAttributes {
@@ -20,6 +33,9 @@ export interface AccountFollowInstance extends AccountFollowClass, AccountFollow
20 id: number 33 id: number
21 createdAt: Date 34 createdAt: Date
22 updatedAt: Date 35 updatedAt: Date
36
37 AccountFollower?: AccountInstance
38 AccountFollowing?: AccountInstance
23} 39}
24 40
25export interface AccountFollowModel extends AccountFollowClass, Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> {} 41export interface AccountFollowModel extends AccountFollowClass, Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> {}
diff --git a/server/models/account/account-follow.ts b/server/models/account/account-follow.ts
index 7c129ab9d..6d7592326 100644
--- a/server/models/account/account-follow.ts
+++ b/server/models/account/account-follow.ts
@@ -1,12 +1,16 @@
1import { values } from 'lodash' 1import { values } from 'lodash'
2import * as Sequelize from 'sequelize' 2import * as Sequelize from 'sequelize'
3 3
4import { addMethodsToModel } from '../utils' 4import { addMethodsToModel, getSort } from '../utils'
5import { AccountFollowAttributes, AccountFollowInstance, AccountFollowMethods } from './account-follow-interface' 5import { AccountFollowAttributes, AccountFollowInstance, AccountFollowMethods } from './account-follow-interface'
6import { FOLLOW_STATES } from '../../initializers/constants' 6import { FOLLOW_STATES } from '../../initializers/constants'
7 7
8let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> 8let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes>
9let loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget 9let loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget
10let listFollowingForApi: AccountFollowMethods.ListFollowingForApi
11let listFollowersForApi: AccountFollowMethods.ListFollowersForApi
12let listAcceptedFollowerUrlsForApi: AccountFollowMethods.ListAcceptedFollowerUrlsForApi
13let listAcceptedFollowingUrlsForApi: AccountFollowMethods.ListAcceptedFollowingUrlsForApi
10 14
11export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { 15export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
12 AccountFollow = sequelize.define<AccountFollowInstance, AccountFollowAttributes>('AccountFollow', 16 AccountFollow = sequelize.define<AccountFollowInstance, AccountFollowAttributes>('AccountFollow',
@@ -34,7 +38,11 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
34 38
35 const classMethods = [ 39 const classMethods = [
36 associate, 40 associate,
37 loadByAccountAndTarget 41 loadByAccountAndTarget,
42 listFollowingForApi,
43 listFollowersForApi,
44 listAcceptedFollowerUrlsForApi,
45 listAcceptedFollowingUrlsForApi
38 ] 46 ]
39 addMethodsToModel(AccountFollow, classMethods) 47 addMethodsToModel(AccountFollow, classMethods)
40 48
@@ -49,7 +57,7 @@ function associate (models) {
49 name: 'accountId', 57 name: 'accountId',
50 allowNull: false 58 allowNull: false
51 }, 59 },
52 as: 'accountFollowers', 60 as: 'AccountFollower',
53 onDelete: 'CASCADE' 61 onDelete: 'CASCADE'
54 }) 62 })
55 63
@@ -58,7 +66,7 @@ function associate (models) {
58 name: 'targetAccountId', 66 name: 'targetAccountId',
59 allowNull: false 67 allowNull: false
60 }, 68 },
61 as: 'accountFollowing', 69 as: 'AccountFollowing',
62 onDelete: 'CASCADE' 70 onDelete: 'CASCADE'
63 }) 71 })
64} 72}
@@ -73,3 +81,117 @@ loadByAccountAndTarget = function (accountId: number, targetAccountId: number) {
73 81
74 return AccountFollow.findOne(query) 82 return AccountFollow.findOne(query)
75} 83}
84
85listFollowingForApi = function (id: number, start: number, count: number, sort: string) {
86 const query = {
87 distinct: true,
88 offset: start,
89 limit: count,
90 order: [ getSort(sort) ],
91 include: [
92 {
93 model: AccountFollow[ 'sequelize' ].models.Account,
94 required: true,
95 as: 'AccountFollower',
96 where: {
97 id
98 }
99 },
100 {
101 model: AccountFollow['sequelize'].models.Account,
102 as: 'AccountFollowing',
103 required: true,
104 include: [ AccountFollow['sequelize'].models.Pod ]
105 }
106 ]
107 }
108
109 return AccountFollow.findAndCountAll(query).then(({ rows, count }) => {
110 return {
111 data: rows.map(r => r.AccountFollowing),
112 total: count
113 }
114 })
115}
116
117listFollowersForApi = function (id: number, start: number, count: number, sort: string) {
118 const query = {
119 distinct: true,
120 offset: start,
121 limit: count,
122 order: [ getSort(sort) ],
123 include: [
124 {
125 model: AccountFollow[ 'sequelize' ].models.Account,
126 required: true,
127 as: 'AccountFollower',
128 include: [ AccountFollow['sequelize'].models.Pod ]
129 },
130 {
131 model: AccountFollow['sequelize'].models.Account,
132 as: 'AccountFollowing',
133 required: true,
134 where: {
135 id
136 }
137 }
138 ]
139 }
140
141 return AccountFollow.findAndCountAll(query).then(({ rows, count }) => {
142 return {
143 data: rows.map(r => r.AccountFollower),
144 total: count
145 }
146 })
147}
148
149listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) {
150 return createListAcceptedFollowForApiQuery('followers', id, start, count)
151}
152
153listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) {
154 return createListAcceptedFollowForApiQuery('following', id, start, count)
155}
156
157// ------------------------------ UTILS ------------------------------
158
159async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) {
160 let firstJoin: string
161 let secondJoin: string
162
163 if (type === 'followers') {
164 firstJoin = 'targetAccountId'
165 secondJoin = 'accountId'
166 } else {
167 firstJoin = 'accountId'
168 secondJoin = 'targetAccountId'
169 }
170
171 const selections = [ '"Followers"."url" AS "url"', 'COUNT(*) AS "total"' ]
172 const tasks: Promise<any>[] = []
173
174 for (const selection of selections) {
175 let query = 'SELECT ' + selection + ' FROM "Account" ' +
176 'INNER JOIN "AccountFollow" ON "AccountFollow"."' + firstJoin + '" = "Account"."id" ' +
177 'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
178 'WHERE "Account"."id" = $id AND "AccountFollow"."state" = \'accepted\' ' +
179 'LIMIT ' + start
180
181 if (count !== undefined) query += ', ' + count
182
183 const options = {
184 bind: { id },
185 type: Sequelize.QueryTypes.SELECT
186 }
187 tasks.push(AccountFollow['sequelize'].query(query, options))
188 }
189
190 const [ followers, [ { total } ]] = await Promise.all(tasks)
191 const urls: string[] = followers.map(f => f.url)
192
193 return {
194 data: urls,
195 total: parseInt(total, 10)
196 }
197}
diff --git a/server/models/account/account-interface.ts b/server/models/account/account-interface.ts
index 6fc36ae9d..ce1afec02 100644
--- a/server/models/account/account-interface.ts
+++ b/server/models/account/account-interface.ts
@@ -15,10 +15,6 @@ export namespace AccountMethods {
15 export type LoadLocalByName = (name: string) => Bluebird<AccountInstance> 15 export type LoadLocalByName = (name: string) => Bluebird<AccountInstance>
16 export type LoadByNameAndHost = (name: string, host: string) => Bluebird<AccountInstance> 16 export type LoadByNameAndHost = (name: string, host: string) => Bluebird<AccountInstance>
17 export type ListOwned = () => Bluebird<AccountInstance[]> 17 export type ListOwned = () => Bluebird<AccountInstance[]>
18 export type ListAcceptedFollowerUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
19 export type ListAcceptedFollowingUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
20 export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
21 export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
22 18
23 export type ToActivityPubObject = (this: AccountInstance) => ActivityPubActor 19 export type ToActivityPubObject = (this: AccountInstance) => ActivityPubActor
24 export type ToFormattedJSON = (this: AccountInstance) => FormattedAccount 20 export type ToFormattedJSON = (this: AccountInstance) => FormattedAccount
@@ -38,10 +34,6 @@ export interface AccountClass {
38 loadLocalByName: AccountMethods.LoadLocalByName 34 loadLocalByName: AccountMethods.LoadLocalByName
39 loadByNameAndHost: AccountMethods.LoadByNameAndHost 35 loadByNameAndHost: AccountMethods.LoadByNameAndHost
40 listOwned: AccountMethods.ListOwned 36 listOwned: AccountMethods.ListOwned
41 listAcceptedFollowerUrlsForApi: AccountMethods.ListAcceptedFollowerUrlsForApi
42 listAcceptedFollowingUrlsForApi: AccountMethods.ListAcceptedFollowingUrlsForApi
43 listFollowingForApi: AccountMethods.ListFollowingForApi
44 listFollowersForApi: AccountMethods.ListFollowersForApi
45} 37}
46 38
47export interface AccountAttributes { 39export interface AccountAttributes {
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index d2293a939..e90eaae5e 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -23,7 +23,7 @@ import {
23 AccountMethods 23 AccountMethods
24} from './account-interface' 24} from './account-interface'
25import { sendDeleteAccount } from '../../lib/activitypub/send-request' 25import { sendDeleteAccount } from '../../lib/activitypub/send-request'
26import { CONSTRAINTS_FIELDS } from '../../initializers/constants' 26import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers/constants'
27 27
28let Account: Sequelize.Model<AccountInstance, AccountAttributes> 28let Account: Sequelize.Model<AccountInstance, AccountAttributes>
29let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID 29let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID
@@ -34,10 +34,6 @@ let loadByUrl: AccountMethods.LoadByUrl
34let loadLocalByName: AccountMethods.LoadLocalByName 34let loadLocalByName: AccountMethods.LoadLocalByName
35let loadByNameAndHost: AccountMethods.LoadByNameAndHost 35let loadByNameAndHost: AccountMethods.LoadByNameAndHost
36let listOwned: AccountMethods.ListOwned 36let listOwned: AccountMethods.ListOwned
37let listAcceptedFollowerUrlsForApi: AccountMethods.ListAcceptedFollowerUrlsForApi
38let listAcceptedFollowingUrlsForApi: AccountMethods.ListAcceptedFollowingUrlsForApi
39let listFollowingForApi: AccountMethods.ListFollowingForApi
40let listFollowersForApi: AccountMethods.ListFollowersForApi
41let isOwned: AccountMethods.IsOwned 37let isOwned: AccountMethods.IsOwned
42let toActivityPubObject: AccountMethods.ToActivityPubObject 38let toActivityPubObject: AccountMethods.ToActivityPubObject
43let toFormattedJSON: AccountMethods.ToFormattedJSON 39let toFormattedJSON: AccountMethods.ToFormattedJSON
@@ -185,7 +181,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
185 unique: true 181 unique: true
186 }, 182 },
187 { 183 {
188 fields: [ 'name', 'podId' ], 184 fields: [ 'name', 'podId', 'applicationId' ],
189 unique: true 185 unique: true
190 } 186 }
191 ], 187 ],
@@ -202,11 +198,7 @@ export default function defineAccount (sequelize: Sequelize.Sequelize, DataTypes
202 loadByUrl, 198 loadByUrl,
203 loadLocalByName, 199 loadLocalByName,
204 loadByNameAndHost, 200 loadByNameAndHost,
205 listOwned, 201 listOwned
206 listAcceptedFollowerUrlsForApi,
207 listAcceptedFollowingUrlsForApi,
208 listFollowingForApi,
209 listFollowersForApi
210 ] 202 ]
211 const instanceMethods = [ 203 const instanceMethods = [
212 isOwned, 204 isOwned,
@@ -286,9 +278,11 @@ function afterDestroy (account: AccountInstance) {
286} 278}
287 279
288toFormattedJSON = function (this: AccountInstance) { 280toFormattedJSON = function (this: AccountInstance) {
281 let host = this.Pod ? this.Pod.host : CONFIG.WEBSERVER.HOST
282
289 const json = { 283 const json = {
290 id: this.id, 284 id: this.id,
291 host: this.Pod.host, 285 host,
292 name: this.name 286 name: this.name
293 } 287 }
294 288
@@ -346,7 +340,7 @@ getFollowerSharedInboxUrls = function (this: AccountInstance) {
346} 340}
347 341
348getFollowingUrl = function (this: AccountInstance) { 342getFollowingUrl = function (this: AccountInstance) {
349 return this.url + '/followers' 343 return this.url + '/following'
350} 344}
351 345
352getFollowersUrl = function (this: AccountInstance) { 346getFollowersUrl = function (this: AccountInstance) {
@@ -369,76 +363,6 @@ listOwned = function () {
369 return Account.findAll(query) 363 return Account.findAll(query)
370} 364}
371 365
372listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) {
373 return createListAcceptedFollowForApiQuery('followers', id, start, count)
374}
375
376listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) {
377 return createListAcceptedFollowForApiQuery('following', id, start, count)
378}
379
380listFollowingForApi = function (id: number, start: number, count: number, sort: string) {
381 const query = {
382 distinct: true,
383 offset: start,
384 limit: count,
385 order: [ getSort(sort) ],
386 include: [
387 {
388 model: Account['sequelize'].models.AccountFollow,
389 required: true,
390 as: 'following',
391 include: [
392 {
393 model: Account['sequelize'].models.Account,
394 as: 'accountFollowing',
395 required: true,
396 include: [ Account['sequelize'].models.Pod ]
397 }
398 ]
399 }
400 ]
401 }
402
403 return Account.findAndCountAll(query).then(({ rows, count }) => {
404 return {
405 data: rows,
406 total: count
407 }
408 })
409}
410
411listFollowersForApi = function (id: number, start: number, count: number, sort: string) {
412 const query = {
413 distinct: true,
414 offset: start,
415 limit: count,
416 order: [ getSort(sort) ],
417 include: [
418 {
419 model: Account['sequelize'].models.AccountFollow,
420 required: true,
421 as: 'followers',
422 include: [
423 {
424 model: Account['sequelize'].models.Account,
425 as: 'accountFollowers',
426 required: true,
427 include: [ Account['sequelize'].models.Pod ]
428 }
429 ]
430 }
431 ]
432 }
433
434 return Account.findAndCountAll(query).then(({ rows, count }) => {
435 return {
436 data: rows,
437 total: count
438 }
439 })
440}
441
442loadApplication = function () { 366loadApplication = function () {
443 return Account.findOne({ 367 return Account.findOne({
444 include: [ 368 include: [
@@ -527,45 +451,3 @@ loadAccountByPodAndUUID = function (uuid: string, podId: number, transaction: Se
527 451
528 return Account.find(query) 452 return Account.find(query)
529} 453}
530
531// ------------------------------ UTILS ------------------------------
532
533async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) {
534 let firstJoin: string
535 let secondJoin: string
536
537 if (type === 'followers') {
538 firstJoin = 'targetAccountId'
539 secondJoin = 'accountId'
540 } else {
541 firstJoin = 'accountId'
542 secondJoin = 'targetAccountId'
543 }
544
545 const selections = [ '"Followers"."url" AS "url"', 'COUNT(*) AS "total"' ]
546 const tasks: Promise<any>[] = []
547
548 for (const selection of selections) {
549 let query = 'SELECT ' + selection + ' FROM "Account" ' +
550 'INNER JOIN "AccountFollow" ON "AccountFollow"."' + firstJoin + '" = "Account"."id" ' +
551 'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
552 'WHERE "Account"."id" = $id AND "AccountFollow"."state" = \'accepted\' ' +
553 'LIMIT ' + start
554
555 if (count !== undefined) query += ', ' + count
556
557 const options = {
558 bind: { id },
559 type: Sequelize.QueryTypes.SELECT
560 }
561 tasks.push(Account['sequelize'].query(query, options))
562 }
563
564 const [ followers, [ { total } ]] = await Promise.all(tasks)
565 const urls: string[] = followers.map(f => f.url)
566
567 return {
568 data: urls,
569 total: parseInt(total, 10)
570 }
571}