Add pod list endpoint with pagination, sort...
authorChocobozzz <florian.bigard@gmail.com>
Thu, 19 Oct 2017 07:43:01 +0000 (09:43 +0200)
committerChocobozzz <florian.bigard@gmail.com>
Thu, 19 Oct 2017 07:43:01 +0000 (09:43 +0200)
19 files changed:
README.md
client/src/app/+admin/friends/friend-list/friend-list.component.html
client/src/app/+admin/friends/friend-list/friend-list.component.ts
client/src/app/+admin/friends/shared/friend.service.ts
server/controllers/api/pods.ts
server/controllers/api/remote/pods.ts
server/initializers/constants.ts
server/lib/friends.ts
server/middlewares/sort.ts
server/middlewares/validators/pods.ts
server/middlewares/validators/remote/index.ts
server/middlewares/validators/remote/pods.ts [new file with mode: 0644]
server/middlewares/validators/sort.ts
server/middlewares/validators/utils.ts
server/models/pod/pod-interface.ts
server/models/pod/pod.ts
server/tests/api/check-params/pods.ts
server/tests/api/friends-basic.ts
server/tests/utils/pods.ts

index c908d7bcb69213fab679db43aee5bce0969997d8..8248e3a7c8179083b86dc0e801287b1097591f36 100644 (file)
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@ Decentralized video streaming platform using P2P (BitTorrent) directly in the we
 Want to see in action?
 
    * [Demo server](http://peertube.cpy.re)
-   * [Video](https://vimeo.com/164881662 "Yes Vimeo, please don't judge me") to see how the "decentralization feature" looks like
+   * [Video](https://peertube.cpy.re/videos/watch/f78a97f8-a142-4ce1-a5bd-154bf9386504) to see how the "decentralization feature" looks like
    * Experimental demo servers that share videos (they are in the same network): [peertube2](http://peertube2.cpy.re), [peertube3](http://peertube3.cpy.re). Since I do experiments with them, sometimes they might not work correctly.
 
 ## Why
index 7887bc5e3ae5131f00305ad630bf379b4b03dc65..7e92ced540ee3c047a5d006bdc2d4a387943013a 100644 (file)
@@ -2,12 +2,15 @@
   <div class="content-padding">
     <h3>Friends list</h3>
 
-    <p-dataTable [value]="friends">
-      <p-column field="id" header="ID"></p-column>
-      <p-column field="host" header="Host"></p-column>
+    <p-dataTable
+        [value]="friends" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage"
+        sortField="id" (onLazyLoad)="loadLazy($event)"
+    >
+      <p-column field="id" header="ID" [sortable]="true"></p-column>
+      <p-column field="host" header="Host" [sortable]="true"></p-column>
       <p-column field="email" header="Email"></p-column>
-      <p-column field="score" header="Score"></p-column>
-      <p-column field="createdAt" header="Created date"></p-column>
+      <p-column field="score" header="Score" [sortable]="true"></p-column>
+      <p-column field="createdAt" header="Created date" [sortable]="true"></p-column>
       <p-column header="Delete" styleClass="action-cell">
         <ng-template pTemplate="body" let-pod="rowData">
           <span (click)="removeFriend(pod)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this pod"></span>
index 4af39c47e84366bbd6d4eefe04cd8d89f26cfab4..5a1ecd28037fde289f5ed5a28aa9d03bdb6e1493 100644 (file)
@@ -1,24 +1,32 @@
 import { Component, OnInit } from '@angular/core'
 
 import { NotificationsService } from 'angular2-notifications'
+import { SortMeta } from 'primeng/primeng'
 
 import { ConfirmService } from '../../../core'
-import { FriendService } from '../shared'
+import { RestTable, RestPagination } from '../../../shared'
 import { Pod } from '../../../../../../shared'
+import { FriendService } from '../shared'
 
 @Component({
   selector: 'my-friend-list',
   templateUrl: './friend-list.component.html',
   styleUrls: ['./friend-list.component.scss']
 })
-export class FriendListComponent implements OnInit {
+export class FriendListComponent extends RestTable implements OnInit {
   friends: Pod[] = []
+  totalRecords = 0
+  rowsPerPage = 10
+  sort: SortMeta = { field: 'id', order: 1 }
+  pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
 
   constructor (
     private notificationsService: NotificationsService,
     private confirmService: ConfirmService,
     private friendService: FriendService
-  ) {}
+  ) {
+    super()
+  }
 
   ngOnInit () {
     this.loadData()
@@ -65,11 +73,12 @@ export class FriendListComponent implements OnInit {
     )
   }
 
-  private loadData () {
-    this.friendService.getFriends()
+  protected loadData () {
+    this.friendService.getFriends(this.pagination, this.sort)
                       .subscribe(
                         resultList => {
                           this.friends = resultList.data
+                          this.totalRecords = resultList.total
                         },
 
                         err => this.notificationsService.error('Error', err.message)
index 274373e3b7a4942b84b204ea46b4ac8e07f84c3f..a32cdcc88410a4d764efc2d173e62529f1043009 100644 (file)
@@ -1,9 +1,12 @@
 import { Injectable } from '@angular/core'
-import { HttpClient } from '@angular/common/http'
+import { HttpClient, HttpParams } from '@angular/common/http'
+import { Observable } from 'rxjs/Observable'
 import 'rxjs/add/operator/catch'
 import 'rxjs/add/operator/map'
 
-import { RestExtractor } from '../../../shared'
+import { SortMeta } from 'primeng/primeng'
+
+import { RestExtractor, RestPagination, RestService } from '../../../shared'
 import { Pod, ResultList } from '../../../../../../shared'
 
 @Injectable()
@@ -12,11 +15,15 @@ export class FriendService {
 
   constructor (
     private authHttp: HttpClient,
+    private restService: RestService,
     private restExtractor: RestExtractor
   ) {}
 
-  getFriends () {
-    return this.authHttp.get<ResultList<Pod>>(FriendService.BASE_FRIEND_URL)
+  getFriends (pagination: RestPagination, sort: SortMeta): Observable<ResultList<Pod>> {
+    let params = new HttpParams()
+    params = this.restService.addRestGetParams(params, pagination, sort)
+
+    return this.authHttp.get<ResultList<Pod>>(FriendService.BASE_FRIEND_URL, { params })
                         .map(res => this.restExtractor.convertResultListDateToHuman(res))
                         .catch(res => this.restExtractor.handleError(res))
   }
index e1e8ff6cad51abf5f2f7940ae876ba68b2ae5fd2..ec94efc3524405df682c3c334f67bac77f4f02ff 100644 (file)
@@ -1,39 +1,33 @@
 import * as express from 'express'
 
 import { database as db } from '../../initializers/database'
-import { CONFIG } from '../../initializers'
+import { logger, getFormattedObjects } from '../../helpers'
 import {
-  logger,
-  getMyPublicCert,
-  getFormattedObjects
-} from '../../helpers'
-import {
-  sendOwnedVideosToPod,
   makeFriends,
   quitFriends,
   removeFriend
 } from '../../lib'
 import {
-  podsAddValidator,
   authenticate,
   ensureIsAdmin,
   makeFriendsValidator,
-  setBodyHostPort,
   setBodyHostsPort,
-  podRemoveValidator
+  podRemoveValidator,
+  paginationValidator,
+  setPagination,
+  setPodsSort,
+  podsSortValidator
 } from '../../middlewares'
-import {
-  PodInstance
-} from '../../models'
-import { Pod as FormattedPod } from '../../../shared'
+import { PodInstance } from '../../models'
 
 const podsRouter = express.Router()
 
-podsRouter.get('/', listPods)
-podsRouter.post('/',
-  setBodyHostPort, // We need to modify the host before running the validator!
-  podsAddValidator,
-  addPods
+podsRouter.get('/',
+  paginationValidator,
+  podsSortValidator,
+  setPodsSort,
+  setPagination,
+  listPods
 )
 podsRouter.post('/make-friends',
   authenticate,
@@ -62,26 +56,9 @@ export {
 
 // ---------------------------------------------------------------------------
 
-function addPods (req: express.Request, res: express.Response, next: express.NextFunction) {
-  const informations = req.body
-
-  const pod = db.Pod.build(informations)
-  pod.save()
-    .then(podCreated => {
-      return sendOwnedVideosToPod(podCreated.id)
-    })
-    .then(() => {
-      return getMyPublicCert()
-    })
-    .then(cert => {
-      return res.json({ cert: cert, email: CONFIG.ADMIN.EMAIL })
-    })
-    .catch(err => next(err))
-}
-
 function listPods (req: express.Request, res: express.Response, next: express.NextFunction) {
-  db.Pod.list()
-    .then(podsList => res.json(getFormattedObjects<FormattedPod, PodInstance>(podsList, podsList.length)))
+  db.Pod.listForApi(req.query.start, req.query.count, req.query.sort)
+    .then(resultList => res.json(getFormattedObjects(resultList.data, resultList.total)))
     .catch(err => next(err))
 }
 
index 69bbd43780b4e8babcb395451f84f9ce12959aa3..6f7b5f6511a2aa0d5b297102d294570254ace4a8 100644 (file)
@@ -1,18 +1,34 @@
 import * as express from 'express'
 
 import { database as db } from '../../../initializers/database'
-import { checkSignature, signatureValidator } from '../../../middlewares'
-import { PodSignature } from '../../../../shared'
+import {
+  checkSignature,
+  signatureValidator,
+  setBodyHostPort,
+  remotePodsAddValidator
+} from '../../../middlewares'
+import { sendOwnedVideosToPod } from '../../../lib'
+import { getMyPublicCert, getFormattedObjects } from '../../../helpers'
+import { CONFIG } from '../../../initializers'
+import { PodInstance } from '../../../models'
+import { PodSignature, Pod as FormattedPod } from '../../../../shared'
 
 const remotePodsRouter = express.Router()
 
-// Post because this is a secured request
 remotePodsRouter.post('/remove',
   signatureValidator,
   checkSignature,
   removePods
 )
 
+remotePodsRouter.post('/list', remotePodsList)
+
+remotePodsRouter.post('/add',
+  setBodyHostPort, // We need to modify the host before running the validator!
+  remotePodsAddValidator,
+  addPods
+)
+
 // ---------------------------------------------------------------------------
 
 export {
@@ -21,6 +37,29 @@ export {
 
 // ---------------------------------------------------------------------------
 
+function addPods (req: express.Request, res: express.Response, next: express.NextFunction) {
+  const information = req.body
+
+  const pod = db.Pod.build(information)
+  pod.save()
+     .then(podCreated => {
+       return sendOwnedVideosToPod(podCreated.id)
+     })
+     .then(() => {
+       return getMyPublicCert()
+     })
+     .then(cert => {
+       return res.json({ cert: cert, email: CONFIG.ADMIN.EMAIL })
+     })
+     .catch(err => next(err))
+}
+
+function remotePodsList (req: express.Request, res: express.Response, next: express.NextFunction) {
+  db.Pod.list()
+    .then(podsList => res.json(getFormattedObjects<FormattedPod, PodInstance>(podsList, podsList.length)))
+    .catch(err => next(err))
+}
+
 function removePods (req: express.Request, res: express.Response, next: express.NextFunction) {
   const signature: PodSignature = req.body.signature
   const host = signature.host
index 491fb78f96c26367955b9d819c4ba2c030db9bdf..132164746efa8b6f7403696f139cd893e7e4f74b 100644 (file)
@@ -32,6 +32,7 @@ const SEARCHABLE_COLUMNS = {
 
 // Sortable columns per schema
 const SORTABLE_COLUMNS = {
+  PODS: [ 'id', 'host', 'score', 'createdAt' ],
   USERS: [ 'id', 'username', 'createdAt' ],
   VIDEO_ABUSES: [ 'id', 'createdAt' ],
   VIDEOS: [ 'name', 'duration', 'createdAt', 'views', 'likes' ],
index c0dd24c534a12743012c902708f99b9c0267f7de..4cc4a82bfe771b4661e7156034cb3478d4d4b61a 100644 (file)
@@ -334,9 +334,9 @@ function computeWinningPods (hosts: string[], podsScore: { [ host: string ]: num
 
 function getForeignPodsList (host: string) {
   return new Promise< ResultList<FormattedPod> >((res, rej) => {
-    const path = '/api/' + API_VERSION + '/pods'
+    const path = '/api/' + API_VERSION + '/remote/pods/list'
 
-    request.get(REMOTE_SCHEME.HTTP + '://' + host + path, (err, response, body) => {
+    request.post(REMOTE_SCHEME.HTTP + '://' + host + path, (err, response, body) => {
       if (err) return rej(err)
 
       try {
@@ -357,7 +357,7 @@ function makeRequestsToWinningPods (cert: string, podsList: PodInstance[]) {
 
   return Promise.map(podsList, pod => {
     const params = {
-      url: REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + API_VERSION + '/pods/',
+      url: REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + API_VERSION + '/remote/pods/add',
       method: 'POST' as 'POST',
       json: {
         host: CONFIG.WEBSERVER.HOST,
index 687ce097b7c8b2f32702df186fd63e8ceb7c1a94..2c70ff5f0b2e5ecbb0eb940710ba13babc1c1a3e 100644 (file)
@@ -4,6 +4,12 @@ import * as express from 'express'
 import { SortType } from '../helpers'
 import { database } from '../initializers'
 
+function setPodsSort (req: express.Request, res: express.Response, next: express.NextFunction) {
+  if (!req.query.sort) req.query.sort = '-createdAt'
+
+  return next()
+}
+
 function setUsersSort (req: express.Request, res: express.Response, next: express.NextFunction) {
   if (!req.query.sort) req.query.sort = '-createdAt'
 
@@ -46,6 +52,7 @@ function setBlacklistSort (req: express.Request, res: express.Response, next: ex
 // ---------------------------------------------------------------------------
 
 export {
+  setPodsSort,
   setUsersSort,
   setVideoAbusesSort,
   setVideosSort,
index ab7702e781721438e1c328f600fdbf631db6b57e..575c36526a52eff1f5765090c97a4a2d0dfd5e5b 100644 (file)
@@ -3,7 +3,7 @@ import * as express from 'express'
 
 import { database as db } from '../../initializers/database'
 import { checkErrors } from './utils'
-import { logger, isEachUniqueHostValid, isHostValid } from '../../helpers'
+import { logger, isEachUniqueHostValid } from '../../helpers'
 import { CONFIG } from '../../initializers'
 import { hasFriends } from '../../lib'
 import { isTestInstance } from '../../helpers'
@@ -41,32 +41,6 @@ const makeFriendsValidator = [
   }
 ]
 
-const podsAddValidator = [
-  body('host').custom(isHostValid).withMessage('Should have a host'),
-  body('email').isEmail().withMessage('Should have an email'),
-  body('publicKey').not().isEmpty().withMessage('Should have a public key'),
-
-  (req: express.Request, res: express.Response, next: express.NextFunction) => {
-    logger.debug('Checking podsAdd parameters', { parameters: req.body })
-
-    checkErrors(req, res, () => {
-      db.Pod.loadByHost(req.body.host)
-        .then(pod => {
-          // Pod with this host already exists
-          if (pod) {
-            return res.sendStatus(409)
-          }
-
-          return next()
-        })
-        .catch(err => {
-          logger.error('Cannot load pod by host.', err)
-          res.sendStatus(500)
-        })
-    })
-  }
-]
-
 const podRemoveValidator = [
   param('id').isNumeric().not().isEmpty().withMessage('Should have a valid id'),
 
@@ -96,6 +70,5 @@ const podRemoveValidator = [
 
 export {
   makeFriendsValidator,
-  podsAddValidator,
   podRemoveValidator
 }
index d0d7740b10dc2ca016d37c9a768b237b42e378bd..f1f26043e8df406dcd4e5dc2f88fedd5544926d1 100644 (file)
@@ -1,2 +1,3 @@
+export * from './pods'
 export * from './signature'
 export * from './videos'
diff --git a/server/middlewares/validators/remote/pods.ts b/server/middlewares/validators/remote/pods.ts
new file mode 100644 (file)
index 0000000..f917b61
--- /dev/null
@@ -0,0 +1,38 @@
+import { body } from 'express-validator/check'
+import * as express from 'express'
+
+import { database as db } from '../../../initializers'
+import { isHostValid, logger } from '../../../helpers'
+import { checkErrors } from '../utils'
+
+const remotePodsAddValidator = [
+  body('host').custom(isHostValid).withMessage('Should have a host'),
+  body('email').isEmail().withMessage('Should have an email'),
+  body('publicKey').not().isEmpty().withMessage('Should have a public key'),
+
+  (req: express.Request, res: express.Response, next: express.NextFunction) => {
+    logger.debug('Checking podsAdd parameters', { parameters: req.body })
+
+    checkErrors(req, res, () => {
+      db.Pod.loadByHost(req.body.host)
+        .then(pod => {
+          // Pod with this host already exists
+          if (pod) {
+            return res.sendStatus(409)
+          }
+
+          return next()
+        })
+        .catch(err => {
+          logger.error('Cannot load pod by host.', err)
+          res.sendStatus(500)
+        })
+    })
+  }
+]
+
+// ---------------------------------------------------------------------------
+
+export {
+  remotePodsAddValidator
+}
index a6f5ccb6b41c8bd5ca2e53d606045d79315fb696..227f309ad567576005fbd7b2527d6a20886c5da0 100644 (file)
@@ -6,11 +6,13 @@ import { logger } from '../../helpers'
 import { SORTABLE_COLUMNS } from '../../initializers'
 
 // Initialize constants here for better performances
+const SORTABLE_PODS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PODS)
 const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS)
 const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES)
 const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS)
 const SORTABLE_BLACKLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.BLACKLISTS)
 
+const podsSortValidator = checkSort(SORTABLE_PODS_COLUMNS)
 const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS)
 const videoAbusesSortValidator = checkSort(SORTABLE_VIDEO_ABUSES_COLUMNS)
 const videosSortValidator = checkSort(SORTABLE_VIDEOS_COLUMNS)
@@ -19,6 +21,7 @@ const blacklistSortValidator = checkSort(SORTABLE_BLACKLISTS_COLUMNS)
 // ---------------------------------------------------------------------------
 
 export {
+  podsSortValidator,
   usersSortValidator,
   videoAbusesSortValidator,
   videosSortValidator,
index 8845f83995be3536abd9c5f3f1b05be5b6f0e3bf..ea107bbe8f67b5036b7f24a964d470de76b7d968 100644 (file)
@@ -3,12 +3,12 @@ import * as express from 'express'
 
 import { logger } from '../../helpers'
 
-function checkErrors (req: express.Request, res: express.Response, next: express.NextFunction, statusCode = 400) {
+function checkErrors (req: express.Request, res: express.Response, next: express.NextFunction) {
   const errors = validationResult(req)
 
   if (!errors.isEmpty()) {
     logger.warn('Incorrect request parameters', { path: req.originalUrl, err: errors.mapped() })
-    return res.status(statusCode).json({ errors: errors.mapped() })
+    return res.status(400).json({ errors: errors.mapped() })
   }
 
   return next()
index fc763acacb7a139da30d575a540b87065271f9e2..7e095d424f61443c6e50548c68d2cf1e31a8b8e3 100644 (file)
@@ -3,6 +3,7 @@ import * as Promise from 'bluebird'
 
 // Don't use barrel, import just what we need
 import { Pod as FormattedPod } from '../../../shared/models/pods/pod.model'
+import { ResultList } from '../../../shared/models/result-list.model'
 
 export namespace PodMethods {
   export type ToFormattedJSON = (this: PodInstance) => FormattedPod
@@ -13,6 +14,8 @@ export namespace PodMethods {
 
   export type List = () => Promise<PodInstance[]>
 
+  export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList<PodInstance> >
+
   export type ListAllIds = (transaction: Sequelize.Transaction) => Promise<number[]>
 
   export type ListRandomPodIdsWithRequest = (limit: number, tableWithPods: string, tableWithPodsJoins: string) => Promise<number[]>
@@ -32,6 +35,7 @@ export interface PodClass {
   countAll: PodMethods.CountAll
   incrementScores: PodMethods.IncrementScores
   list: PodMethods.List
+  listForApi: PodMethods.ListForApi
   listAllIds: PodMethods.ListAllIds
   listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest
   listBadPods: PodMethods.ListBadPods
index 1440ac9b4bf70cdda961db2265a7a85e69f5e927..e4d7db48a722f3b7cead1fa26ccd2e66c159dc71 100644 (file)
@@ -4,7 +4,7 @@ import * as Sequelize from 'sequelize'
 import { FRIEND_SCORE, PODS_SCORE } from '../../initializers'
 import { logger, isHostValid } from '../../helpers'
 
-import { addMethodsToModel } from '../utils'
+import { addMethodsToModel, getSort } from '../utils'
 import {
   PodInstance,
   PodAttributes,
@@ -17,6 +17,7 @@ let toFormattedJSON: PodMethods.ToFormattedJSON
 let countAll: PodMethods.CountAll
 let incrementScores: PodMethods.IncrementScores
 let list: PodMethods.List
+let listForApi: PodMethods.ListForApi
 let listAllIds: PodMethods.ListAllIds
 let listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest
 let listBadPods: PodMethods.ListBadPods
@@ -78,6 +79,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da
     countAll,
     incrementScores,
     list,
+    listForApi,
     listAllIds,
     listRandomPodIdsWithRequest,
     listBadPods,
@@ -142,6 +144,21 @@ list = function () {
   return Pod.findAll()
 }
 
+listForApi = function (start: number, count: number, sort: string) {
+  const query = {
+    offset: start,
+    limit: count,
+    order: [ getSort(sort) ]
+  }
+
+  return Pod.findAndCountAll(query).then(({ rows, count }) => {
+    return {
+      data: rows,
+      total: count
+    }
+  })
+}
+
 listAllIds = function (transaction: Sequelize.Transaction) {
   const query = {
     attributes: [ 'id' ],
index a897e4dcd959801e509b36442a2f7604460417ba..9f9c2e4f0eca1da10f1d06a09e10e41c1c41f6f5 100644 (file)
@@ -15,7 +15,6 @@ import {
 } from '../../utils'
 
 describe('Test pods API validators', function () {
-  const path = '/api/v1/pods/'
   let server: ServerInfo
 
   // ---------------------------------------------------------------
@@ -30,6 +29,7 @@ describe('Test pods API validators', function () {
   })
 
   describe('When managing friends', function () {
+    const path = '/api/v1/pods/'
     let userAccessToken = null
 
     before(async function () {
@@ -110,6 +110,32 @@ describe('Test pods API validators', function () {
       })
     })
 
+    describe('When listing friends', function () {
+      it('Should fail with a bad start pagination', async function () {
+        await request(server.url)
+          .get(path)
+          .query({ start: 'hello' })
+          .set('Accept', 'application/json')
+          .expect(400)
+      })
+
+      it('Should fail with a bad count pagination', async function () {
+        await request(server.url)
+          .get(path)
+          .query({ count: 'hello' })
+          .set('Accept', 'application/json')
+          .expect(400)
+      })
+
+      it('Should fail with an incorrect sort', async function () {
+        await request(server.url)
+          .get(path)
+          .query({ sort: 'hello' })
+          .set('Accept', 'application/json')
+          .expect(400)
+      })
+    })
+
     describe('When quitting friends', function () {
       it('Should fail with an invalid token', async function () {
         await request(server.url)
@@ -175,7 +201,9 @@ describe('Test pods API validators', function () {
     })
   })
 
-  describe('When adding a pod', function () {
+  describe('When adding a pod from remote', function () {
+    const path = '/api/v1/remote/pods/add'
+
     it('Should fail with nothing', async function () {
       const fields = {}
       await makePostBodyRequest({ url: server.url, path, fields })
index 13edf627312da7d75ff396eff470402a6e956be0..efca4fda23532ae970fbcfc053366a19b9a468d2 100644 (file)
@@ -15,7 +15,8 @@ import {
   makeFriends,
   getFriendsList,
   dateIsValid,
-  quitOneFriend
+  quitOneFriend,
+  getPodsListPaginationAndSort
 } from '../utils'
 
 describe('Test basic friends', function () {
@@ -120,6 +121,22 @@ describe('Test basic friends', function () {
     await makeFriends(server.url, server.accessToken, 409)
   })
 
+  it('Should list friends correctly', async function () {
+    const start = 1
+    const count = 1
+    const sort = '-host'
+
+    const res = await getPodsListPaginationAndSort(servers[0].url, start, count, sort)
+    expect(res.body.total).to.equal(2)
+    expect(res.body.data).to.have.lengthOf(1)
+
+    const pod = res.body.data[0]
+    expect(pod.host).to.equal('localhost:9002')
+    expect(pod.email).to.equal('admin2@example.com')
+    expect(pod.score).to.equal(20)
+    expect(dateIsValid(pod.createdAt)).to.be.true
+  })
+
   it('Should quit friends of pod 2', async function () {
     this.timeout(10000)
 
index a86dd20d912cd12e3aea1cfafbcd5849264c85e3..52e807e70e9f1a621a71febb57245eb1e298b182 100644 (file)
@@ -12,6 +12,19 @@ function getFriendsList (url: string) {
           .expect('Content-Type', /json/)
 }
 
+function getPodsListPaginationAndSort (url: string, start: number, count: number, sort: string) {
+  const path = '/api/v1/pods/'
+
+  return request(url)
+    .get(path)
+    .query({ start })
+    .query({ count })
+    .query({ sort })
+    .set('Accept', 'application/json')
+    .expect(200)
+    .expect('Content-Type', /json/)
+}
+
 async function makeFriends (url: string, accessToken: string, expectedStatus = 204) {
   // Which pod makes friends with which pod
   const friendsMatrix = {
@@ -85,5 +98,6 @@ export {
   getFriendsList,
   makeFriends,
   quitFriends,
-  quitOneFriend
+  quitOneFriend,
+  getPodsListPaginationAndSort
 }