diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | client/src/app/+admin/friends/friend-list/friend-list.component.html | 13 | ||||
-rw-r--r-- | client/src/app/+admin/friends/friend-list/friend-list.component.ts | 19 | ||||
-rw-r--r-- | client/src/app/+admin/friends/shared/friend.service.ts | 15 | ||||
-rw-r--r-- | server/controllers/api/pods.ts | 53 | ||||
-rw-r--r-- | server/controllers/api/remote/pods.ts | 45 | ||||
-rw-r--r-- | server/initializers/constants.ts | 1 | ||||
-rw-r--r-- | server/lib/friends.ts | 6 | ||||
-rw-r--r-- | server/middlewares/sort.ts | 7 | ||||
-rw-r--r-- | server/middlewares/validators/pods.ts | 29 | ||||
-rw-r--r-- | server/middlewares/validators/remote/index.ts | 1 | ||||
-rw-r--r-- | server/middlewares/validators/remote/pods.ts | 38 | ||||
-rw-r--r-- | server/middlewares/validators/sort.ts | 3 | ||||
-rw-r--r-- | server/middlewares/validators/utils.ts | 4 | ||||
-rw-r--r-- | server/models/pod/pod-interface.ts | 4 | ||||
-rw-r--r-- | server/models/pod/pod.ts | 19 | ||||
-rw-r--r-- | server/tests/api/check-params/pods.ts | 32 | ||||
-rw-r--r-- | server/tests/api/friends-basic.ts | 19 | ||||
-rw-r--r-- | server/tests/utils/pods.ts | 16 |
19 files changed, 232 insertions, 94 deletions
@@ -59,7 +59,7 @@ Decentralized video streaming platform using P2P (BitTorrent) directly in the we | |||
59 | Want to see in action? | 59 | Want to see in action? |
60 | 60 | ||
61 | * [Demo server](http://peertube.cpy.re) | 61 | * [Demo server](http://peertube.cpy.re) |
62 | * [Video](https://vimeo.com/164881662 "Yes Vimeo, please don't judge me") to see how the "decentralization feature" looks like | 62 | * [Video](https://peertube.cpy.re/videos/watch/f78a97f8-a142-4ce1-a5bd-154bf9386504) to see how the "decentralization feature" looks like |
63 | * 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. | 63 | * 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. |
64 | 64 | ||
65 | ## Why | 65 | ## Why |
diff --git a/client/src/app/+admin/friends/friend-list/friend-list.component.html b/client/src/app/+admin/friends/friend-list/friend-list.component.html index 7887bc5e3..7e92ced54 100644 --- a/client/src/app/+admin/friends/friend-list/friend-list.component.html +++ b/client/src/app/+admin/friends/friend-list/friend-list.component.html | |||
@@ -2,12 +2,15 @@ | |||
2 | <div class="content-padding"> | 2 | <div class="content-padding"> |
3 | <h3>Friends list</h3> | 3 | <h3>Friends list</h3> |
4 | 4 | ||
5 | <p-dataTable [value]="friends"> | 5 | <p-dataTable |
6 | <p-column field="id" header="ID"></p-column> | 6 | [value]="friends" [lazy]="true" [paginator]="true" [totalRecords]="totalRecords" [rows]="rowsPerPage" |
7 | <p-column field="host" header="Host"></p-column> | 7 | sortField="id" (onLazyLoad)="loadLazy($event)" |
8 | > | ||
9 | <p-column field="id" header="ID" [sortable]="true"></p-column> | ||
10 | <p-column field="host" header="Host" [sortable]="true"></p-column> | ||
8 | <p-column field="email" header="Email"></p-column> | 11 | <p-column field="email" header="Email"></p-column> |
9 | <p-column field="score" header="Score"></p-column> | 12 | <p-column field="score" header="Score" [sortable]="true"></p-column> |
10 | <p-column field="createdAt" header="Created date"></p-column> | 13 | <p-column field="createdAt" header="Created date" [sortable]="true"></p-column> |
11 | <p-column header="Delete" styleClass="action-cell"> | 14 | <p-column header="Delete" styleClass="action-cell"> |
12 | <ng-template pTemplate="body" let-pod="rowData"> | 15 | <ng-template pTemplate="body" let-pod="rowData"> |
13 | <span (click)="removeFriend(pod)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this pod"></span> | 16 | <span (click)="removeFriend(pod)" class="glyphicon glyphicon-remove glyphicon-black" title="Remove this pod"></span> |
diff --git a/client/src/app/+admin/friends/friend-list/friend-list.component.ts b/client/src/app/+admin/friends/friend-list/friend-list.component.ts index 4af39c47e..5a1ecd280 100644 --- a/client/src/app/+admin/friends/friend-list/friend-list.component.ts +++ b/client/src/app/+admin/friends/friend-list/friend-list.component.ts | |||
@@ -1,24 +1,32 @@ | |||
1 | import { Component, OnInit } from '@angular/core' | 1 | import { Component, OnInit } from '@angular/core' |
2 | 2 | ||
3 | import { NotificationsService } from 'angular2-notifications' | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | import { SortMeta } from 'primeng/primeng' | ||
4 | 5 | ||
5 | import { ConfirmService } from '../../../core' | 6 | import { ConfirmService } from '../../../core' |
6 | import { FriendService } from '../shared' | 7 | import { RestTable, RestPagination } from '../../../shared' |
7 | import { Pod } from '../../../../../../shared' | 8 | import { Pod } from '../../../../../../shared' |
9 | import { FriendService } from '../shared' | ||
8 | 10 | ||
9 | @Component({ | 11 | @Component({ |
10 | selector: 'my-friend-list', | 12 | selector: 'my-friend-list', |
11 | templateUrl: './friend-list.component.html', | 13 | templateUrl: './friend-list.component.html', |
12 | styleUrls: ['./friend-list.component.scss'] | 14 | styleUrls: ['./friend-list.component.scss'] |
13 | }) | 15 | }) |
14 | export class FriendListComponent implements OnInit { | 16 | export class FriendListComponent extends RestTable implements OnInit { |
15 | friends: Pod[] = [] | 17 | friends: Pod[] = [] |
18 | totalRecords = 0 | ||
19 | rowsPerPage = 10 | ||
20 | sort: SortMeta = { field: 'id', order: 1 } | ||
21 | pagination: RestPagination = { count: this.rowsPerPage, start: 0 } | ||
16 | 22 | ||
17 | constructor ( | 23 | constructor ( |
18 | private notificationsService: NotificationsService, | 24 | private notificationsService: NotificationsService, |
19 | private confirmService: ConfirmService, | 25 | private confirmService: ConfirmService, |
20 | private friendService: FriendService | 26 | private friendService: FriendService |
21 | ) {} | 27 | ) { |
28 | super() | ||
29 | } | ||
22 | 30 | ||
23 | ngOnInit () { | 31 | ngOnInit () { |
24 | this.loadData() | 32 | this.loadData() |
@@ -65,11 +73,12 @@ export class FriendListComponent implements OnInit { | |||
65 | ) | 73 | ) |
66 | } | 74 | } |
67 | 75 | ||
68 | private loadData () { | 76 | protected loadData () { |
69 | this.friendService.getFriends() | 77 | this.friendService.getFriends(this.pagination, this.sort) |
70 | .subscribe( | 78 | .subscribe( |
71 | resultList => { | 79 | resultList => { |
72 | this.friends = resultList.data | 80 | this.friends = resultList.data |
81 | this.totalRecords = resultList.total | ||
73 | }, | 82 | }, |
74 | 83 | ||
75 | err => this.notificationsService.error('Error', err.message) | 84 | err => this.notificationsService.error('Error', err.message) |
diff --git a/client/src/app/+admin/friends/shared/friend.service.ts b/client/src/app/+admin/friends/shared/friend.service.ts index 274373e3b..a32cdcc88 100644 --- a/client/src/app/+admin/friends/shared/friend.service.ts +++ b/client/src/app/+admin/friends/shared/friend.service.ts | |||
@@ -1,9 +1,12 @@ | |||
1 | import { Injectable } from '@angular/core' | 1 | import { Injectable } from '@angular/core' |
2 | import { HttpClient } from '@angular/common/http' | 2 | import { HttpClient, HttpParams } from '@angular/common/http' |
3 | import { Observable } from 'rxjs/Observable' | ||
3 | import 'rxjs/add/operator/catch' | 4 | import 'rxjs/add/operator/catch' |
4 | import 'rxjs/add/operator/map' | 5 | import 'rxjs/add/operator/map' |
5 | 6 | ||
6 | import { RestExtractor } from '../../../shared' | 7 | import { SortMeta } from 'primeng/primeng' |
8 | |||
9 | import { RestExtractor, RestPagination, RestService } from '../../../shared' | ||
7 | import { Pod, ResultList } from '../../../../../../shared' | 10 | import { Pod, ResultList } from '../../../../../../shared' |
8 | 11 | ||
9 | @Injectable() | 12 | @Injectable() |
@@ -12,11 +15,15 @@ export class FriendService { | |||
12 | 15 | ||
13 | constructor ( | 16 | constructor ( |
14 | private authHttp: HttpClient, | 17 | private authHttp: HttpClient, |
18 | private restService: RestService, | ||
15 | private restExtractor: RestExtractor | 19 | private restExtractor: RestExtractor |
16 | ) {} | 20 | ) {} |
17 | 21 | ||
18 | getFriends () { | 22 | getFriends (pagination: RestPagination, sort: SortMeta): Observable<ResultList<Pod>> { |
19 | return this.authHttp.get<ResultList<Pod>>(FriendService.BASE_FRIEND_URL) | 23 | let params = new HttpParams() |
24 | params = this.restService.addRestGetParams(params, pagination, sort) | ||
25 | |||
26 | return this.authHttp.get<ResultList<Pod>>(FriendService.BASE_FRIEND_URL, { params }) | ||
20 | .map(res => this.restExtractor.convertResultListDateToHuman(res)) | 27 | .map(res => this.restExtractor.convertResultListDateToHuman(res)) |
21 | .catch(res => this.restExtractor.handleError(res)) | 28 | .catch(res => this.restExtractor.handleError(res)) |
22 | } | 29 | } |
diff --git a/server/controllers/api/pods.ts b/server/controllers/api/pods.ts index e1e8ff6ca..ec94efc35 100644 --- a/server/controllers/api/pods.ts +++ b/server/controllers/api/pods.ts | |||
@@ -1,39 +1,33 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | 2 | ||
3 | import { database as db } from '../../initializers/database' | 3 | import { database as db } from '../../initializers/database' |
4 | import { CONFIG } from '../../initializers' | 4 | import { logger, getFormattedObjects } from '../../helpers' |
5 | import { | 5 | import { |
6 | logger, | ||
7 | getMyPublicCert, | ||
8 | getFormattedObjects | ||
9 | } from '../../helpers' | ||
10 | import { | ||
11 | sendOwnedVideosToPod, | ||
12 | makeFriends, | 6 | makeFriends, |
13 | quitFriends, | 7 | quitFriends, |
14 | removeFriend | 8 | removeFriend |
15 | } from '../../lib' | 9 | } from '../../lib' |
16 | import { | 10 | import { |
17 | podsAddValidator, | ||
18 | authenticate, | 11 | authenticate, |
19 | ensureIsAdmin, | 12 | ensureIsAdmin, |
20 | makeFriendsValidator, | 13 | makeFriendsValidator, |
21 | setBodyHostPort, | ||
22 | setBodyHostsPort, | 14 | setBodyHostsPort, |
23 | podRemoveValidator | 15 | podRemoveValidator, |
16 | paginationValidator, | ||
17 | setPagination, | ||
18 | setPodsSort, | ||
19 | podsSortValidator | ||
24 | } from '../../middlewares' | 20 | } from '../../middlewares' |
25 | import { | 21 | import { PodInstance } from '../../models' |
26 | PodInstance | ||
27 | } from '../../models' | ||
28 | import { Pod as FormattedPod } from '../../../shared' | ||
29 | 22 | ||
30 | const podsRouter = express.Router() | 23 | const podsRouter = express.Router() |
31 | 24 | ||
32 | podsRouter.get('/', listPods) | 25 | podsRouter.get('/', |
33 | podsRouter.post('/', | 26 | paginationValidator, |
34 | setBodyHostPort, // We need to modify the host before running the validator! | 27 | podsSortValidator, |
35 | podsAddValidator, | 28 | setPodsSort, |
36 | addPods | 29 | setPagination, |
30 | listPods | ||
37 | ) | 31 | ) |
38 | podsRouter.post('/make-friends', | 32 | podsRouter.post('/make-friends', |
39 | authenticate, | 33 | authenticate, |
@@ -62,26 +56,9 @@ export { | |||
62 | 56 | ||
63 | // --------------------------------------------------------------------------- | 57 | // --------------------------------------------------------------------------- |
64 | 58 | ||
65 | function addPods (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
66 | const informations = req.body | ||
67 | |||
68 | const pod = db.Pod.build(informations) | ||
69 | pod.save() | ||
70 | .then(podCreated => { | ||
71 | return sendOwnedVideosToPod(podCreated.id) | ||
72 | }) | ||
73 | .then(() => { | ||
74 | return getMyPublicCert() | ||
75 | }) | ||
76 | .then(cert => { | ||
77 | return res.json({ cert: cert, email: CONFIG.ADMIN.EMAIL }) | ||
78 | }) | ||
79 | .catch(err => next(err)) | ||
80 | } | ||
81 | |||
82 | function listPods (req: express.Request, res: express.Response, next: express.NextFunction) { | 59 | function listPods (req: express.Request, res: express.Response, next: express.NextFunction) { |
83 | db.Pod.list() | 60 | db.Pod.listForApi(req.query.start, req.query.count, req.query.sort) |
84 | .then(podsList => res.json(getFormattedObjects<FormattedPod, PodInstance>(podsList, podsList.length))) | 61 | .then(resultList => res.json(getFormattedObjects(resultList.data, resultList.total))) |
85 | .catch(err => next(err)) | 62 | .catch(err => next(err)) |
86 | } | 63 | } |
87 | 64 | ||
diff --git a/server/controllers/api/remote/pods.ts b/server/controllers/api/remote/pods.ts index 69bbd4378..6f7b5f651 100644 --- a/server/controllers/api/remote/pods.ts +++ b/server/controllers/api/remote/pods.ts | |||
@@ -1,18 +1,34 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | 2 | ||
3 | import { database as db } from '../../../initializers/database' | 3 | import { database as db } from '../../../initializers/database' |
4 | import { checkSignature, signatureValidator } from '../../../middlewares' | 4 | import { |
5 | import { PodSignature } from '../../../../shared' | 5 | checkSignature, |
6 | signatureValidator, | ||
7 | setBodyHostPort, | ||
8 | remotePodsAddValidator | ||
9 | } from '../../../middlewares' | ||
10 | import { sendOwnedVideosToPod } from '../../../lib' | ||
11 | import { getMyPublicCert, getFormattedObjects } from '../../../helpers' | ||
12 | import { CONFIG } from '../../../initializers' | ||
13 | import { PodInstance } from '../../../models' | ||
14 | import { PodSignature, Pod as FormattedPod } from '../../../../shared' | ||
6 | 15 | ||
7 | const remotePodsRouter = express.Router() | 16 | const remotePodsRouter = express.Router() |
8 | 17 | ||
9 | // Post because this is a secured request | ||
10 | remotePodsRouter.post('/remove', | 18 | remotePodsRouter.post('/remove', |
11 | signatureValidator, | 19 | signatureValidator, |
12 | checkSignature, | 20 | checkSignature, |
13 | removePods | 21 | removePods |
14 | ) | 22 | ) |
15 | 23 | ||
24 | remotePodsRouter.post('/list', remotePodsList) | ||
25 | |||
26 | remotePodsRouter.post('/add', | ||
27 | setBodyHostPort, // We need to modify the host before running the validator! | ||
28 | remotePodsAddValidator, | ||
29 | addPods | ||
30 | ) | ||
31 | |||
16 | // --------------------------------------------------------------------------- | 32 | // --------------------------------------------------------------------------- |
17 | 33 | ||
18 | export { | 34 | export { |
@@ -21,6 +37,29 @@ export { | |||
21 | 37 | ||
22 | // --------------------------------------------------------------------------- | 38 | // --------------------------------------------------------------------------- |
23 | 39 | ||
40 | function addPods (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
41 | const information = req.body | ||
42 | |||
43 | const pod = db.Pod.build(information) | ||
44 | pod.save() | ||
45 | .then(podCreated => { | ||
46 | return sendOwnedVideosToPod(podCreated.id) | ||
47 | }) | ||
48 | .then(() => { | ||
49 | return getMyPublicCert() | ||
50 | }) | ||
51 | .then(cert => { | ||
52 | return res.json({ cert: cert, email: CONFIG.ADMIN.EMAIL }) | ||
53 | }) | ||
54 | .catch(err => next(err)) | ||
55 | } | ||
56 | |||
57 | function remotePodsList (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
58 | db.Pod.list() | ||
59 | .then(podsList => res.json(getFormattedObjects<FormattedPod, PodInstance>(podsList, podsList.length))) | ||
60 | .catch(err => next(err)) | ||
61 | } | ||
62 | |||
24 | function removePods (req: express.Request, res: express.Response, next: express.NextFunction) { | 63 | function removePods (req: express.Request, res: express.Response, next: express.NextFunction) { |
25 | const signature: PodSignature = req.body.signature | 64 | const signature: PodSignature = req.body.signature |
26 | const host = signature.host | 65 | const host = signature.host |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 491fb78f9..132164746 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -32,6 +32,7 @@ const SEARCHABLE_COLUMNS = { | |||
32 | 32 | ||
33 | // Sortable columns per schema | 33 | // Sortable columns per schema |
34 | const SORTABLE_COLUMNS = { | 34 | const SORTABLE_COLUMNS = { |
35 | PODS: [ 'id', 'host', 'score', 'createdAt' ], | ||
35 | USERS: [ 'id', 'username', 'createdAt' ], | 36 | USERS: [ 'id', 'username', 'createdAt' ], |
36 | VIDEO_ABUSES: [ 'id', 'createdAt' ], | 37 | VIDEO_ABUSES: [ 'id', 'createdAt' ], |
37 | VIDEOS: [ 'name', 'duration', 'createdAt', 'views', 'likes' ], | 38 | VIDEOS: [ 'name', 'duration', 'createdAt', 'views', 'likes' ], |
diff --git a/server/lib/friends.ts b/server/lib/friends.ts index c0dd24c53..4cc4a82bf 100644 --- a/server/lib/friends.ts +++ b/server/lib/friends.ts | |||
@@ -334,9 +334,9 @@ function computeWinningPods (hosts: string[], podsScore: { [ host: string ]: num | |||
334 | 334 | ||
335 | function getForeignPodsList (host: string) { | 335 | function getForeignPodsList (host: string) { |
336 | return new Promise< ResultList<FormattedPod> >((res, rej) => { | 336 | return new Promise< ResultList<FormattedPod> >((res, rej) => { |
337 | const path = '/api/' + API_VERSION + '/pods' | 337 | const path = '/api/' + API_VERSION + '/remote/pods/list' |
338 | 338 | ||
339 | request.get(REMOTE_SCHEME.HTTP + '://' + host + path, (err, response, body) => { | 339 | request.post(REMOTE_SCHEME.HTTP + '://' + host + path, (err, response, body) => { |
340 | if (err) return rej(err) | 340 | if (err) return rej(err) |
341 | 341 | ||
342 | try { | 342 | try { |
@@ -357,7 +357,7 @@ function makeRequestsToWinningPods (cert: string, podsList: PodInstance[]) { | |||
357 | 357 | ||
358 | return Promise.map(podsList, pod => { | 358 | return Promise.map(podsList, pod => { |
359 | const params = { | 359 | const params = { |
360 | url: REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + API_VERSION + '/pods/', | 360 | url: REMOTE_SCHEME.HTTP + '://' + pod.host + '/api/' + API_VERSION + '/remote/pods/add', |
361 | method: 'POST' as 'POST', | 361 | method: 'POST' as 'POST', |
362 | json: { | 362 | json: { |
363 | host: CONFIG.WEBSERVER.HOST, | 363 | host: CONFIG.WEBSERVER.HOST, |
diff --git a/server/middlewares/sort.ts b/server/middlewares/sort.ts index 687ce097b..2c70ff5f0 100644 --- a/server/middlewares/sort.ts +++ b/server/middlewares/sort.ts | |||
@@ -4,6 +4,12 @@ import * as express from 'express' | |||
4 | import { SortType } from '../helpers' | 4 | import { SortType } from '../helpers' |
5 | import { database } from '../initializers' | 5 | import { database } from '../initializers' |
6 | 6 | ||
7 | function setPodsSort (req: express.Request, res: express.Response, next: express.NextFunction) { | ||
8 | if (!req.query.sort) req.query.sort = '-createdAt' | ||
9 | |||
10 | return next() | ||
11 | } | ||
12 | |||
7 | function setUsersSort (req: express.Request, res: express.Response, next: express.NextFunction) { | 13 | function setUsersSort (req: express.Request, res: express.Response, next: express.NextFunction) { |
8 | if (!req.query.sort) req.query.sort = '-createdAt' | 14 | if (!req.query.sort) req.query.sort = '-createdAt' |
9 | 15 | ||
@@ -46,6 +52,7 @@ function setBlacklistSort (req: express.Request, res: express.Response, next: ex | |||
46 | // --------------------------------------------------------------------------- | 52 | // --------------------------------------------------------------------------- |
47 | 53 | ||
48 | export { | 54 | export { |
55 | setPodsSort, | ||
49 | setUsersSort, | 56 | setUsersSort, |
50 | setVideoAbusesSort, | 57 | setVideoAbusesSort, |
51 | setVideosSort, | 58 | setVideosSort, |
diff --git a/server/middlewares/validators/pods.ts b/server/middlewares/validators/pods.ts index ab7702e78..575c36526 100644 --- a/server/middlewares/validators/pods.ts +++ b/server/middlewares/validators/pods.ts | |||
@@ -3,7 +3,7 @@ import * as express from 'express' | |||
3 | 3 | ||
4 | import { database as db } from '../../initializers/database' | 4 | import { database as db } from '../../initializers/database' |
5 | import { checkErrors } from './utils' | 5 | import { checkErrors } from './utils' |
6 | import { logger, isEachUniqueHostValid, isHostValid } from '../../helpers' | 6 | import { logger, isEachUniqueHostValid } from '../../helpers' |
7 | import { CONFIG } from '../../initializers' | 7 | import { CONFIG } from '../../initializers' |
8 | import { hasFriends } from '../../lib' | 8 | import { hasFriends } from '../../lib' |
9 | import { isTestInstance } from '../../helpers' | 9 | import { isTestInstance } from '../../helpers' |
@@ -41,32 +41,6 @@ const makeFriendsValidator = [ | |||
41 | } | 41 | } |
42 | ] | 42 | ] |
43 | 43 | ||
44 | const podsAddValidator = [ | ||
45 | body('host').custom(isHostValid).withMessage('Should have a host'), | ||
46 | body('email').isEmail().withMessage('Should have an email'), | ||
47 | body('publicKey').not().isEmpty().withMessage('Should have a public key'), | ||
48 | |||
49 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
50 | logger.debug('Checking podsAdd parameters', { parameters: req.body }) | ||
51 | |||
52 | checkErrors(req, res, () => { | ||
53 | db.Pod.loadByHost(req.body.host) | ||
54 | .then(pod => { | ||
55 | // Pod with this host already exists | ||
56 | if (pod) { | ||
57 | return res.sendStatus(409) | ||
58 | } | ||
59 | |||
60 | return next() | ||
61 | }) | ||
62 | .catch(err => { | ||
63 | logger.error('Cannot load pod by host.', err) | ||
64 | res.sendStatus(500) | ||
65 | }) | ||
66 | }) | ||
67 | } | ||
68 | ] | ||
69 | |||
70 | const podRemoveValidator = [ | 44 | const podRemoveValidator = [ |
71 | param('id').isNumeric().not().isEmpty().withMessage('Should have a valid id'), | 45 | param('id').isNumeric().not().isEmpty().withMessage('Should have a valid id'), |
72 | 46 | ||
@@ -96,6 +70,5 @@ const podRemoveValidator = [ | |||
96 | 70 | ||
97 | export { | 71 | export { |
98 | makeFriendsValidator, | 72 | makeFriendsValidator, |
99 | podsAddValidator, | ||
100 | podRemoveValidator | 73 | podRemoveValidator |
101 | } | 74 | } |
diff --git a/server/middlewares/validators/remote/index.ts b/server/middlewares/validators/remote/index.ts index d0d7740b1..f1f26043e 100644 --- a/server/middlewares/validators/remote/index.ts +++ b/server/middlewares/validators/remote/index.ts | |||
@@ -1,2 +1,3 @@ | |||
1 | export * from './pods' | ||
1 | export * from './signature' | 2 | export * from './signature' |
2 | export * from './videos' | 3 | export * from './videos' |
diff --git a/server/middlewares/validators/remote/pods.ts b/server/middlewares/validators/remote/pods.ts new file mode 100644 index 000000000..f917b61ee --- /dev/null +++ b/server/middlewares/validators/remote/pods.ts | |||
@@ -0,0 +1,38 @@ | |||
1 | import { body } from 'express-validator/check' | ||
2 | import * as express from 'express' | ||
3 | |||
4 | import { database as db } from '../../../initializers' | ||
5 | import { isHostValid, logger } from '../../../helpers' | ||
6 | import { checkErrors } from '../utils' | ||
7 | |||
8 | const remotePodsAddValidator = [ | ||
9 | body('host').custom(isHostValid).withMessage('Should have a host'), | ||
10 | body('email').isEmail().withMessage('Should have an email'), | ||
11 | body('publicKey').not().isEmpty().withMessage('Should have a public key'), | ||
12 | |||
13 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | ||
14 | logger.debug('Checking podsAdd parameters', { parameters: req.body }) | ||
15 | |||
16 | checkErrors(req, res, () => { | ||
17 | db.Pod.loadByHost(req.body.host) | ||
18 | .then(pod => { | ||
19 | // Pod with this host already exists | ||
20 | if (pod) { | ||
21 | return res.sendStatus(409) | ||
22 | } | ||
23 | |||
24 | return next() | ||
25 | }) | ||
26 | .catch(err => { | ||
27 | logger.error('Cannot load pod by host.', err) | ||
28 | res.sendStatus(500) | ||
29 | }) | ||
30 | }) | ||
31 | } | ||
32 | ] | ||
33 | |||
34 | // --------------------------------------------------------------------------- | ||
35 | |||
36 | export { | ||
37 | remotePodsAddValidator | ||
38 | } | ||
diff --git a/server/middlewares/validators/sort.ts b/server/middlewares/validators/sort.ts index a6f5ccb6b..227f309ad 100644 --- a/server/middlewares/validators/sort.ts +++ b/server/middlewares/validators/sort.ts | |||
@@ -6,11 +6,13 @@ import { logger } from '../../helpers' | |||
6 | import { SORTABLE_COLUMNS } from '../../initializers' | 6 | import { SORTABLE_COLUMNS } from '../../initializers' |
7 | 7 | ||
8 | // Initialize constants here for better performances | 8 | // Initialize constants here for better performances |
9 | const SORTABLE_PODS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.PODS) | ||
9 | const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS) | 10 | const SORTABLE_USERS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.USERS) |
10 | const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES) | 11 | const SORTABLE_VIDEO_ABUSES_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEO_ABUSES) |
11 | const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS) | 12 | const SORTABLE_VIDEOS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.VIDEOS) |
12 | const SORTABLE_BLACKLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.BLACKLISTS) | 13 | const SORTABLE_BLACKLISTS_COLUMNS = createSortableColumns(SORTABLE_COLUMNS.BLACKLISTS) |
13 | 14 | ||
15 | const podsSortValidator = checkSort(SORTABLE_PODS_COLUMNS) | ||
14 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) | 16 | const usersSortValidator = checkSort(SORTABLE_USERS_COLUMNS) |
15 | const videoAbusesSortValidator = checkSort(SORTABLE_VIDEO_ABUSES_COLUMNS) | 17 | const videoAbusesSortValidator = checkSort(SORTABLE_VIDEO_ABUSES_COLUMNS) |
16 | const videosSortValidator = checkSort(SORTABLE_VIDEOS_COLUMNS) | 18 | const videosSortValidator = checkSort(SORTABLE_VIDEOS_COLUMNS) |
@@ -19,6 +21,7 @@ const blacklistSortValidator = checkSort(SORTABLE_BLACKLISTS_COLUMNS) | |||
19 | // --------------------------------------------------------------------------- | 21 | // --------------------------------------------------------------------------- |
20 | 22 | ||
21 | export { | 23 | export { |
24 | podsSortValidator, | ||
22 | usersSortValidator, | 25 | usersSortValidator, |
23 | videoAbusesSortValidator, | 26 | videoAbusesSortValidator, |
24 | videosSortValidator, | 27 | videosSortValidator, |
diff --git a/server/middlewares/validators/utils.ts b/server/middlewares/validators/utils.ts index 8845f8399..ea107bbe8 100644 --- a/server/middlewares/validators/utils.ts +++ b/server/middlewares/validators/utils.ts | |||
@@ -3,12 +3,12 @@ import * as express from 'express' | |||
3 | 3 | ||
4 | import { logger } from '../../helpers' | 4 | import { logger } from '../../helpers' |
5 | 5 | ||
6 | function checkErrors (req: express.Request, res: express.Response, next: express.NextFunction, statusCode = 400) { | 6 | function checkErrors (req: express.Request, res: express.Response, next: express.NextFunction) { |
7 | const errors = validationResult(req) | 7 | const errors = validationResult(req) |
8 | 8 | ||
9 | if (!errors.isEmpty()) { | 9 | if (!errors.isEmpty()) { |
10 | logger.warn('Incorrect request parameters', { path: req.originalUrl, err: errors.mapped() }) | 10 | logger.warn('Incorrect request parameters', { path: req.originalUrl, err: errors.mapped() }) |
11 | return res.status(statusCode).json({ errors: errors.mapped() }) | 11 | return res.status(400).json({ errors: errors.mapped() }) |
12 | } | 12 | } |
13 | 13 | ||
14 | return next() | 14 | return next() |
diff --git a/server/models/pod/pod-interface.ts b/server/models/pod/pod-interface.ts index fc763acac..7e095d424 100644 --- a/server/models/pod/pod-interface.ts +++ b/server/models/pod/pod-interface.ts | |||
@@ -3,6 +3,7 @@ import * as Promise from 'bluebird' | |||
3 | 3 | ||
4 | // Don't use barrel, import just what we need | 4 | // Don't use barrel, import just what we need |
5 | import { Pod as FormattedPod } from '../../../shared/models/pods/pod.model' | 5 | import { Pod as FormattedPod } from '../../../shared/models/pods/pod.model' |
6 | import { ResultList } from '../../../shared/models/result-list.model' | ||
6 | 7 | ||
7 | export namespace PodMethods { | 8 | export namespace PodMethods { |
8 | export type ToFormattedJSON = (this: PodInstance) => FormattedPod | 9 | export type ToFormattedJSON = (this: PodInstance) => FormattedPod |
@@ -13,6 +14,8 @@ export namespace PodMethods { | |||
13 | 14 | ||
14 | export type List = () => Promise<PodInstance[]> | 15 | export type List = () => Promise<PodInstance[]> |
15 | 16 | ||
17 | export type ListForApi = (start: number, count: number, sort: string) => Promise< ResultList<PodInstance> > | ||
18 | |||
16 | export type ListAllIds = (transaction: Sequelize.Transaction) => Promise<number[]> | 19 | export type ListAllIds = (transaction: Sequelize.Transaction) => Promise<number[]> |
17 | 20 | ||
18 | export type ListRandomPodIdsWithRequest = (limit: number, tableWithPods: string, tableWithPodsJoins: string) => Promise<number[]> | 21 | export type ListRandomPodIdsWithRequest = (limit: number, tableWithPods: string, tableWithPodsJoins: string) => Promise<number[]> |
@@ -32,6 +35,7 @@ export interface PodClass { | |||
32 | countAll: PodMethods.CountAll | 35 | countAll: PodMethods.CountAll |
33 | incrementScores: PodMethods.IncrementScores | 36 | incrementScores: PodMethods.IncrementScores |
34 | list: PodMethods.List | 37 | list: PodMethods.List |
38 | listForApi: PodMethods.ListForApi | ||
35 | listAllIds: PodMethods.ListAllIds | 39 | listAllIds: PodMethods.ListAllIds |
36 | listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest | 40 | listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest |
37 | listBadPods: PodMethods.ListBadPods | 41 | listBadPods: PodMethods.ListBadPods |
diff --git a/server/models/pod/pod.ts b/server/models/pod/pod.ts index 1440ac9b4..e4d7db48a 100644 --- a/server/models/pod/pod.ts +++ b/server/models/pod/pod.ts | |||
@@ -4,7 +4,7 @@ import * as Sequelize from 'sequelize' | |||
4 | import { FRIEND_SCORE, PODS_SCORE } from '../../initializers' | 4 | import { FRIEND_SCORE, PODS_SCORE } from '../../initializers' |
5 | import { logger, isHostValid } from '../../helpers' | 5 | import { logger, isHostValid } from '../../helpers' |
6 | 6 | ||
7 | import { addMethodsToModel } from '../utils' | 7 | import { addMethodsToModel, getSort } from '../utils' |
8 | import { | 8 | import { |
9 | PodInstance, | 9 | PodInstance, |
10 | PodAttributes, | 10 | PodAttributes, |
@@ -17,6 +17,7 @@ let toFormattedJSON: PodMethods.ToFormattedJSON | |||
17 | let countAll: PodMethods.CountAll | 17 | let countAll: PodMethods.CountAll |
18 | let incrementScores: PodMethods.IncrementScores | 18 | let incrementScores: PodMethods.IncrementScores |
19 | let list: PodMethods.List | 19 | let list: PodMethods.List |
20 | let listForApi: PodMethods.ListForApi | ||
20 | let listAllIds: PodMethods.ListAllIds | 21 | let listAllIds: PodMethods.ListAllIds |
21 | let listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest | 22 | let listRandomPodIdsWithRequest: PodMethods.ListRandomPodIdsWithRequest |
22 | let listBadPods: PodMethods.ListBadPods | 23 | let listBadPods: PodMethods.ListBadPods |
@@ -78,6 +79,7 @@ export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.Da | |||
78 | countAll, | 79 | countAll, |
79 | incrementScores, | 80 | incrementScores, |
80 | list, | 81 | list, |
82 | listForApi, | ||
81 | listAllIds, | 83 | listAllIds, |
82 | listRandomPodIdsWithRequest, | 84 | listRandomPodIdsWithRequest, |
83 | listBadPods, | 85 | listBadPods, |
@@ -142,6 +144,21 @@ list = function () { | |||
142 | return Pod.findAll() | 144 | return Pod.findAll() |
143 | } | 145 | } |
144 | 146 | ||
147 | listForApi = function (start: number, count: number, sort: string) { | ||
148 | const query = { | ||
149 | offset: start, | ||
150 | limit: count, | ||
151 | order: [ getSort(sort) ] | ||
152 | } | ||
153 | |||
154 | return Pod.findAndCountAll(query).then(({ rows, count }) => { | ||
155 | return { | ||
156 | data: rows, | ||
157 | total: count | ||
158 | } | ||
159 | }) | ||
160 | } | ||
161 | |||
145 | listAllIds = function (transaction: Sequelize.Transaction) { | 162 | listAllIds = function (transaction: Sequelize.Transaction) { |
146 | const query = { | 163 | const query = { |
147 | attributes: [ 'id' ], | 164 | attributes: [ 'id' ], |
diff --git a/server/tests/api/check-params/pods.ts b/server/tests/api/check-params/pods.ts index a897e4dcd..9f9c2e4f0 100644 --- a/server/tests/api/check-params/pods.ts +++ b/server/tests/api/check-params/pods.ts | |||
@@ -15,7 +15,6 @@ import { | |||
15 | } from '../../utils' | 15 | } from '../../utils' |
16 | 16 | ||
17 | describe('Test pods API validators', function () { | 17 | describe('Test pods API validators', function () { |
18 | const path = '/api/v1/pods/' | ||
19 | let server: ServerInfo | 18 | let server: ServerInfo |
20 | 19 | ||
21 | // --------------------------------------------------------------- | 20 | // --------------------------------------------------------------- |
@@ -30,6 +29,7 @@ describe('Test pods API validators', function () { | |||
30 | }) | 29 | }) |
31 | 30 | ||
32 | describe('When managing friends', function () { | 31 | describe('When managing friends', function () { |
32 | const path = '/api/v1/pods/' | ||
33 | let userAccessToken = null | 33 | let userAccessToken = null |
34 | 34 | ||
35 | before(async function () { | 35 | before(async function () { |
@@ -110,6 +110,32 @@ describe('Test pods API validators', function () { | |||
110 | }) | 110 | }) |
111 | }) | 111 | }) |
112 | 112 | ||
113 | describe('When listing friends', function () { | ||
114 | it('Should fail with a bad start pagination', async function () { | ||
115 | await request(server.url) | ||
116 | .get(path) | ||
117 | .query({ start: 'hello' }) | ||
118 | .set('Accept', 'application/json') | ||
119 | .expect(400) | ||
120 | }) | ||
121 | |||
122 | it('Should fail with a bad count pagination', async function () { | ||
123 | await request(server.url) | ||
124 | .get(path) | ||
125 | .query({ count: 'hello' }) | ||
126 | .set('Accept', 'application/json') | ||
127 | .expect(400) | ||
128 | }) | ||
129 | |||
130 | it('Should fail with an incorrect sort', async function () { | ||
131 | await request(server.url) | ||
132 | .get(path) | ||
133 | .query({ sort: 'hello' }) | ||
134 | .set('Accept', 'application/json') | ||
135 | .expect(400) | ||
136 | }) | ||
137 | }) | ||
138 | |||
113 | describe('When quitting friends', function () { | 139 | describe('When quitting friends', function () { |
114 | it('Should fail with an invalid token', async function () { | 140 | it('Should fail with an invalid token', async function () { |
115 | await request(server.url) | 141 | await request(server.url) |
@@ -175,7 +201,9 @@ describe('Test pods API validators', function () { | |||
175 | }) | 201 | }) |
176 | }) | 202 | }) |
177 | 203 | ||
178 | describe('When adding a pod', function () { | 204 | describe('When adding a pod from remote', function () { |
205 | const path = '/api/v1/remote/pods/add' | ||
206 | |||
179 | it('Should fail with nothing', async function () { | 207 | it('Should fail with nothing', async function () { |
180 | const fields = {} | 208 | const fields = {} |
181 | await makePostBodyRequest({ url: server.url, path, fields }) | 209 | await makePostBodyRequest({ url: server.url, path, fields }) |
diff --git a/server/tests/api/friends-basic.ts b/server/tests/api/friends-basic.ts index 13edf6273..efca4fda2 100644 --- a/server/tests/api/friends-basic.ts +++ b/server/tests/api/friends-basic.ts | |||
@@ -15,7 +15,8 @@ import { | |||
15 | makeFriends, | 15 | makeFriends, |
16 | getFriendsList, | 16 | getFriendsList, |
17 | dateIsValid, | 17 | dateIsValid, |
18 | quitOneFriend | 18 | quitOneFriend, |
19 | getPodsListPaginationAndSort | ||
19 | } from '../utils' | 20 | } from '../utils' |
20 | 21 | ||
21 | describe('Test basic friends', function () { | 22 | describe('Test basic friends', function () { |
@@ -120,6 +121,22 @@ describe('Test basic friends', function () { | |||
120 | await makeFriends(server.url, server.accessToken, 409) | 121 | await makeFriends(server.url, server.accessToken, 409) |
121 | }) | 122 | }) |
122 | 123 | ||
124 | it('Should list friends correctly', async function () { | ||
125 | const start = 1 | ||
126 | const count = 1 | ||
127 | const sort = '-host' | ||
128 | |||
129 | const res = await getPodsListPaginationAndSort(servers[0].url, start, count, sort) | ||
130 | expect(res.body.total).to.equal(2) | ||
131 | expect(res.body.data).to.have.lengthOf(1) | ||
132 | |||
133 | const pod = res.body.data[0] | ||
134 | expect(pod.host).to.equal('localhost:9002') | ||
135 | expect(pod.email).to.equal('admin2@example.com') | ||
136 | expect(pod.score).to.equal(20) | ||
137 | expect(dateIsValid(pod.createdAt)).to.be.true | ||
138 | }) | ||
139 | |||
123 | it('Should quit friends of pod 2', async function () { | 140 | it('Should quit friends of pod 2', async function () { |
124 | this.timeout(10000) | 141 | this.timeout(10000) |
125 | 142 | ||
diff --git a/server/tests/utils/pods.ts b/server/tests/utils/pods.ts index a86dd20d9..52e807e70 100644 --- a/server/tests/utils/pods.ts +++ b/server/tests/utils/pods.ts | |||
@@ -12,6 +12,19 @@ function getFriendsList (url: string) { | |||
12 | .expect('Content-Type', /json/) | 12 | .expect('Content-Type', /json/) |
13 | } | 13 | } |
14 | 14 | ||
15 | function getPodsListPaginationAndSort (url: string, start: number, count: number, sort: string) { | ||
16 | const path = '/api/v1/pods/' | ||
17 | |||
18 | return request(url) | ||
19 | .get(path) | ||
20 | .query({ start }) | ||
21 | .query({ count }) | ||
22 | .query({ sort }) | ||
23 | .set('Accept', 'application/json') | ||
24 | .expect(200) | ||
25 | .expect('Content-Type', /json/) | ||
26 | } | ||
27 | |||
15 | async function makeFriends (url: string, accessToken: string, expectedStatus = 204) { | 28 | async function makeFriends (url: string, accessToken: string, expectedStatus = 204) { |
16 | // Which pod makes friends with which pod | 29 | // Which pod makes friends with which pod |
17 | const friendsMatrix = { | 30 | const friendsMatrix = { |
@@ -85,5 +98,6 @@ export { | |||
85 | getFriendsList, | 98 | getFriendsList, |
86 | makeFriends, | 99 | makeFriends, |
87 | quitFriends, | 100 | quitFriends, |
88 | quitOneFriend | 101 | quitOneFriend, |
102 | getPodsListPaginationAndSort | ||
89 | } | 103 | } |