]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/controllers/api/server/follows.ts
Merge branch 'master' into release/3.3.0
[github/Chocobozzz/PeerTube.git] / server / controllers / api / server / follows.ts
1 import * as express from 'express'
2 import { getServerActor } from '@server/models/application/application'
3 import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
4 import { UserRight } from '../../../../shared/models/users'
5 import { logger } from '../../../helpers/logger'
6 import { getFormattedObjects } from '../../../helpers/utils'
7 import { SERVER_ACTOR_NAME } from '../../../initializers/constants'
8 import { sequelizeTypescript } from '../../../initializers/database'
9 import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow'
10 import { sendAccept, sendReject, sendUndoFollow } from '../../../lib/activitypub/send'
11 import { JobQueue } from '../../../lib/job-queue'
12 import { removeRedundanciesOfServer } from '../../../lib/redundancy'
13 import {
14 asyncMiddleware,
15 authenticate,
16 ensureUserHasRight,
17 paginationValidator,
18 setBodyHostsPort,
19 setDefaultPagination,
20 setDefaultSort
21 } from '../../../middlewares'
22 import {
23 acceptOrRejectFollowerValidator,
24 followersSortValidator,
25 followingSortValidator,
26 followValidator,
27 getFollowerValidator,
28 listFollowsValidator,
29 removeFollowingValidator
30 } from '../../../middlewares/validators'
31 import { ActorFollowModel } from '../../../models/actor/actor-follow'
32
33 const serverFollowsRouter = express.Router()
34 serverFollowsRouter.get('/following',
35 listFollowsValidator,
36 paginationValidator,
37 followingSortValidator,
38 setDefaultSort,
39 setDefaultPagination,
40 asyncMiddleware(listFollowing)
41 )
42
43 serverFollowsRouter.post('/following',
44 authenticate,
45 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
46 followValidator,
47 setBodyHostsPort,
48 asyncMiddleware(followInstance)
49 )
50
51 serverFollowsRouter.delete('/following/:host',
52 authenticate,
53 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
54 asyncMiddleware(removeFollowingValidator),
55 asyncMiddleware(removeFollowing)
56 )
57
58 serverFollowsRouter.get('/followers',
59 listFollowsValidator,
60 paginationValidator,
61 followersSortValidator,
62 setDefaultSort,
63 setDefaultPagination,
64 asyncMiddleware(listFollowers)
65 )
66
67 serverFollowsRouter.delete('/followers/:nameWithHost',
68 authenticate,
69 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
70 asyncMiddleware(getFollowerValidator),
71 asyncMiddleware(removeOrRejectFollower)
72 )
73
74 serverFollowsRouter.post('/followers/:nameWithHost/reject',
75 authenticate,
76 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
77 asyncMiddleware(getFollowerValidator),
78 acceptOrRejectFollowerValidator,
79 asyncMiddleware(removeOrRejectFollower)
80 )
81
82 serverFollowsRouter.post('/followers/:nameWithHost/accept',
83 authenticate,
84 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
85 asyncMiddleware(getFollowerValidator),
86 acceptOrRejectFollowerValidator,
87 asyncMiddleware(acceptFollower)
88 )
89
90 // ---------------------------------------------------------------------------
91
92 export {
93 serverFollowsRouter
94 }
95
96 // ---------------------------------------------------------------------------
97
98 async function listFollowing (req: express.Request, res: express.Response) {
99 const serverActor = await getServerActor()
100 const resultList = await ActorFollowModel.listFollowingForApi({
101 id: serverActor.id,
102 start: req.query.start,
103 count: req.query.count,
104 sort: req.query.sort,
105 search: req.query.search,
106 actorType: req.query.actorType,
107 state: req.query.state
108 })
109
110 return res.json(getFormattedObjects(resultList.data, resultList.total))
111 }
112
113 async function listFollowers (req: express.Request, res: express.Response) {
114 const serverActor = await getServerActor()
115 const resultList = await ActorFollowModel.listFollowersForApi({
116 actorId: serverActor.id,
117 start: req.query.start,
118 count: req.query.count,
119 sort: req.query.sort,
120 search: req.query.search,
121 actorType: req.query.actorType,
122 state: req.query.state
123 })
124
125 return res.json(getFormattedObjects(resultList.data, resultList.total))
126 }
127
128 async function followInstance (req: express.Request, res: express.Response) {
129 const hosts = req.body.hosts as string[]
130 const follower = await getServerActor()
131
132 for (const host of hosts) {
133 const payload = {
134 host,
135 name: SERVER_ACTOR_NAME,
136 followerActorId: follower.id
137 }
138
139 JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
140 }
141
142 return res.status(HttpStatusCode.NO_CONTENT_204).end()
143 }
144
145 async function removeFollowing (req: express.Request, res: express.Response) {
146 const follow = res.locals.follow
147
148 await sequelizeTypescript.transaction(async t => {
149 if (follow.state === 'accepted') await sendUndoFollow(follow, t)
150
151 // Disable redundancy on unfollowed instances
152 const server = follow.ActorFollowing.Server
153 server.redundancyAllowed = false
154 await server.save({ transaction: t })
155
156 // Async, could be long
157 removeRedundanciesOfServer(server.id)
158 .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, err))
159
160 await follow.destroy({ transaction: t })
161 })
162
163 return res.status(HttpStatusCode.NO_CONTENT_204).end()
164 }
165
166 async function removeOrRejectFollower (req: express.Request, res: express.Response) {
167 const follow = res.locals.follow
168
169 await sendReject(follow.url, follow.ActorFollower, follow.ActorFollowing)
170
171 await follow.destroy()
172
173 return res.status(HttpStatusCode.NO_CONTENT_204).end()
174 }
175
176 async function acceptFollower (req: express.Request, res: express.Response) {
177 const follow = res.locals.follow
178
179 sendAccept(follow)
180
181 follow.state = 'accepted'
182 await follow.save()
183
184 await autoFollowBackIfNeeded(follow)
185
186 return res.status(HttpStatusCode.NO_CONTENT_204).end()
187 }