From b014b6b9c7cb68d09c52b44046afe486c0736426 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 10 Oct 2018 09:43:53 +0200 Subject: [PATCH] Add ability to search on followers/following --- .../followers-list.component.html | 9 ++ .../followers-list.component.scss | 10 +++ .../following-list.component.html | 11 +++ .../following-list.component.scss | 8 ++ .../following-list.component.ts | 2 +- .../+admin/follows/shared/follow.service.ts | 8 +- .../users/user-list/user-list.component.scss | 3 - .../video-change-ownership.component.html | 6 +- client/src/sass/primeng-custom.scss | 6 ++ server/controllers/api/server/follows.ts | 16 +++- server/models/activitypub/actor-follow.ts | 90 +++++++++++-------- server/tests/api/server/follows.ts | 40 ++++++++- server/tests/utils/server/follows.ts | 6 +- 13 files changed, 166 insertions(+), 49 deletions(-) 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/) -- 2.41.0