diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.html b/client/src/app/+admin/follows/followers-list/followers-list.component.html
index 5645a60cc..fc022bdb4 100644
--- a/client/src/app/+admin/follows/followers-list/followers-list.component.html
+++ b/client/src/app/+admin/follows/followers-list/followers-list.component.html
@@ -2,6 +2,15 @@
[value]="followers" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
>
+
+
+
+
+
+
ID |
diff --git a/client/src/app/+admin/follows/followers-list/followers-list.component.scss b/client/src/app/+admin/follows/followers-list/followers-list.component.scss
index e69de29bb..a6f0656b8 100644
--- a/client/src/app/+admin/follows/followers-list/followers-list.component.scss
+++ b/client/src/app/+admin/follows/followers-list/followers-list.component.scss
@@ -0,0 +1,10 @@
+@import '_variables';
+@import '_mixins';
+
+.caption {
+ justify-content: flex-end;
+
+ input {
+ @include peertube-input-text(250px);
+ }
+}
\ No newline at end of file
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.html b/client/src/app/+admin/follows/following-list/following-list.component.html
index 8af624ac5..5bc8fbc2d 100644
--- a/client/src/app/+admin/follows/following-list/following-list.component.html
+++ b/client/src/app/+admin/follows/following-list/following-list.component.html
@@ -2,6 +2,17 @@
[value]="following" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
[sortField]="sort.field" [sortOrder]="sort.order" (onLazyLoad)="loadLazy($event)"
>
+
+
+
+
ID |
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.scss b/client/src/app/+admin/follows/following-list/following-list.component.scss
index bfcdcaa49..b3bb7f5f8 100644
--- a/client/src/app/+admin/follows/following-list/following-list.component.scss
+++ b/client/src/app/+admin/follows/following-list/following-list.component.scss
@@ -10,4 +10,12 @@ my-redundancy-checkbox /deep/ my-peertube-checkbox {
label {
margin: 0;
}
+}
+
+.caption {
+ justify-content: flex-end;
+
+ input {
+ @include peertube-input-text(250px);
+ }
}
\ No newline at end of file
diff --git a/client/src/app/+admin/follows/following-list/following-list.component.ts b/client/src/app/+admin/follows/following-list/following-list.component.ts
index 70235a48d..9b7029f75 100644
--- a/client/src/app/+admin/follows/following-list/following-list.component.ts
+++ b/client/src/app/+admin/follows/following-list/following-list.component.ts
@@ -53,7 +53,7 @@ export class FollowingListComponent extends RestTable implements OnInit {
}
protected loadData () {
- this.followService.getFollowing(this.pagination, this.sort)
+ this.followService.getFollowing(this.pagination, this.sort, this.search)
.subscribe(
resultList => {
this.following = resultList.data
diff --git a/client/src/app/+admin/follows/shared/follow.service.ts b/client/src/app/+admin/follows/shared/follow.service.ts
index 27169a9cd..a2904179e 100644
--- a/client/src/app/+admin/follows/shared/follow.service.ts
+++ b/client/src/app/+admin/follows/shared/follow.service.ts
@@ -18,10 +18,12 @@ export class FollowService {
) {
}
- getFollowing (pagination: RestPagination, sort: SortMeta): Observable> {
+ getFollowing (pagination: RestPagination, sort: SortMeta, search?: string): Observable> {
let params = new HttpParams()
params = this.restService.addRestGetParams(params, pagination, sort)
+ if (search) params = params.append('search', search)
+
return this.authHttp.get>(FollowService.BASE_APPLICATION_URL + '/following', { params })
.pipe(
map(res => this.restExtractor.convertResultListDateToHuman(res)),
@@ -29,10 +31,12 @@ export class FollowService {
)
}
- getFollowers (pagination: RestPagination, sort: SortMeta): Observable> {
+ getFollowers (pagination: RestPagination, sort: SortMeta, search?: string): Observable> {
let params = new HttpParams()
params = this.restService.addRestGetParams(params, pagination, sort)
+ if (search) params = params.append('search', search)
+
return this.authHttp.get>(FollowService.BASE_APPLICATION_URL + '/followers', { params })
.pipe(
map(res => this.restExtractor.convertResultListDateToHuman(res)),
diff --git a/client/src/app/+admin/users/user-list/user-list.component.scss b/client/src/app/+admin/users/user-list/user-list.component.scss
index 01f43dfe1..f235769f0 100644
--- a/client/src/app/+admin/users/user-list/user-list.component.scss
+++ b/client/src/app/+admin/users/user-list/user-list.component.scss
@@ -18,10 +18,7 @@ tr.banned {
}
.caption {
- height: 40px;
- display: flex;
justify-content: space-between;
- align-items: center;
input {
@include peertube-input-text(250px);
diff --git a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html
index 69b198faa..7c0df850d 100644
--- a/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html
+++ b/client/src/app/+my-account/my-account-videos/video-change-ownership/video-change-ownership.component.html
@@ -22,9 +22,9 @@
diff --git a/client/src/sass/primeng-custom.scss b/client/src/sass/primeng-custom.scss
index 4a19e0275..0568de4e2 100644
--- a/client/src/sass/primeng-custom.scss
+++ b/client/src/sass/primeng-custom.scss
@@ -16,6 +16,12 @@ p-table {
.ui-table-caption {
border: none;
+
+ .caption {
+ height: 40px;
+ display: flex;
+ align-items: center;
+ }
}
td {
diff --git a/server/controllers/api/server/follows.ts b/server/controllers/api/server/follows.ts
index d62400e42..9fa6c34ba 100644
--- a/server/controllers/api/server/follows.ts
+++ b/server/controllers/api/server/follows.ts
@@ -61,14 +61,26 @@ export {
async function listFollowing (req: express.Request, res: express.Response, next: express.NextFunction) {
const serverActor = await getServerActor()
- const resultList = await ActorFollowModel.listFollowingForApi(serverActor.id, req.query.start, req.query.count, req.query.sort)
+ const resultList = await ActorFollowModel.listFollowingForApi(
+ serverActor.id,
+ req.query.start,
+ req.query.count,
+ req.query.sort,
+ req.query.search
+ )
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
async function listFollowers (req: express.Request, res: express.Response, next: express.NextFunction) {
const serverActor = await getServerActor()
- const resultList = await ActorFollowModel.listFollowersForApi(serverActor.id, req.query.start, req.query.count, req.query.sort)
+ const resultList = await ActorFollowModel.listFollowersForApi(
+ serverActor.id,
+ req.query.start,
+ req.query.count,
+ req.query.sort,
+ req.query.search
+ )
return res.json(getFormattedObjects(resultList.data, resultList.total))
}
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index 27bb43dae..3373355ef 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -280,7 +280,7 @@ export class ActorFollowModel extends Model {
return ActorFollowModel.findAll(query)
}
- static listFollowingForApi (id: number, start: number, count: number, sort: string) {
+ static listFollowingForApi (id: number, start: number, count: number, sort: string, search?: string) {
const query = {
distinct: true,
offset: start,
@@ -299,7 +299,17 @@ export class ActorFollowModel extends Model {
model: ActorModel,
as: 'ActorFollowing',
required: true,
- include: [ ServerModel ]
+ include: [
+ {
+ model: ServerModel,
+ required: true,
+ where: search ? {
+ host: {
+ [Sequelize.Op.iLike]: '%' + search + '%'
+ }
+ } : undefined
+ }
+ ]
}
]
}
@@ -313,6 +323,49 @@ export class ActorFollowModel extends Model {
})
}
+ static listFollowersForApi (id: number, start: number, count: number, sort: string, search?: string) {
+ const query = {
+ distinct: true,
+ offset: start,
+ limit: count,
+ order: getSort(sort),
+ include: [
+ {
+ model: ActorModel,
+ required: true,
+ as: 'ActorFollower',
+ include: [
+ {
+ model: ServerModel,
+ required: true,
+ where: search ? {
+ host: {
+ [ Sequelize.Op.iLike ]: '%' + search + '%'
+ }
+ } : undefined
+ }
+ ]
+ },
+ {
+ model: ActorModel,
+ as: 'ActorFollowing',
+ required: true,
+ where: {
+ id
+ }
+ }
+ ]
+ }
+
+ return ActorFollowModel.findAndCountAll(query)
+ .then(({ rows, count }) => {
+ return {
+ data: rows,
+ total: count
+ }
+ })
+ }
+
static listSubscriptionsForApi (id: number, start: number, count: number, sort: string) {
const query = {
attributes: [],
@@ -370,39 +423,6 @@ export class ActorFollowModel extends Model {
})
}
- static listFollowersForApi (id: number, start: number, count: number, sort: string) {
- const query = {
- distinct: true,
- offset: start,
- limit: count,
- order: getSort(sort),
- include: [
- {
- model: ActorModel,
- required: true,
- as: 'ActorFollower',
- include: [ ServerModel ]
- },
- {
- model: ActorModel,
- as: 'ActorFollowing',
- required: true,
- where: {
- id
- }
- }
- ]
- }
-
- return ActorFollowModel.findAndCountAll(query)
- .then(({ rows, count }) => {
- return {
- data: rows,
- total: count
- }
- })
- }
-
static listAcceptedFollowerUrlsForApi (actorIds: number[], t: Sequelize.Transaction, start?: number, count?: number) {
return ActorFollowModel.createListAcceptedFollowForApiQuery('followers', actorIds, t, start, count)
}
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts
index 310c291bf..e80e93e7f 100644
--- a/server/tests/api/server/follows.ts
+++ b/server/tests/api/server/follows.ts
@@ -93,7 +93,26 @@ describe('Test follows', function () {
expect(server3Follow.state).to.equal('accepted')
})
- it('Should have 0 followings on server 1 and 2', async function () {
+ it('Should search followings on server 1', async function () {
+ {
+ const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', ':9002')
+ 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:9002')
+ }
+
+ {
+ const res = await getFollowingListPaginationAndSort(servers[ 0 ].url, 0, 1, 'createdAt', 'bla')
+ const follows = res.body.data
+
+ expect(res.body.total).to.equal(0)
+ expect(follows.length).to.equal(0)
+ }
+ })
+
+ it('Should have 0 followings on server 2 and 3', async function () {
for (const server of [ servers[1], servers[2] ]) {
const res = await getFollowingListPaginationAndSort(server.url, 0, 5, 'createdAt')
const follows = res.body.data
@@ -116,6 +135,25 @@ describe('Test follows', function () {
}
})
+ it('Should search followers on server 2', async function () {
+ {
+ const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', '9001')
+ 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:9003')
+ }
+
+ {
+ const res = await getFollowersListPaginationAndSort(servers[ 2 ].url, 0, 5, 'createdAt', 'bla')
+ const follows = res.body.data
+
+ expect(res.body.total).to.equal(0)
+ expect(follows.length).to.equal(0)
+ }
+ })
+
it('Should have 0 followers on server 1', async function () {
const res = await getFollowersListPaginationAndSort(servers[0].url, 0, 5, 'createdAt')
const follows = res.body.data
diff --git a/server/tests/utils/server/follows.ts b/server/tests/utils/server/follows.ts
index 8a65a958b..7741757a6 100644
--- a/server/tests/utils/server/follows.ts
+++ b/server/tests/utils/server/follows.ts
@@ -2,7 +2,7 @@ import * as request from 'supertest'
import { ServerInfo } from './servers'
import { waitJobs } from './jobs'
-function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string) {
+function getFollowersListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
const path = '/api/v1/server/followers'
return request(url)
@@ -10,12 +10,13 @@ function getFollowersListPaginationAndSort (url: string, start: number, count: n
.query({ start })
.query({ count })
.query({ sort })
+ .query({ search })
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
}
-function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string) {
+function getFollowingListPaginationAndSort (url: string, start: number, count: number, sort: string, search?: string) {
const path = '/api/v1/server/following'
return request(url)
@@ -23,6 +24,7 @@ function getFollowingListPaginationAndSort (url: string, start: number, count: n
.query({ start })
.query({ count })
.query({ sort })
+ .query({ search })
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)