diff options
Diffstat (limited to 'server/controllers/api/application/follows.ts')
-rw-r--r-- | server/controllers/api/application/follows.ts | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/server/controllers/api/application/follows.ts b/server/controllers/api/application/follows.ts new file mode 100644 index 000000000..000bbd23e --- /dev/null +++ b/server/controllers/api/application/follows.ts | |||
@@ -0,0 +1,127 @@ | |||
1 | import * as express from 'express' | ||
2 | import { UserRight } from '../../../../shared/models/users/user-right.enum' | ||
3 | import { getFormattedObjects } from '../../../helpers' | ||
4 | import { logger } from '../../../helpers/logger' | ||
5 | import { getApplicationAccount } from '../../../helpers/utils' | ||
6 | import { getAccountFromWebfinger } from '../../../helpers/webfinger' | ||
7 | import { SERVER_ACCOUNT_NAME } from '../../../initializers/constants' | ||
8 | import { database as db } from '../../../initializers/database' | ||
9 | import { sendFollow } from '../../../lib/activitypub/send-request' | ||
10 | import { asyncMiddleware, paginationValidator, setFollowersSort, setPagination } from '../../../middlewares' | ||
11 | import { authenticate } from '../../../middlewares/oauth' | ||
12 | import { setBodyHostsPort } from '../../../middlewares/pods' | ||
13 | import { setFollowingSort } from '../../../middlewares/sort' | ||
14 | import { ensureUserHasRight } from '../../../middlewares/user-right' | ||
15 | import { followValidator } from '../../../middlewares/validators/pods' | ||
16 | import { followersSortValidator, followingSortValidator } from '../../../middlewares/validators/sort' | ||
17 | |||
18 | const applicationFollowsRouter = express.Router() | ||
19 | |||
20 | applicationFollowsRouter.get('/following', | ||
21 | paginationValidator, | ||
22 | followingSortValidator, | ||
23 | setFollowingSort, | ||
24 | setPagination, | ||
25 | asyncMiddleware(listFollowing) | ||
26 | ) | ||
27 | |||
28 | applicationFollowsRouter.post('/follow', | ||
29 | authenticate, | ||
30 | ensureUserHasRight(UserRight.MANAGE_APPLICATION_FOLLOW), | ||
31 | followValidator, | ||
32 | setBodyHostsPort, | ||
33 | asyncMiddleware(follow) | ||
34 | ) | ||
35 | |||
36 | applicationFollowsRouter.get('/followers', | ||
37 | paginationValidator, | ||
38 | followersSortValidator, | ||
39 | setFollowersSort, | ||
40 | setPagination, | ||
41 | asyncMiddleware(listFollowers) | ||
42 | ) | ||
43 | |||
44 | // --------------------------------------------------------------------------- | ||
45 | |||
46 | export { | ||
47 | applicationFollowsRouter | ||
48 | } | ||
49 | |||
50 | // --------------------------------------------------------------------------- | ||
51 | |||
52 | async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
53 | const applicationAccount = await getApplicationAccount() | ||
54 | const resultList = await db.AccountFollow.listFollowingForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort) | ||
55 | |||
56 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | ||
57 | } | ||
58 | |||
59 | async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
60 | const applicationAccount = await getApplicationAccount() | ||
61 | const resultList = await db.AccountFollow.listFollowersForApi(applicationAccount.id, req.query.start, req.query.count, req.query.sort) | ||
62 | |||
63 | return res.json(getFormattedObjects(resultList.data, resultList.total)) | ||
64 | } | ||
65 | |||
66 | async function follow (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
67 | const hosts = req.body.hosts as string[] | ||
68 | const fromAccount = await getApplicationAccount() | ||
69 | |||
70 | const tasks: Promise<any>[] = [] | ||
71 | const accountName = SERVER_ACCOUNT_NAME | ||
72 | |||
73 | for (const host of hosts) { | ||
74 | |||
75 | // We process each host in a specific transaction | ||
76 | // First, we add the follow request in the database | ||
77 | // Then we send the follow request to other account | ||
78 | const p = loadLocalOrGetAccountFromWebfinger(accountName, host) | ||
79 | .then(accountResult => { | ||
80 | let targetAccount = accountResult.account | ||
81 | |||
82 | return db.sequelize.transaction(async t => { | ||
83 | if (accountResult.loadedFromDB === false) { | ||
84 | targetAccount = await targetAccount.save({ transaction: t }) | ||
85 | } | ||
86 | |||
87 | const [ accountFollow ] = await db.AccountFollow.findOrCreate({ | ||
88 | where: { | ||
89 | accountId: fromAccount.id, | ||
90 | targetAccountId: targetAccount.id | ||
91 | }, | ||
92 | defaults: { | ||
93 | state: 'pending', | ||
94 | accountId: fromAccount.id, | ||
95 | targetAccountId: targetAccount.id | ||
96 | }, | ||
97 | transaction: t | ||
98 | }) | ||
99 | |||
100 | // Send a notification to remote server | ||
101 | if (accountFollow.state === 'pending') { | ||
102 | await sendFollow(fromAccount, targetAccount, t) | ||
103 | } | ||
104 | }) | ||
105 | }) | ||
106 | .catch(err => logger.warn('Cannot follow server %s.', `${accountName}@${host}`, err)) | ||
107 | |||
108 | tasks.push(p) | ||
109 | } | ||
110 | |||
111 | await Promise.all(tasks) | ||
112 | |||
113 | return res.status(204).end() | ||
114 | } | ||
115 | |||
116 | async function loadLocalOrGetAccountFromWebfinger (name: string, host: string) { | ||
117 | let loadedFromDB = true | ||
118 | let account = await db.Account.loadByNameAndHost(name, host) | ||
119 | |||
120 | if (!account) { | ||
121 | const nameWithDomain = name + '@' + host | ||
122 | account = await getAccountFromWebfinger(nameWithDomain) | ||
123 | loadedFromDB = false | ||
124 | } | ||
125 | |||
126 | return { account, loadedFromDB } | ||
127 | } | ||