private loadMoreFollowers () {
const pagination = this.restService.componentPaginationToRestPagination(this.followersPagination)
- this.followService.getFollowers(pagination, this.sort)
+ this.followService.getFollowers({ pagination: pagination, sort: this.sort, state: 'accepted' })
.subscribe(
resultList => {
const newFollowers = resultList.data.map(r => r.follower.host)
private loadMoreFollowings () {
const pagination = this.restService.componentPaginationToRestPagination(this.followingsPagination)
- this.followService.getFollowing(pagination, this.sort)
+ this.followService.getFollowing({ pagination, sort: this.sort, state: 'accepted' })
.subscribe(
resultList => {
const newFollowings = resultList.data.map(r => r.following.host)
}
protected loadData () {
- this.followService.getFollowers(this.pagination, this.sort, this.search)
+ this.followService.getFollowers({ pagination: this.pagination, sort: this.sort, search: this.search })
.subscribe(
resultList => {
this.followers = resultList.data
}
protected loadData () {
- this.followService.getFollowing(this.pagination, this.sort, this.search)
+ this.followService.getFollowing({ pagination: this.pagination, sort: this.sort, search: this.search })
.subscribe(
resultList => {
this.following = resultList.data
import { HttpClient, HttpParams } from '@angular/common/http'
import { Injectable } from '@angular/core'
import { Observable } from 'rxjs'
-import { ActorFollow, ResultList } from '@shared/index'
+import { ActorFollow, FollowState, ResultList } from '@shared/index'
import { environment } from '../../../environments/environment'
import { RestExtractor, RestPagination, RestService } from '../rest'
import { SortMeta } from 'primeng/api'
) {
}
- getFollowing (pagination: RestPagination, sort: SortMeta, search?: string): Observable<ResultList<ActorFollow>> {
+ getFollowing (options: {
+ pagination: RestPagination,
+ sort: SortMeta,
+ search?: string,
+ state?: FollowState
+ }): Observable<ResultList<ActorFollow>> {
+ const { pagination, sort, search, state } = options
+
let params = new HttpParams()
params = this.restService.addRestGetParams(params, pagination, sort)
if (search) params = params.append('search', search)
+ if (state) params = params.append('state', state)
return this.authHttp.get<ResultList<ActorFollow>>(FollowService.BASE_APPLICATION_URL + '/following', { params })
.pipe(
)
}
- getFollowers (pagination: RestPagination, sort: SortMeta, search?: string): Observable<ResultList<ActorFollow>> {
+ getFollowers (options: {
+ pagination: RestPagination,
+ sort: SortMeta,
+ search?: string,
+ state?: FollowState
+ }): Observable<ResultList<ActorFollow>> {
+ const { pagination, sort, search, state } = options
+
let params = new HttpParams()
params = this.restService.addRestGetParams(params, pagination, sort)
if (search) params = params.append('search', search)
+ if (state) params = params.append('state', state)
return this.authHttp.get<ResultList<ActorFollow>>(FollowService.BASE_APPLICATION_URL + '/followers', { params })
.pipe(
followingSortValidator,
followValidator,
getFollowerValidator,
- removeFollowingValidator
+ removeFollowingValidator,
+ listFollowsValidator
} from '../../../middlewares/validators'
import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
import { JobQueue } from '../../../lib/job-queue'
const serverFollowsRouter = express.Router()
serverFollowsRouter.get('/following',
+ listFollowsValidator,
paginationValidator,
followingSortValidator,
setDefaultSort,
)
serverFollowsRouter.get('/followers',
+ listFollowsValidator,
paginationValidator,
followersSortValidator,
setDefaultSort,
async function listFollowing (req: express.Request, res: express.Response) {
const serverActor = await getServerActor()
- const resultList = await ActorFollowModel.listFollowingForApi(
- serverActor.id,
- req.query.start,
- req.query.count,
- req.query.sort,
- req.query.search
- )
+ const resultList = await ActorFollowModel.listFollowingForApi({
+ id: serverActor.id,
+ start: req.query.start,
+ count: req.query.count,
+ sort: req.query.sort,
+ search: req.query.search,
+ state: req.query.state
+ })
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
async function listFollowers (req: express.Request, res: express.Response) {
const serverActor = await getServerActor()
- const resultList = await ActorFollowModel.listFollowersForApi(
- serverActor.id,
- req.query.start,
- req.query.count,
- req.query.sort,
- req.query.search
- )
+ const resultList = await ActorFollowModel.listFollowersForApi({
+ actorId: serverActor.id,
+ start: req.query.start,
+ count: req.query.count,
+ sort: req.query.sort,
+ search: req.query.search,
+ state: req.query.state
+ })
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
--- /dev/null
+import { exists } from './misc'
+import { FollowState } from '@shared/models'
+
+function isFollowStateValid (value: FollowState) {
+ if (!exists(value)) return false
+
+ return value === 'pending' || value === 'accepted'
+}
+
+// ---------------------------------------------------------------------------
+
+export {
+ isFollowStateValid
+}
import * as express from 'express'
-import { body, param } from 'express-validator'
+import { body, param, query } from 'express-validator'
import { isTestInstance } from '../../helpers/core-utils'
import { isEachUniqueHostValid, isHostValid } from '../../helpers/custom-validators/servers'
import { logger } from '../../helpers/logger'
import { loadActorUrlOrGetFromWebfinger } from '../../helpers/webfinger'
import { isValidActorHandle } from '../../helpers/custom-validators/activitypub/actor'
import { MActorFollowActorsDefault } from '@server/typings/models'
+import { isFollowStateValid } from '@server/helpers/custom-validators/follows'
+
+const listFollowsValidator = [
+ query('state')
+ .optional()
+ .custom(isFollowStateValid).withMessage('Should have a valid follow state'),
+
+ (req: express.Request, res: express.Response, next: express.NextFunction) => {
+ if (areValidationErrors(req, res)) return
+
+ return next()
+ }
+]
const followValidator = [
body('hosts').custom(isEachUniqueHostValid).withMessage('Should have an array of unique hosts'),
followValidator,
removeFollowingValidator,
getFollowerValidator,
- acceptOrRejectFollowerValidator
+ acceptOrRejectFollowerValidator,
+ listFollowsValidator
}
return ActorFollowModel.findAll(query)
}
- static listFollowingForApi (id: number, start: number, count: number, sort: string, search?: string) {
+ static listFollowingForApi (options: {
+ id: number,
+ start: number,
+ count: number,
+ sort: string,
+ state?: FollowState,
+ search?: string
+ }) {
+ const { id, start, count, sort, search, state } = options
+
+ const followWhere = state ? { state } : {}
+
const query = {
distinct: true,
offset: start,
limit: count,
order: getSort(sort),
+ where: followWhere,
include: [
{
model: ActorModel,
})
}
- static listFollowersForApi (actorId: number, start: number, count: number, sort: string, search?: string) {
+ static listFollowersForApi (options: {
+ actorId: number,
+ start: number,
+ count: number,
+ sort: string,
+ state?: FollowState,
+ search?: string
+ }) {
+ const { actorId, start, count, sort, search, state } = options
+
+ const followWhere = state ? { state } : {}
+
const query = {
distinct: true,
offset: start,
limit: count,
order: getSort(sort),
+ where: followWhere,
include: [
{
model: ActorModel,
cleanupTests,
createUser,
flushAndRunServer,
- makeDeleteRequest,
+ makeDeleteRequest, makeGetRequest,
makePostBodyRequest,
ServerInfo,
setAccessTokensToServers,
it('Should fail with an incorrect sort', async function () {
await checkBadSortPagination(server.url, path)
})
+
+ it('Should fail with an incorrect state', async function () {
+ await makeGetRequest({
+ url: server.url,
+ path,
+ query: {
+ state: 'blabla'
+ }
+ })
+ })
+
+ it('Should fail succeed with the correct params', async function () {
+ await makeGetRequest({
+ url: server.url,
+ path,
+ statusCodeExpected: 200,
+ query: {
+ state: 'accepted'
+ }
+ })
+ })
})
describe('When listing followers', function () {
it('Should fail with an incorrect sort', async function () {
await checkBadSortPagination(server.url, path)
})
+
+ it('Should fail with an incorrect state', async function () {
+ await makeGetRequest({
+ url: server.url,
+ path,
+ query: {
+ state: 'blabla'
+ }
+ })
+ })
+
+ it('Should fail succeed with the correct params', async function () {
+ await makeGetRequest({
+ url: server.url,
+ path,
+ statusCodeExpected: 200,
+ query: {
+ state: 'accepted'
+ }
+ })
+ })
})
describe('When removing a follower', function () {
expect(server3Follow.state).to.equal('accepted')
})
- it('Should search followings on server 1', async function () {
+ it('Should search/filter followings on server 1', async function () {
{
- const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', ':' + servers[1].port)
+ const search = ':' + servers[1].port
+ const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', search)
const follows = res.body.data
expect(res.body.total).to.equal(1)
expect(follows.length).to.equal(1)
expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[1].port)
+
+ const res2 = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', search, 'accepted')
+ expect(res2.body.total).to.equal(1)
+ expect(res2.body.data).to.have.lengthOf(1)
+
+ const res3 = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', search, 'pending')
+ expect(res3.body.total).to.equal(0)
+ expect(res3.body.data).to.have.lengthOf(0)
}
{
}
})
- it('Should search followers on server 2', async function () {
+ it('Should search/filter followers on server 2', async function () {
{
- const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', servers[0].port + '')
+ const search = servers[0].port + ''
+ const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', search)
const follows = res.body.data
expect(res.body.total).to.equal(1)
expect(follows.length).to.equal(1)
expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[2].port)
+
+ const res2 = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', search, 'accepted')
+ expect(res2.body.total).to.equal(1)
+ expect(res2.body.data).to.have.lengthOf(1)
+
+ const res3 = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', search, 'pending')
+ expect(res3.body.total).to.equal(0)
+ expect(res3.body.data).to.have.lengthOf(0)
}
{
import { ServerInfo } from './servers'
import { waitJobs } from './jobs'
import { makePostBodyRequest } from '../requests/requests'
+import { FollowState } from '@shared/models'
-function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
+function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string, state?: FollowState) {
const path = '/api/v1/server/followers'
const query = {
start,
count,
sort,
- search
+ search,
+ state
}
return request(url)
})
}
-function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
+function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string, state?: FollowState) {
const path = '/api/v1/server/following'
const query = {
start,
count,
sort,
- search
+ search,
+ state
}
return request(url)