aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/controllers/api/server/follows.ts35
-rw-r--r--server/helpers/custom-validators/follows.ts14
-rw-r--r--server/middlewares/validators/follows.ts18
-rw-r--r--server/models/activitypub/actor-follow.ts28
-rw-r--r--server/tests/api/check-params/follows.ts44
-rw-r--r--server/tests/api/server/follows.ts26
6 files changed, 141 insertions, 24 deletions
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts
index 37647622b..e7fd3aabd 100644
--- a/server/controllers/api/server/follows.ts
+++ b/server/controllers/api/server/follows.ts
@@ -19,7 +19,8 @@ import {
19 followingSortValidator, 19 followingSortValidator,
20 followValidator, 20 followValidator,
21 getFollowerValidator, 21 getFollowerValidator,
22 removeFollowingValidator 22 removeFollowingValidator,
23 listFollowsValidator
23} from '../../../middlewares/validators' 24} from '../../../middlewares/validators'
24import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 25import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
25import { JobQueue } from '../../../lib/job-queue' 26import { JobQueue } from '../../../lib/job-queue'
@@ -29,6 +30,7 @@ import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow'
29 30
30const serverFollowsRouter = express.Router() 31const serverFollowsRouter = express.Router()
31serverFollowsRouter.get('/following', 32serverFollowsRouter.get('/following',
33 listFollowsValidator,
32 paginationValidator, 34 paginationValidator,
33 followingSortValidator, 35 followingSortValidator,
34 setDefaultSort, 36 setDefaultSort,
@@ -52,6 +54,7 @@ serverFollowsRouter.delete('/following/:host',
52) 54)
53 55
54serverFollowsRouter.get('/followers', 56serverFollowsRouter.get('/followers',
57 listFollowsValidator,
55 paginationValidator, 58 paginationValidator,
56 followersSortValidator, 59 followersSortValidator,
57 setDefaultSort, 60 setDefaultSort,
@@ -92,26 +95,28 @@ export {
92 95
93async function listFollowing (req: express.Request, res: express.Response) { 96async function listFollowing (req: express.Request, res: express.Response) {
94 const serverActor = await getServerActor() 97 const serverActor = await getServerActor()
95 const resultList = await ActorFollowModel.listFollowingForApi( 98 const resultList = await ActorFollowModel.listFollowingForApi({
96 serverActor.id, 99 id: serverActor.id,
97 req.query.start, 100 start: req.query.start,
98 req.query.count, 101 count: req.query.count,
99 req.query.sort, 102 sort: req.query.sort,
100 req.query.search 103 search: req.query.search,
101 ) 104 state: req.query.state
105 })
102 106
103 return res.json(getFormattedObjects(resultList.data, resultList.total)) 107 return res.json(getFormattedObjects(resultList.data, resultList.total))
104} 108}
105 109
106async function listFollowers (req: express.Request, res: express.Response) { 110async function listFollowers (req: express.Request, res: express.Response) {
107 const serverActor = await getServerActor() 111 const serverActor = await getServerActor()
108 const resultList = await ActorFollowModel.listFollowersForApi( 112 const resultList = await ActorFollowModel.listFollowersForApi({
109 serverActor.id, 113 actorId: serverActor.id,
110 req.query.start, 114 start: req.query.start,
111 req.query.count, 115 count: req.query.count,
112 req.query.sort, 116 sort: req.query.sort,
113 req.query.search 117 search: req.query.search,
114 ) 118 state: req.query.state
119 })
115 120
116 return res.json(getFormattedObjects(resultList.data, resultList.total)) 121 return res.json(getFormattedObjects(resultList.data, resultList.total))
117} 122}
diff --git a/server/helpers/custom-validators/follows.ts b/server/helpers/custom-validators/follows.ts
new file mode 100644
index 000000000..fbef7ad87
--- /dev/null
+++ b/server/helpers/custom-validators/follows.ts
@@ -0,0 +1,14 @@
1import { exists } from './misc'
2import { FollowState } from '@shared/models'
3
4function isFollowStateValid (value: FollowState) {
5 if (!exists(value)) return false
6
7 return value === 'pending' || value === 'accepted'
8}
9
10// ---------------------------------------------------------------------------
11
12export {
13 isFollowStateValid
14}
diff --git a/server/middlewares/validators/follows.ts b/server/middlewares/validators/follows.ts
index 788735663..454f9f2b8 100644
--- a/server/middlewares/validators/follows.ts
+++ b/server/middlewares/validators/follows.ts
@@ -1,5 +1,5 @@
1import * as express from 'express' 1import * as express from 'express'
2import { body, param } from 'express-validator' 2import { body, param, query } from 'express-validator'
3import { isTestInstance } from '../../helpers/core-utils' 3import { isTestInstance } from '../../helpers/core-utils'
4import { isEachUniqueHostValid, isHostValid } from '../../helpers/custom-validators/servers' 4import { isEachUniqueHostValid, isHostValid } from '../../helpers/custom-validators/servers'
5import { logger } from '../../helpers/logger' 5import { logger } from '../../helpers/logger'
@@ -11,6 +11,19 @@ import { ActorModel } from '../../models/activitypub/actor'
11import { loadActorUrlOrGetFromWebfinger } from '../../helpers/webfinger' 11import { loadActorUrlOrGetFromWebfinger } from '../../helpers/webfinger'
12import { isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor' 12import { isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor'
13import { MActorFollowActorsDefault } from '@server/typings/models' 13import { MActorFollowActorsDefault } from '@server/typings/models'
14import { isFollowStateValid } from '@server/helpers/custom-validators/follows'
15
16const listFollowsValidator = [
17 query('state')
18 .optional()
19 .custom(isFollowStateValid).withMessage('Should have a valid follow state'),
20
21 (req: express.Request, res: express.Response, next: express.NextFunction) => {
22 if (areValidationErrors(req, res)) return
23
24 return next()
25 }
26]
14 27
15const followValidator = [ 28const followValidator = [
16 body('hosts').custom(isEachUniqueHostValid).withMessage('Should have an array of unique hosts'), 29 body('hosts').custom(isEachUniqueHostValid).withMessage('Should have an array of unique hosts'),
@@ -110,5 +123,6 @@ export {
110 followValidator, 123 followValidator,
111 removeFollowingValidator, 124 removeFollowingValidator,
112 getFollowerValidator, 125 getFollowerValidator,
113 acceptOrRejectFollowerValidator 126 acceptOrRejectFollowerValidator,
127 listFollowsValidator
114} 128}
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index 24272a40e..09bc6853d 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -292,12 +292,24 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
292 return ActorFollowModel.findAll(query) 292 return ActorFollowModel.findAll(query)
293 } 293 }
294 294
295 static listFollowingForApi (id: number, start: number, count: number, sort: string, search?: string) { 295 static listFollowingForApi (options: {
296 id: number,
297 start: number,
298 count: number,
299 sort: string,
300 state?: FollowState,
301 search?: string
302 }) {
303 const { id, start, count, sort, search, state } = options
304
305 const followWhere = state ? { state } : {}
306
296 const query = { 307 const query = {
297 distinct: true, 308 distinct: true,
298 offset: start, 309 offset: start,
299 limit: count, 310 limit: count,
300 order: getSort(sort), 311 order: getSort(sort),
312 where: followWhere,
301 include: [ 313 include: [
302 { 314 {
303 model: ActorModel, 315 model: ActorModel,
@@ -335,12 +347,24 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
335 }) 347 })
336 } 348 }
337 349
338 static listFollowersForApi (actorId: number, start: number, count: number, sort: string, search?: string) { 350 static listFollowersForApi (options: {
351 actorId: number,
352 start: number,
353 count: number,
354 sort: string,
355 state?: FollowState,
356 search?: string
357 }) {
358 const { actorId, start, count, sort, search, state } = options
359
360 const followWhere = state ? { state } : {}
361
339 const query = { 362 const query = {
340 distinct: true, 363 distinct: true,
341 offset: start, 364 offset: start,
342 limit: count, 365 limit: count,
343 order: getSort(sort), 366 order: getSort(sort),
367 where: followWhere,
344 include: [ 368 include: [
345 { 369 {
346 model: ActorModel, 370 model: ActorModel,
diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts
index 2eb54cb0a..488666a75 100644
--- a/server/tests/api/check-params/follows.ts
+++ b/server/tests/api/check-params/follows.ts
@@ -6,7 +6,7 @@ import {
6 cleanupTests, 6 cleanupTests,
7 createUser, 7 createUser,
8 flushAndRunServer, 8 flushAndRunServer,
9 makeDeleteRequest, 9 makeDeleteRequest, makeGetRequest,
10 makePostBodyRequest, 10 makePostBodyRequest,
11 ServerInfo, 11 ServerInfo,
12 setAccessTokensToServers, 12 setAccessTokensToServers,
@@ -131,6 +131,27 @@ describe('Test server follows API validators', function () {
131 it('Should fail with an incorrect sort', async function () { 131 it('Should fail with an incorrect sort', async function () {
132 await checkBadSortPagination(server.url, path) 132 await checkBadSortPagination(server.url, path)
133 }) 133 })
134
135 it('Should fail with an incorrect state', async function () {
136 await makeGetRequest({
137 url: server.url,
138 path,
139 query: {
140 state: 'blabla'
141 }
142 })
143 })
144
145 it('Should fail succeed with the correct params', async function () {
146 await makeGetRequest({
147 url: server.url,
148 path,
149 statusCodeExpected: 200,
150 query: {
151 state: 'accepted'
152 }
153 })
154 })
134 }) 155 })
135 156
136 describe('When listing followers', function () { 157 describe('When listing followers', function () {
@@ -147,6 +168,27 @@ describe('Test server follows API validators', function () {
147 it('Should fail with an incorrect sort', async function () { 168 it('Should fail with an incorrect sort', async function () {
148 await checkBadSortPagination(server.url, path) 169 await checkBadSortPagination(server.url, path)
149 }) 170 })
171
172 it('Should fail with an incorrect state', async function () {
173 await makeGetRequest({
174 url: server.url,
175 path,
176 query: {
177 state: 'blabla'
178 }
179 })
180 })
181
182 it('Should fail succeed with the correct params', async function () {
183 await makeGetRequest({
184 url: server.url,
185 path,
186 statusCodeExpected: 200,
187 query: {
188 state: 'accepted'
189 }
190 })
191 })
150 }) 192 })
151 193
152 describe('When removing a follower', function () { 194 describe('When removing a follower', function () {
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts
index e8d6f5138..36a061926 100644
--- a/server/tests/api/server/follows.ts
+++ b/server/tests/api/server/follows.ts
@@ -97,14 +97,23 @@ describe('Test follows', function () {
97 expect(server3Follow.state).to.equal('accepted') 97 expect(server3Follow.state).to.equal('accepted')
98 }) 98 })
99 99
100 it('Should search followings on server 1', async function () { 100 it('Should search/filter followings on server 1', async function () {
101 { 101 {
102 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', ':' + servers[1].port) 102 const search = ':' + servers[1].port
103 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', search)
103 const follows = res.body.data 104 const follows = res.body.data
104 105
105 expect(res.body.total).to.equal(1) 106 expect(res.body.total).to.equal(1)
106 expect(follows.length).to.equal(1) 107 expect(follows.length).to.equal(1)
107 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[1].port) 108 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[1].port)
109
110 const res2 = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', search, 'accepted')
111 expect(res2.body.total).to.equal(1)
112 expect(res2.body.data).to.have.lengthOf(1)
113
114 const res3 = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', search, 'pending')
115 expect(res3.body.total).to.equal(0)
116 expect(res3.body.data).to.have.lengthOf(0)
108 } 117 }
109 118
110 { 119 {
@@ -139,14 +148,23 @@ describe('Test follows', function () {
139 } 148 }
140 }) 149 })
141 150
142 it('Should search followers on server 2', async function () { 151 it('Should search/filter followers on server 2', async function () {
143 { 152 {
144 const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', servers[0].port + '') 153 const search = servers[0].port + ''
154 const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', search)
145 const follows = res.body.data 155 const follows = res.body.data
146 156
147 expect(res.body.total).to.equal(1) 157 expect(res.body.total).to.equal(1)
148 expect(follows.length).to.equal(1) 158 expect(follows.length).to.equal(1)
149 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[2].port) 159 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[2].port)
160
161 const res2 = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', search, 'accepted')
162 expect(res2.body.total).to.equal(1)
163 expect(res2.body.data).to.have.lengthOf(1)
164
165 const res3 = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', search, 'pending')
166 expect(res3.body.total).to.equal(0)
167 expect(res3.body.data).to.have.lengthOf(0)
150 } 168 }
151 169
152 { 170 {