aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/+about/about-follows/about-follows.component.html8
-rw-r--r--client/src/app/shared/instance/follow.service.ts10
-rw-r--r--server/controllers/api/server/follows.ts2
-rw-r--r--server/middlewares/validators/follows.ts5
-rw-r--r--server/models/activitypub/actor-follow.ts51
-rw-r--r--server/tests/api/check-params/follows.ts26
-rw-r--r--server/tests/api/redundancy/redundancy.ts4
-rw-r--r--server/tests/api/server/auto-follows.ts4
-rw-r--r--server/tests/api/server/follows-moderation.ts16
-rw-r--r--server/tests/api/server/follows.ts130
-rw-r--r--server/tests/api/server/handle-down.ts4
-rw-r--r--shared/extra-utils/server/follows.ts32
12 files changed, 216 insertions, 76 deletions
diff --git a/client/src/app/+about/about-follows/about-follows.component.html b/client/src/app/+about/about-follows/about-follows.component.html
index 5d7a50c74..ebe03bd94 100644
--- a/client/src/app/+about/about-follows/about-follows.component.html
+++ b/client/src/app/+about/about-follows/about-follows.component.html
@@ -1,8 +1,8 @@
1<div class="row" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()"> 1<div class="row" myInfiniteScroller [autoInit]="true" (nearOfBottom)="onNearOfBottom()" [dataObservable]="onDataSubject.asObservable()">
2 <div class="col-xl-6 col-md-12"> 2 <div class="col-xl-6 col-md-12">
3 <div i18n class="subtitle">Followers</div> 3 <div i18n class="subtitle">Followers instances</div>
4 4
5 <div i18n class="no-results" *ngIf="followersPagination.totalItems === 0">This instance does not have followers.</div> 5 <div i18n class="no-results" *ngIf="followersPagination.totalItems === 0">This instance does not have instances followers.</div>
6 6
7 <a *ngFor="let follower of followers" [href]="buildLink(follower)" target="_blank" rel="noopener noreferrer"> 7 <a *ngFor="let follower of followers" [href]="buildLink(follower)" target="_blank" rel="noopener noreferrer">
8 {{ follower }} 8 {{ follower }}
@@ -10,9 +10,9 @@
10 </div> 10 </div>
11 11
12 <div class="col-xl-6 col-md-12"> 12 <div class="col-xl-6 col-md-12">
13 <div i18n class="subtitle">Followings</div> 13 <div i18n class="subtitle">Followings instances</div>
14 14
15 <div i18n class="no-results" *ngIf="followingsPagination.totalItems === 0">This instance does not have followings.</div> 15 <div i18n class="no-results" *ngIf="followingsPagination.totalItems === 0">This instance does not have instances followings.</div>
16 16
17 <a *ngFor="let following of followings" [href]="buildLink(following)" target="_blank" rel="noopener noreferrer"> 17 <a *ngFor="let following of followings" [href]="buildLink(following)" target="_blank" rel="noopener noreferrer">
18 {{ following }} 18 {{ following }}
diff --git a/client/src/app/shared/instance/follow.service.ts b/client/src/app/shared/instance/follow.service.ts
index 1477a26ae..ef4c09583 100644
--- a/client/src/app/shared/instance/follow.service.ts
+++ b/client/src/app/shared/instance/follow.service.ts
@@ -2,7 +2,7 @@ import { catchError, map } from 'rxjs/operators'
2import { HttpClient, HttpParams } from '@angular/common/http' 2import { HttpClient, HttpParams } from '@angular/common/http'
3import { Injectable } from '@angular/core' 3import { Injectable } from '@angular/core'
4import { Observable } from 'rxjs' 4import { Observable } from 'rxjs'
5import { ActorFollow, FollowState, ResultList } from '@shared/index' 5import { ActivityPubActorType, ActorFollow, FollowState, ResultList } from '@shared/index'
6import { environment } from '../../../environments/environment' 6import { environment } from '../../../environments/environment'
7import { RestExtractor, RestPagination, RestService } from '../rest' 7import { RestExtractor, RestPagination, RestService } from '../rest'
8import { SortMeta } from 'primeng/api' 8import { SortMeta } from 'primeng/api'
@@ -22,15 +22,17 @@ export class FollowService {
22 pagination: RestPagination, 22 pagination: RestPagination,
23 sort: SortMeta, 23 sort: SortMeta,
24 search?: string, 24 search?: string,
25 actorType?: ActivityPubActorType,
25 state?: FollowState 26 state?: FollowState
26 }): Observable<ResultList<ActorFollow>> { 27 }): Observable<ResultList<ActorFollow>> {
27 const { pagination, sort, search, state } = options 28 const { pagination, sort, search, state, actorType } = options
28 29
29 let params = new HttpParams() 30 let params = new HttpParams()
30 params = this.restService.addRestGetParams(params, pagination, sort) 31 params = this.restService.addRestGetParams(params, pagination, sort)
31 32
32 if (search) params = params.append('search', search) 33 if (search) params = params.append('search', search)
33 if (state) params = params.append('state', state) 34 if (state) params = params.append('state', state)
35 if (actorType) params = params.append('actorType', actorType)
34 36
35 return this.authHttp.get<ResultList<ActorFollow>>(FollowService.BASE_APPLICATION_URL + '/following', { params }) 37 return this.authHttp.get<ResultList<ActorFollow>>(FollowService.BASE_APPLICATION_URL + '/following', { params })
36 .pipe( 38 .pipe(
@@ -43,15 +45,17 @@ export class FollowService {
43 pagination: RestPagination, 45 pagination: RestPagination,
44 sort: SortMeta, 46 sort: SortMeta,
45 search?: string, 47 search?: string,
48 actorType?: ActivityPubActorType,
46 state?: FollowState 49 state?: FollowState
47 }): Observable<ResultList<ActorFollow>> { 50 }): Observable<ResultList<ActorFollow>> {
48 const { pagination, sort, search, state } = options 51 const { pagination, sort, search, state, actorType } = options
49 52
50 let params = new HttpParams() 53 let params = new HttpParams()
51 params = this.restService.addRestGetParams(params, pagination, sort) 54 params = this.restService.addRestGetParams(params, pagination, sort)
52 55
53 if (search) params = params.append('search', search) 56 if (search) params = params.append('search', search)
54 if (state) params = params.append('state', state) 57 if (state) params = params.append('state', state)
58 if (actorType) params = params.append('actorType', actorType)
55 59
56 return this.authHttp.get<ResultList<ActorFollow>>(FollowService.BASE_APPLICATION_URL + '/followers', { params }) 60 return this.authHttp.get<ResultList<ActorFollow>>(FollowService.BASE_APPLICATION_URL + '/followers', { params })
57 .pipe( 61 .pipe(
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts
index e7fd3aabd..29a403a43 100644
--- a/server/controllers/api/server/follows.ts
+++ b/server/controllers/api/server/follows.ts
@@ -101,6 +101,7 @@ async function listFollowing (req: express.Request, res: express.Response) {
101 count: req.query.count, 101 count: req.query.count,
102 sort: req.query.sort, 102 sort: req.query.sort,
103 search: req.query.search, 103 search: req.query.search,
104 actorType: req.query.actorType,
104 state: req.query.state 105 state: req.query.state
105 }) 106 })
106 107
@@ -115,6 +116,7 @@ async function listFollowers (req: express.Request, res: express.Response) {
115 count: req.query.count, 116 count: req.query.count,
116 sort: req.query.sort, 117 sort: req.query.sort,
117 search: req.query.search, 118 search: req.query.search,
119 actorType: req.query.actorType,
118 state: req.query.state 120 state: req.query.state
119 }) 121 })
120 122
diff --git a/server/middlewares/validators/follows.ts b/server/middlewares/validators/follows.ts
index 454f9f2b8..a98d32d86 100644
--- a/server/middlewares/validators/follows.ts
+++ b/server/middlewares/validators/follows.ts
@@ -9,7 +9,7 @@ import { ActorFollowModel } from '../../models/activitypub/actor-follow'
9import { areValidationErrors } from './utils' 9import { areValidationErrors } from './utils'
10import { ActorModel } from '../../models/activitypub/actor' 10import { ActorModel } from '../../models/activitypub/actor'
11import { loadActorUrlOrGetFromWebfinger } from '../../helpers/webfinger' 11import { loadActorUrlOrGetFromWebfinger } from '../../helpers/webfinger'
12import { isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor' 12import { isActorTypeValid, 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' 14import { isFollowStateValid } from '@server/helpers/custom-validators/follows'
15 15
@@ -17,6 +17,9 @@ const listFollowsValidator = [
17 query('state') 17 query('state')
18 .optional() 18 .optional()
19 .custom(isFollowStateValid).withMessage('Should have a valid follow state'), 19 .custom(isFollowStateValid).withMessage('Should have a valid follow state'),
20 query('actorType')
21 .optional()
22 .custom(isActorTypeValid).withMessage('Should have a valid actor type'),
20 23
21 (req: express.Request, res: express.Response, next: express.NextFunction) => { 24 (req: express.Request, res: express.Response, next: express.NextFunction) => {
22 if (areValidationErrors(req, res)) return 25 if (areValidationErrors(req, res)) return
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index 09bc6853d..c3c4d61ab 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -27,7 +27,7 @@ import { createSafeIn, getSort } from '../utils'
27import { ActorModel, unusedActorAttributesForAPI } from './actor' 27import { ActorModel, unusedActorAttributesForAPI } from './actor'
28import { VideoChannelModel } from '../video/video-channel' 28import { VideoChannelModel } from '../video/video-channel'
29import { AccountModel } from '../account/account' 29import { AccountModel } from '../account/account'
30import { IncludeOptions, Op, QueryTypes, Transaction } from 'sequelize' 30import { IncludeOptions, Op, QueryTypes, Transaction, WhereOptions } from 'sequelize'
31import { 31import {
32 MActorFollowActorsDefault, 32 MActorFollowActorsDefault,
33 MActorFollowActorsDefaultSubscription, 33 MActorFollowActorsDefaultSubscription,
@@ -35,6 +35,7 @@ import {
35 MActorFollowFormattable, 35 MActorFollowFormattable,
36 MActorFollowSubscriptions 36 MActorFollowSubscriptions
37} from '@server/typings/models' 37} from '@server/typings/models'
38import { ActivityPubActorType } from '@shared/models'
38 39
39@Table({ 40@Table({
40 tableName: 'actorFollow', 41 tableName: 'actorFollow',
@@ -298,11 +299,26 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
298 count: number, 299 count: number,
299 sort: string, 300 sort: string,
300 state?: FollowState, 301 state?: FollowState,
302 actorType?: ActivityPubActorType,
301 search?: string 303 search?: string
302 }) { 304 }) {
303 const { id, start, count, sort, search, state } = options 305 const { id, start, count, sort, search, state, actorType } = options
304 306
305 const followWhere = state ? { state } : {} 307 const followWhere = state ? { state } : {}
308 const followingWhere: WhereOptions = {}
309 const followingServerWhere: WhereOptions = {}
310
311 if (search) {
312 Object.assign(followingServerWhere, {
313 host: {
314 [ Op.iLike ]: '%' + search + '%'
315 }
316 })
317 }
318
319 if (actorType) {
320 Object.assign(followingWhere, { type: actorType })
321 }
306 322
307 const query = { 323 const query = {
308 distinct: true, 324 distinct: true,
@@ -323,15 +339,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
323 model: ActorModel, 339 model: ActorModel,
324 as: 'ActorFollowing', 340 as: 'ActorFollowing',
325 required: true, 341 required: true,
342 where: followingWhere,
326 include: [ 343 include: [
327 { 344 {
328 model: ServerModel, 345 model: ServerModel,
329 required: true, 346 required: true,
330 where: search ? { 347 where: followingServerWhere
331 host: {
332 [Op.iLike]: '%' + search + '%'
333 }
334 } : undefined
335 } 348 }
336 ] 349 ]
337 } 350 }
@@ -353,11 +366,26 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
353 count: number, 366 count: number,
354 sort: string, 367 sort: string,
355 state?: FollowState, 368 state?: FollowState,
369 actorType?: ActivityPubActorType,
356 search?: string 370 search?: string
357 }) { 371 }) {
358 const { actorId, start, count, sort, search, state } = options 372 const { actorId, start, count, sort, search, state, actorType } = options
359 373
360 const followWhere = state ? { state } : {} 374 const followWhere = state ? { state } : {}
375 const followerWhere: WhereOptions = {}
376 const followerServerWhere: WhereOptions = {}
377
378 if (search) {
379 Object.assign(followerServerWhere, {
380 host: {
381 [ Op.iLike ]: '%' + search + '%'
382 }
383 })
384 }
385
386 if (actorType) {
387 Object.assign(followerWhere, { type: actorType })
388 }
361 389
362 const query = { 390 const query = {
363 distinct: true, 391 distinct: true,
@@ -370,15 +398,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
370 model: ActorModel, 398 model: ActorModel,
371 required: true, 399 required: true,
372 as: 'ActorFollower', 400 as: 'ActorFollower',
401 where: followerWhere,
373 include: [ 402 include: [
374 { 403 {
375 model: ServerModel, 404 model: ServerModel,
376 required: true, 405 required: true,
377 where: search ? { 406 where: followerServerWhere
378 host: {
379 [ Op.iLike ]: '%' + search + '%'
380 }
381 } : undefined
382 } 407 }
383 ] 408 ]
384 }, 409 },
diff --git a/server/tests/api/check-params/follows.ts b/server/tests/api/check-params/follows.ts
index 488666a75..be2a603a3 100644
--- a/server/tests/api/check-params/follows.ts
+++ b/server/tests/api/check-params/follows.ts
@@ -142,13 +142,24 @@ describe('Test server follows API validators', function () {
142 }) 142 })
143 }) 143 })
144 144
145 it('Should fail with an incorrect actor type', async function () {
146 await makeGetRequest({
147 url: server.url,
148 path,
149 query: {
150 actorType: 'blabla'
151 }
152 })
153 })
154
145 it('Should fail succeed with the correct params', async function () { 155 it('Should fail succeed with the correct params', async function () {
146 await makeGetRequest({ 156 await makeGetRequest({
147 url: server.url, 157 url: server.url,
148 path, 158 path,
149 statusCodeExpected: 200, 159 statusCodeExpected: 200,
150 query: { 160 query: {
151 state: 'accepted' 161 state: 'accepted',
162 actorType: 'Application'
152 } 163 }
153 }) 164 })
154 }) 165 })
@@ -169,12 +180,23 @@ describe('Test server follows API validators', function () {
169 await checkBadSortPagination(server.url, path) 180 await checkBadSortPagination(server.url, path)
170 }) 181 })
171 182
183 it('Should fail with an incorrect actor type', async function () {
184 await makeGetRequest({
185 url: server.url,
186 path,
187 query: {
188 actorType: 'blabla'
189 }
190 })
191 })
192
172 it('Should fail with an incorrect state', async function () { 193 it('Should fail with an incorrect state', async function () {
173 await makeGetRequest({ 194 await makeGetRequest({
174 url: server.url, 195 url: server.url,
175 path, 196 path,
176 query: { 197 query: {
177 state: 'blabla' 198 state: 'blabla',
199 actorType: 'Application'
178 } 200 }
179 }) 201 })
180 }) 202 })
diff --git a/server/tests/api/redundancy/redundancy.ts b/server/tests/api/redundancy/redundancy.ts
index 9e8733774..be24eb32f 100644
--- a/server/tests/api/redundancy/redundancy.ts
+++ b/server/tests/api/redundancy/redundancy.ts
@@ -247,7 +247,7 @@ async function checkStatsWith1Webseed (strategy: VideoRedundancyStrategy) {
247async function enableRedundancyOnServer1 () { 247async function enableRedundancyOnServer1 () {
248 await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true) 248 await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true)
249 249
250 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') 250 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' })
251 const follows: ActorFollow[] = res.body.data 251 const follows: ActorFollow[] = res.body.data
252 const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) 252 const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`)
253 const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) 253 const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`)
@@ -262,7 +262,7 @@ async function enableRedundancyOnServer1 () {
262async function disableRedundancyOnServer1 () { 262async function disableRedundancyOnServer1 () {
263 await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, false) 263 await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, false)
264 264
265 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, '-createdAt') 265 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' })
266 const follows: ActorFollow[] = res.body.data 266 const follows: ActorFollow[] = res.body.data
267 const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`) 267 const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`)
268 const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`) 268 const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`)
diff --git a/server/tests/api/server/auto-follows.ts b/server/tests/api/server/auto-follows.ts
index df468034c..a06f578fc 100644
--- a/server/tests/api/server/auto-follows.ts
+++ b/server/tests/api/server/auto-follows.ts
@@ -21,7 +21,7 @@ const expect = chai.expect
21 21
22async function checkFollow (follower: ServerInfo, following: ServerInfo, exists: boolean) { 22async function checkFollow (follower: ServerInfo, following: ServerInfo, exists: boolean) {
23 { 23 {
24 const res = await getFollowersListPaginationAndSort(following.url, 0, 5, '-createdAt') 24 const res = await getFollowersListPaginationAndSort({ url: following.url, start: 0, count: 5, sort: '-createdAt' })
25 const follows = res.body.data as ActorFollow[] 25 const follows = res.body.data as ActorFollow[]
26 26
27 const follow = follows.find(f => { 27 const follow = follows.find(f => {
@@ -36,7 +36,7 @@ async function checkFollow (follower: ServerInfo, following: ServerInfo, exists:
36 } 36 }
37 37
38 { 38 {
39 const res = await getFollowingListPaginationAndSort(follower.url, 0, 5, '-createdAt') 39 const res = await getFollowingListPaginationAndSort({ url: follower.url, start: 0, count: 5, sort: '-createdAt' })
40 const follows = res.body.data as ActorFollow[] 40 const follows = res.body.data as ActorFollow[]
41 41
42 const follow = follows.find(f => { 42 const follow = follows.find(f => {
diff --git a/server/tests/api/server/follows-moderation.ts b/server/tests/api/server/follows-moderation.ts
index a82acdb34..1984c9eb1 100644
--- a/server/tests/api/server/follows-moderation.ts
+++ b/server/tests/api/server/follows-moderation.ts
@@ -24,7 +24,7 @@ const expect = chai.expect
24 24
25async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') { 25async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') {
26 { 26 {
27 const res = await getFollowingListPaginationAndSort(servers[0].url, 0, 5, 'createdAt') 27 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' })
28 expect(res.body.total).to.equal(1) 28 expect(res.body.total).to.equal(1)
29 29
30 const follow = res.body.data[0] as ActorFollow 30 const follow = res.body.data[0] as ActorFollow
@@ -34,7 +34,7 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc
34 } 34 }
35 35
36 { 36 {
37 const res = await getFollowersListPaginationAndSort(servers[1].url, 0, 5, 'createdAt') 37 const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' })
38 expect(res.body.total).to.equal(1) 38 expect(res.body.total).to.equal(1)
39 39
40 const follow = res.body.data[0] as ActorFollow 40 const follow = res.body.data[0] as ActorFollow
@@ -46,12 +46,12 @@ async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'acc
46 46
47async function checkNoFollowers (servers: ServerInfo[]) { 47async function checkNoFollowers (servers: ServerInfo[]) {
48 { 48 {
49 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 5, 'createdAt') 49 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' })
50 expect(res.body.total).to.equal(0) 50 expect(res.body.total).to.equal(0)
51 } 51 }
52 52
53 { 53 {
54 const res = await getFollowersListPaginationAndSort(servers[ 1 ].url, 0, 5, 'createdAt') 54 const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' })
55 expect(res.body.total).to.equal(0) 55 expect(res.body.total).to.equal(0)
56 } 56 }
57} 57}
@@ -164,17 +164,17 @@ describe('Test follows moderation', function () {
164 await waitJobs(servers) 164 await waitJobs(servers)
165 165
166 { 166 {
167 const res = await getFollowingListPaginationAndSort(servers[0].url, 0, 5, 'createdAt') 167 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' })
168 expect(res.body.total).to.equal(2) 168 expect(res.body.total).to.equal(2)
169 } 169 }
170 170
171 { 171 {
172 const res = await getFollowersListPaginationAndSort(servers[1].url, 0, 5, 'createdAt') 172 const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' })
173 expect(res.body.total).to.equal(1) 173 expect(res.body.total).to.equal(1)
174 } 174 }
175 175
176 { 176 {
177 const res = await getFollowersListPaginationAndSort(servers[2].url, 0, 5, 'createdAt') 177 const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' })
178 expect(res.body.total).to.equal(1) 178 expect(res.body.total).to.equal(1)
179 } 179 }
180 180
@@ -184,7 +184,7 @@ describe('Test follows moderation', function () {
184 await checkServer1And2HasFollowers(servers) 184 await checkServer1And2HasFollowers(servers)
185 185
186 { 186 {
187 const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt') 187 const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' })
188 expect(res.body.total).to.equal(0) 188 expect(res.body.total).to.equal(0)
189 } 189 }
190 }) 190 })
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts
index 36a061926..dd85722a0 100644
--- a/server/tests/api/server/follows.ts
+++ b/server/tests/api/server/follows.ts
@@ -49,7 +49,7 @@ describe('Test follows', function () {
49 49
50 it('Should not have followers', async function () { 50 it('Should not have followers', async function () {
51 for (const server of servers) { 51 for (const server of servers) {
52 const res = await getFollowersListPaginationAndSort(server.url, 0, 5, 'createdAt') 52 const res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 5, sort: 'createdAt' })
53 const follows = res.body.data 53 const follows = res.body.data
54 54
55 expect(res.body.total).to.equal(0) 55 expect(res.body.total).to.equal(0)
@@ -60,7 +60,7 @@ describe('Test follows', function () {
60 60
61 it('Should not have following', async function () { 61 it('Should not have following', async function () {
62 for (const server of servers) { 62 for (const server of servers) {
63 const res = await getFollowingListPaginationAndSort(server.url, 0, 5, 'createdAt') 63 const res = await getFollowingListPaginationAndSort({ url: server.url, start: 0, count: 5, sort: 'createdAt' })
64 const follows = res.body.data 64 const follows = res.body.data
65 65
66 expect(res.body.total).to.equal(0) 66 expect(res.body.total).to.equal(0)
@@ -78,14 +78,14 @@ describe('Test follows', function () {
78 }) 78 })
79 79
80 it('Should have 2 followings on server 1', async function () { 80 it('Should have 2 followings on server 1', async function () {
81 let res = await getFollowingListPaginationAndSort(servers[0].url, 0, 1, 'createdAt') 81 let res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 1, sort: 'createdAt' })
82 let follows = res.body.data 82 let follows = res.body.data
83 83
84 expect(res.body.total).to.equal(2) 84 expect(res.body.total).to.equal(2)
85 expect(follows).to.be.an('array') 85 expect(follows).to.be.an('array')
86 expect(follows.length).to.equal(1) 86 expect(follows.length).to.equal(1)
87 87
88 res = await getFollowingListPaginationAndSort(servers[0].url, 1, 1, 'createdAt') 88 res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 1, count: 1, sort: 'createdAt' })
89 follows = follows.concat(res.body.data) 89 follows = follows.concat(res.body.data)
90 90
91 const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port) 91 const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port)
@@ -98,26 +98,58 @@ describe('Test follows', function () {
98 }) 98 })
99 99
100 it('Should search/filter followings on server 1', async function () { 100 it('Should search/filter followings on server 1', async function () {
101 const sort = 'createdAt'
102 const start = 0
103 const count = 1
104 const url = servers[ 0 ].url
105
101 { 106 {
102 const search = ':' + servers[1].port 107 const search = ':' + servers[1].port
103 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', search)
104 const follows = res.body.data
105 108
106 expect(res.body.total).to.equal(1) 109 {
107 expect(follows.length).to.equal(1) 110 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search })
108 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[1].port) 111 const follows = res.body.data
109 112
110 const res2 = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', search, 'accepted') 113 expect(res.body.total).to.equal(1)
111 expect(res2.body.total).to.equal(1) 114 expect(follows.length).to.equal(1)
112 expect(res2.body.data).to.have.lengthOf(1) 115 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 1 ].port)
116 }
117
118 {
119 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search, state: 'accepted' })
120 expect(res.body.total).to.equal(1)
121 expect(res.body.data).to.have.lengthOf(1)
122 }
113 123
114 const res3 = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', search, 'pending') 124 {
115 expect(res3.body.total).to.equal(0) 125 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search, state: 'accepted', actorType: 'Person' })
116 expect(res3.body.data).to.have.lengthOf(0) 126 expect(res.body.total).to.equal(0)
127 expect(res.body.data).to.have.lengthOf(0)
128 }
129
130 {
131 const res = await getFollowingListPaginationAndSort({
132 url,
133 start,
134 count,
135 sort,
136 search,
137 state: 'accepted',
138 actorType: 'Application'
139 })
140 expect(res.body.total).to.equal(1)
141 expect(res.body.data).to.have.lengthOf(1)
142 }
143
144 {
145 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search, state: 'pending' })
146 expect(res.body.total).to.equal(0)
147 expect(res.body.data).to.have.lengthOf(0)
148 }
117 } 149 }
118 150
119 { 151 {
120 const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', 'bla') 152 const res = await getFollowingListPaginationAndSort({ url, start, count, sort, search: 'bla' })
121 const follows = res.body.data 153 const follows = res.body.data
122 154
123 expect(res.body.total).to.equal(0) 155 expect(res.body.total).to.equal(0)
@@ -127,7 +159,7 @@ describe('Test follows', function () {
127 159
128 it('Should have 0 followings on server 2 and 3', async function () { 160 it('Should have 0 followings on server 2 and 3', async function () {
129 for (const server of [ servers[1], servers[2] ]) { 161 for (const server of [ servers[1], servers[2] ]) {
130 const res = await getFollowingListPaginationAndSort(server.url, 0, 5, 'createdAt') 162 const res = await getFollowingListPaginationAndSort({ url: server.url, start: 0, count: 5, sort: 'createdAt' })
131 const follows = res.body.data 163 const follows = res.body.data
132 164
133 expect(res.body.total).to.equal(0) 165 expect(res.body.total).to.equal(0)
@@ -138,7 +170,7 @@ describe('Test follows', function () {
138 170
139 it('Should have 1 followers on server 2 and 3', async function () { 171 it('Should have 1 followers on server 2 and 3', async function () {
140 for (const server of [ servers[1], servers[2] ]) { 172 for (const server of [ servers[1], servers[2] ]) {
141 let res = await getFollowersListPaginationAndSort(server.url, 0, 1, 'createdAt') 173 let res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' })
142 174
143 let follows = res.body.data 175 let follows = res.body.data
144 expect(res.body.total).to.equal(1) 176 expect(res.body.total).to.equal(1)
@@ -149,26 +181,58 @@ describe('Test follows', function () {
149 }) 181 })
150 182
151 it('Should search/filter followers on server 2', async function () { 183 it('Should search/filter followers on server 2', async function () {
184 const url = servers[ 2 ].url
185 const start = 0
186 const count = 5
187 const sort = 'createdAt'
188
152 { 189 {
153 const search = servers[0].port + '' 190 const search = servers[0].port + ''
154 const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', search)
155 const follows = res.body.data
156 191
157 expect(res.body.total).to.equal(1) 192 {
158 expect(follows.length).to.equal(1) 193 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search })
159 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[2].port) 194 const follows = res.body.data
160 195
161 const res2 = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', search, 'accepted') 196 expect(res.body.total).to.equal(1)
162 expect(res2.body.total).to.equal(1) 197 expect(follows.length).to.equal(1)
163 expect(res2.body.data).to.have.lengthOf(1) 198 expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 2 ].port)
199 }
200
201 {
202 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search, state: 'accepted' })
203 expect(res.body.total).to.equal(1)
204 expect(res.body.data).to.have.lengthOf(1)
205 }
164 206
165 const res3 = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', search, 'pending') 207 {
166 expect(res3.body.total).to.equal(0) 208 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search, state: 'accepted', actorType: 'Person' })
167 expect(res3.body.data).to.have.lengthOf(0) 209 expect(res.body.total).to.equal(0)
210 expect(res.body.data).to.have.lengthOf(0)
211 }
212
213 {
214 const res = await getFollowersListPaginationAndSort({
215 url,
216 start,
217 count,
218 sort,
219 search,
220 state: 'accepted',
221 actorType: 'Application'
222 })
223 expect(res.body.total).to.equal(1)
224 expect(res.body.data).to.have.lengthOf(1)
225 }
226
227 {
228 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search, state: 'pending' })
229 expect(res.body.total).to.equal(0)
230 expect(res.body.data).to.have.lengthOf(0)
231 }
168 } 232 }
169 233
170 { 234 {
171 const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', 'bla') 235 const res = await getFollowersListPaginationAndSort({ url, start, count, sort, search: 'bla' })
172 const follows = res.body.data 236 const follows = res.body.data
173 237
174 expect(res.body.total).to.equal(0) 238 expect(res.body.total).to.equal(0)
@@ -177,7 +241,7 @@ describe('Test follows', function () {
177 }) 241 })
178 242
179 it('Should have 0 followers on server 1', async function () { 243 it('Should have 0 followers on server 1', async function () {
180 const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 5, 'createdAt') 244 const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' })
181 const follows = res.body.data 245 const follows = res.body.data
182 246
183 expect(res.body.total).to.equal(0) 247 expect(res.body.total).to.equal(0)
@@ -207,7 +271,7 @@ describe('Test follows', function () {
207 }) 271 })
208 272
209 it('Should not follow server 3 on server 1 anymore', async function () { 273 it('Should not follow server 3 on server 1 anymore', async function () {
210 const res = await getFollowingListPaginationAndSort(servers[0].url, 0, 2, 'createdAt') 274 const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' })
211 let follows = res.body.data 275 let follows = res.body.data
212 276
213 expect(res.body.total).to.equal(1) 277 expect(res.body.total).to.equal(1)
@@ -218,7 +282,7 @@ describe('Test follows', function () {
218 }) 282 })
219 283
220 it('Should not have server 1 as follower on server 3 anymore', async function () { 284 it('Should not have server 1 as follower on server 3 anymore', async function () {
221 const res = await getFollowersListPaginationAndSort(servers[2].url, 0, 1, 'createdAt') 285 const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 1, sort: 'createdAt' })
222 286
223 let follows = res.body.data 287 let follows = res.body.data
224 expect(res.body.total).to.equal(0) 288 expect(res.body.total).to.equal(0)
diff --git a/server/tests/api/server/handle-down.ts b/server/tests/api/server/handle-down.ts
index 420289bf4..a0f505474 100644
--- a/server/tests/api/server/handle-down.ts
+++ b/server/tests/api/server/handle-down.ts
@@ -174,7 +174,7 @@ describe('Test handle downs', function () {
174 await wait(11000) 174 await wait(11000)
175 175
176 // Only server 3 is still a follower of server 1 176 // Only server 3 is still a follower of server 1
177 const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 2, 'createdAt') 177 const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' })
178 expect(res.body.data).to.be.an('array') 178 expect(res.body.data).to.be.an('array')
179 expect(res.body.data).to.have.lengthOf(1) 179 expect(res.body.data).to.have.lengthOf(1)
180 expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port) 180 expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port)
@@ -202,7 +202,7 @@ describe('Test handle downs', function () {
202 202
203 await waitJobs(servers) 203 await waitJobs(servers)
204 204
205 const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 2, 'createdAt') 205 const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' })
206 expect(res.body.data).to.be.an('array') 206 expect(res.body.data).to.be.an('array')
207 expect(res.body.data).to.have.lengthOf(2) 207 expect(res.body.data).to.have.lengthOf(2)
208 }) 208 })
diff --git a/shared/extra-utils/server/follows.ts b/shared/extra-utils/server/follows.ts
index 365263a22..3f7729c20 100644
--- a/shared/extra-utils/server/follows.ts
+++ b/shared/extra-utils/server/follows.ts
@@ -2,9 +2,18 @@ import * as request from 'supertest'
2import { ServerInfo } from './servers' 2import { ServerInfo } from './servers'
3import { waitJobs } from './jobs' 3import { waitJobs } from './jobs'
4import { makePostBodyRequest } from '../requests/requests' 4import { makePostBodyRequest } from '../requests/requests'
5import { FollowState } from '@shared/models' 5import { ActivityPubActorType, FollowState } from '@shared/models'
6 6
7function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string, state?: FollowState) { 7function getFollowersListPaginationAndSort (options: {
8 url: string,
9 start: number,
10 count: number,
11 sort: string,
12 search?: string,
13 actorType?: ActivityPubActorType,
14 state?: FollowState
15}) {
16 const { url, start, count, sort, search, state, actorType } = options
8 const path = '/api/v1/server/followers' 17 const path = '/api/v1/server/followers'
9 18
10 const query = { 19 const query = {
@@ -12,7 +21,8 @@ function getFollowersListPaginationAndSort (url: string, start: number, count: n
12 count, 21 count,
13 sort, 22 sort,
14 search, 23 search,
15 state 24 state,
25 actorType
16 } 26 }
17 27
18 return request(url) 28 return request(url)
@@ -45,7 +55,16 @@ function rejectFollower (url: string, token: string, follower: string, statusCod
45 }) 55 })
46} 56}
47 57
48function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string, state?: FollowState) { 58function getFollowingListPaginationAndSort (options: {
59 url: string,
60 start: number,
61 count: number,
62 sort: string,
63 search?: string,
64 actorType?: ActivityPubActorType,
65 state?: FollowState
66}) {
67 const { url, start, count, sort, search, state, actorType } = options
49 const path = '/api/v1/server/following' 68 const path = '/api/v1/server/following'
50 69
51 const query = { 70 const query = {
@@ -53,7 +72,8 @@ function getFollowingListPaginationAndSort (url: string, start: number, count: n
53 count, 72 count,
54 sort, 73 sort,
55 search, 74 search,
56 state 75 state,
76 actorType
57 } 77 }
58 78
59 return request(url) 79 return request(url)