diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2017-11-15 10:10:41 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2017-11-27 19:40:51 +0100 |
commit | 51548b31815c6f96f314ae96588a9adca150519d (patch) | |
tree | b3298447b7ac128823016fdec92d083e07d9432e /server | |
parent | 350e31d6b64e4973dfa5e9f7b46841cb09aeb1ad (diff) | |
download | PeerTube-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.ts | 4 | ||||
-rw-r--r-- | server/controllers/activitypub/index.ts | 5 | ||||
-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.ts | 12 | ||||
-rw-r--r-- | server/controllers/api/index.ts | 4 | ||||
-rw-r--r-- | server/controllers/webfinger.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/send-request.ts | 2 | ||||
-rw-r--r-- | server/models/account/account-follow-interface.ts | 16 | ||||
-rw-r--r-- | server/models/account/account-follow.ts | 130 | ||||
-rw-r--r-- | server/models/account/account-interface.ts | 8 | ||||
-rw-r--r-- | server/models/account/account.ts | 132 |
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 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | |||
3 | import { badRequest } from '../../helpers' | ||
4 | import { inboxRouter } from './inbox' | ||
5 | import { activityPubClientRouter } from './client' | 2 | import { activityPubClientRouter } from './client' |
3 | import { inboxRouter } from './inbox' | ||
6 | 4 | ||
7 | const activityPubRouter = express.Router() | 5 | const activityPubRouter = express.Router() |
8 | 6 | ||
9 | activityPubRouter.use('/', inboxRouter) | 7 | activityPubRouter.use('/', inboxRouter) |
10 | activityPubRouter.use('/', activityPubClientRouter) | 8 | activityPubRouter.use('/', activityPubClientRouter) |
11 | activityPubRouter.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 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { UserRight } from '../../../shared/models/users/user-right.enum' | 2 | import { UserRight } from '../../../../shared/models/users/user-right.enum' |
3 | import { getFormattedObjects } from '../../helpers' | 3 | import { getFormattedObjects } from '../../../helpers' |
4 | import { logger } from '../../helpers/logger' | 4 | import { logger } from '../../../helpers/logger' |
5 | import { getApplicationAccount } from '../../helpers/utils' | 5 | import { getApplicationAccount } from '../../../helpers/utils' |
6 | import { getAccountFromWebfinger } from '../../helpers/webfinger' | 6 | import { getAccountFromWebfinger } from '../../../helpers/webfinger' |
7 | import { SERVER_ACCOUNT_NAME } from '../../initializers/constants' | 7 | import { SERVER_ACCOUNT_NAME } from '../../../initializers/constants' |
8 | import { database as db } from '../../initializers/database' | 8 | import { database as db } from '../../../initializers/database' |
9 | import { sendFollow } from '../../lib/activitypub/send-request' | 9 | import { sendFollow } from '../../../lib/activitypub/send-request' |
10 | import { asyncMiddleware, paginationValidator, setFollowersSort, setPagination } from '../../middlewares' | 10 | import { asyncMiddleware, paginationValidator, setFollowersSort, setPagination } from '../../../middlewares' |
11 | import { authenticate } from '../../middlewares/oauth' | 11 | import { authenticate } from '../../../middlewares/oauth' |
12 | import { setBodyHostsPort } from '../../middlewares/pods' | 12 | import { setBodyHostsPort } from '../../../middlewares/pods' |
13 | import { setFollowingSort } from '../../middlewares/sort' | 13 | import { setFollowingSort } from '../../../middlewares/sort' |
14 | import { ensureUserHasRight } from '../../middlewares/user-right' | 14 | import { ensureUserHasRight } from '../../../middlewares/user-right' |
15 | import { followValidator } from '../../middlewares/validators/pods' | 15 | import { followValidator } from '../../../middlewares/validators/pods' |
16 | import { followersSortValidator, followingSortValidator } from '../../middlewares/validators/sort' | 16 | import { followersSortValidator, followingSortValidator } from '../../../middlewares/validators/sort' |
17 | 17 | ||
18 | const podsRouter = express.Router() | 18 | const applicationFollowsRouter = express.Router() |
19 | 19 | ||
20 | podsRouter.get('/following', | 20 | applicationFollowsRouter.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 | ||
28 | podsRouter.post('/follow', | 28 | applicationFollowsRouter.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 | ||
36 | podsRouter.get('/followers', | 36 | applicationFollowsRouter.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 | ||
46 | export { | 46 | export { |
47 | podsRouter | 47 | applicationFollowsRouter |
48 | } | 48 | } |
49 | 49 | ||
50 | // --------------------------------------------------------------------------- | 50 | // --------------------------------------------------------------------------- |
51 | 51 | ||
52 | async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) { | 52 | async 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 | ||
59 | async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) { | 59 | async 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 @@ | |||
1 | import * as express from 'express' | ||
2 | import { applicationFollowsRouter } from './follows' | ||
3 | |||
4 | const applicationRouter = express.Router() | ||
5 | |||
6 | applicationRouter.use('/', applicationFollowsRouter) | ||
7 | |||
8 | // --------------------------------------------------------------------------- | ||
9 | |||
10 | export { | ||
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 | ||
5 | import { oauthClientsRouter } from './oauth-clients' | 5 | import { oauthClientsRouter } from './oauth-clients' |
6 | import { configRouter } from './config' | 6 | import { configRouter } from './config' |
7 | import { podsRouter } from './pods' | 7 | import { applicationRouter } from './application' |
8 | import { usersRouter } from './users' | 8 | import { usersRouter } from './users' |
9 | import { videosRouter } from './videos' | 9 | import { videosRouter } from './videos' |
10 | 10 | ||
11 | const apiRouter = express.Router() | 11 | const apiRouter = express.Router() |
12 | 12 | ||
13 | apiRouter.use('/application', applicationRouter) | ||
13 | apiRouter.use('/oauth-clients', oauthClientsRouter) | 14 | apiRouter.use('/oauth-clients', oauthClientsRouter) |
14 | apiRouter.use('/config', configRouter) | 15 | apiRouter.use('/config', configRouter) |
15 | apiRouter.use('/pods', podsRouter) | ||
16 | apiRouter.use('/users', usersRouter) | 16 | apiRouter.use('/users', usersRouter) |
17 | apiRouter.use('/videos', videosRouter) | 17 | apiRouter.use('/videos', videosRouter) |
18 | apiRouter.use('/ping', pong) | 18 | apiRouter.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 | ||
9 | const webfingerRouter = express.Router() | 9 | const webfingerRouter = express.Router() |
10 | 10 | ||
11 | webfingerRouter.use('/.well-known/webfinger', | 11 | webfingerRouter.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 | ||
87 | async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) { | 87 | async 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 @@ | |||
1 | import * as Sequelize from 'sequelize' | 1 | import * as Sequelize from 'sequelize' |
2 | import * as Bluebird from 'bluebird' | 2 | import * as Bluebird from 'bluebird' |
3 | import { FollowState } from '../../../shared/models/accounts/follow.model' | 3 | import { FollowState } from '../../../shared/models/accounts/follow.model' |
4 | import { ResultList } from '../../../shared/models/result-list.model' | ||
5 | import { AccountInstance } from './account-interface' | ||
4 | 6 | ||
5 | export namespace AccountFollowMethods { | 7 | export 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 | ||
9 | export interface AccountFollowClass { | 17 | export 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 | ||
13 | export interface AccountFollowAttributes { | 26 | export 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 | ||
25 | export interface AccountFollowModel extends AccountFollowClass, Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> {} | 41 | export 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 @@ | |||
1 | import { values } from 'lodash' | 1 | import { values } from 'lodash' |
2 | import * as Sequelize from 'sequelize' | 2 | import * as Sequelize from 'sequelize' |
3 | 3 | ||
4 | import { addMethodsToModel } from '../utils' | 4 | import { addMethodsToModel, getSort } from '../utils' |
5 | import { AccountFollowAttributes, AccountFollowInstance, AccountFollowMethods } from './account-follow-interface' | 5 | import { AccountFollowAttributes, AccountFollowInstance, AccountFollowMethods } from './account-follow-interface' |
6 | import { FOLLOW_STATES } from '../../initializers/constants' | 6 | import { FOLLOW_STATES } from '../../initializers/constants' |
7 | 7 | ||
8 | let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> | 8 | let AccountFollow: Sequelize.Model<AccountFollowInstance, AccountFollowAttributes> |
9 | let loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget | 9 | let loadByAccountAndTarget: AccountFollowMethods.LoadByAccountAndTarget |
10 | let listFollowingForApi: AccountFollowMethods.ListFollowingForApi | ||
11 | let listFollowersForApi: AccountFollowMethods.ListFollowersForApi | ||
12 | let listAcceptedFollowerUrlsForApi: AccountFollowMethods.ListAcceptedFollowerUrlsForApi | ||
13 | let listAcceptedFollowingUrlsForApi: AccountFollowMethods.ListAcceptedFollowingUrlsForApi | ||
10 | 14 | ||
11 | export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) { | 15 | export 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 | |||
85 | listFollowingForApi = 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 | |||
117 | listFollowersForApi = 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 | |||
149 | listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) { | ||
150 | return createListAcceptedFollowForApiQuery('followers', id, start, count) | ||
151 | } | ||
152 | |||
153 | listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) { | ||
154 | return createListAcceptedFollowForApiQuery('following', id, start, count) | ||
155 | } | ||
156 | |||
157 | // ------------------------------ UTILS ------------------------------ | ||
158 | |||
159 | async 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 | ||
47 | export interface AccountAttributes { | 39 | export 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' |
25 | import { sendDeleteAccount } from '../../lib/activitypub/send-request' | 25 | import { sendDeleteAccount } from '../../lib/activitypub/send-request' |
26 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 26 | import { CONFIG, CONSTRAINTS_FIELDS } from '../../initializers/constants' |
27 | 27 | ||
28 | let Account: Sequelize.Model<AccountInstance, AccountAttributes> | 28 | let Account: Sequelize.Model<AccountInstance, AccountAttributes> |
29 | let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID | 29 | let loadAccountByPodAndUUID: AccountMethods.LoadAccountByPodAndUUID |
@@ -34,10 +34,6 @@ let loadByUrl: AccountMethods.LoadByUrl | |||
34 | let loadLocalByName: AccountMethods.LoadLocalByName | 34 | let loadLocalByName: AccountMethods.LoadLocalByName |
35 | let loadByNameAndHost: AccountMethods.LoadByNameAndHost | 35 | let loadByNameAndHost: AccountMethods.LoadByNameAndHost |
36 | let listOwned: AccountMethods.ListOwned | 36 | let listOwned: AccountMethods.ListOwned |
37 | let listAcceptedFollowerUrlsForApi: AccountMethods.ListAcceptedFollowerUrlsForApi | ||
38 | let listAcceptedFollowingUrlsForApi: AccountMethods.ListAcceptedFollowingUrlsForApi | ||
39 | let listFollowingForApi: AccountMethods.ListFollowingForApi | ||
40 | let listFollowersForApi: AccountMethods.ListFollowersForApi | ||
41 | let isOwned: AccountMethods.IsOwned | 37 | let isOwned: AccountMethods.IsOwned |
42 | let toActivityPubObject: AccountMethods.ToActivityPubObject | 38 | let toActivityPubObject: AccountMethods.ToActivityPubObject |
43 | let toFormattedJSON: AccountMethods.ToFormattedJSON | 39 | let 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 | ||
288 | toFormattedJSON = function (this: AccountInstance) { | 280 | toFormattedJSON = 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 | ||
348 | getFollowingUrl = function (this: AccountInstance) { | 342 | getFollowingUrl = function (this: AccountInstance) { |
349 | return this.url + '/followers' | 343 | return this.url + '/following' |
350 | } | 344 | } |
351 | 345 | ||
352 | getFollowersUrl = function (this: AccountInstance) { | 346 | getFollowersUrl = function (this: AccountInstance) { |
@@ -369,76 +363,6 @@ listOwned = function () { | |||
369 | return Account.findAll(query) | 363 | return Account.findAll(query) |
370 | } | 364 | } |
371 | 365 | ||
372 | listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) { | ||
373 | return createListAcceptedFollowForApiQuery('followers', id, start, count) | ||
374 | } | ||
375 | |||
376 | listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) { | ||
377 | return createListAcceptedFollowForApiQuery('following', id, start, count) | ||
378 | } | ||
379 | |||
380 | listFollowingForApi = 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 | |||
411 | listFollowersForApi = 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 | |||
442 | loadApplication = function () { | 366 | loadApplication = 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 | |||
533 | async 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 | } | ||