aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/src/app/+admin/friends/friend-list/friend-list.component.html2
-rw-r--r--client/src/app/+admin/friends/friend-list/friend-list.component.ts30
-rw-r--r--client/src/app/+admin/friends/shared/friend.service.ts9
-rw-r--r--server/controllers/api/pods.ts20
-rw-r--r--server/lib/friends.ts18
-rw-r--r--server/middlewares/validators/pods.ts26
-rw-r--r--server/tests/api/check-params/pods.js52
-rw-r--r--server/tests/api/friends-advanced.js92
-rw-r--r--server/tests/api/friends-basic.js65
-rw-r--r--server/tests/utils/pods.js23
10 files changed, 324 insertions, 13 deletions
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 45695f7c8..7b9fff304 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,7 +2,7 @@
2 <div class="content-padding"> 2 <div class="content-padding">
3 <h3>Friends list</h3> 3 <h3>Friends list</h3>
4 4
5 <ng2-smart-table [settings]="tableSettings" [source]="friendsSource"></ng2-smart-table> 5 <ng2-smart-table [settings]="tableSettings" [source]="friendsSource" (delete)="removeFriend($event)"></ng2-smart-table>
6 6
7 <a *ngIf="hasFriends()" class="btn btn-danger pull-left" (click)="quitFriends()"> 7 <a *ngIf="hasFriends()" class="btn btn-danger pull-left" (click)="quitFriends()">
8 Quit friends 8 Quit friends
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 9f0256d7f..822a112cc 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
@@ -6,6 +6,7 @@ import { ServerDataSource } from 'ng2-smart-table'
6import { ConfirmService } from '../../../core' 6import { ConfirmService } from '../../../core'
7import { Utils } from '../../../shared' 7import { Utils } from '../../../shared'
8import { FriendService } from '../shared' 8import { FriendService } from '../shared'
9import { Pod } from '../../../../../../shared'
9 10
10@Component({ 11@Component({
11 selector: 'my-friend-list', 12 selector: 'my-friend-list',
@@ -15,6 +16,7 @@ import { FriendService } from '../shared'
15export class FriendListComponent { 16export class FriendListComponent {
16 friendsSource = null 17 friendsSource = null
17 tableSettings = { 18 tableSettings = {
19 mode: 'external',
18 attr: { 20 attr: {
19 class: 'table-hover' 21 class: 'table-hover'
20 }, 22 },
@@ -23,7 +25,10 @@ export class FriendListComponent {
23 position: 'right', 25 position: 'right',
24 add: false, 26 add: false,
25 edit: false, 27 edit: false,
26 delete: false 28 delete: true
29 },
30 delete: {
31 deleteButtonContent: Utils.getRowDeleteButton()
27 }, 32 },
28 columns: { 33 columns: {
29 id: { 34 id: {
@@ -71,8 +76,7 @@ export class FriendListComponent {
71 76
72 this.friendService.quitFriends().subscribe( 77 this.friendService.quitFriends().subscribe(
73 status => { 78 status => {
74 this.notificationsService.success('Sucess', 'Friends left!') 79 this.notificationsService.success('Success', 'Friends left!')
75
76 this.friendsSource.refresh() 80 this.friendsSource.refresh()
77 }, 81 },
78 82
@@ -81,4 +85,24 @@ export class FriendListComponent {
81 } 85 }
82 ) 86 )
83 } 87 }
88
89 removeFriend ({ data }) {
90 const confirmMessage = 'Do you really want to remove this friend ? All its videos will be deleted.'
91 const friend: Pod = data
92
93 this.confirmService.confirm(confirmMessage, 'Remove').subscribe(
94 res => {
95 if (res === false) return
96
97 this.friendService.removeFriend(friend).subscribe(
98 status => {
99 this.notificationsService.success('Success', 'Friend removed')
100 this.friendsSource.refresh()
101 },
102
103 err => this.notificationsService.error('Error', err.text)
104 )
105 }
106 )
107 }
84} 108}
diff --git a/client/src/app/+admin/friends/shared/friend.service.ts b/client/src/app/+admin/friends/shared/friend.service.ts
index 79de4470e..8bc0239ab 100644
--- a/client/src/app/+admin/friends/shared/friend.service.ts
+++ b/client/src/app/+admin/friends/shared/friend.service.ts
@@ -6,6 +6,7 @@ import 'rxjs/add/operator/map'
6import { ServerDataSource } from 'ng2-smart-table' 6import { ServerDataSource } from 'ng2-smart-table'
7 7
8import { AuthHttp, RestExtractor, RestDataSource, ResultList } from '../../../shared' 8import { AuthHttp, RestExtractor, RestDataSource, ResultList } from '../../../shared'
9import { Pod } from '../../../../../../shared'
9 10
10@Injectable() 11@Injectable()
11export class FriendService { 12export class FriendService {
@@ -20,7 +21,7 @@ export class FriendService {
20 return new RestDataSource(this.authHttp, FriendService.BASE_FRIEND_URL) 21 return new RestDataSource(this.authHttp, FriendService.BASE_FRIEND_URL)
21 } 22 }
22 23
23 makeFriends (notEmptyHosts) { 24 makeFriends (notEmptyHosts: String[]) {
24 const body = { 25 const body = {
25 hosts: notEmptyHosts 26 hosts: notEmptyHosts
26 } 27 }
@@ -35,4 +36,10 @@ export class FriendService {
35 .map(res => res.status) 36 .map(res => res.status)
36 .catch((res) => this.restExtractor.handleError(res)) 37 .catch((res) => this.restExtractor.handleError(res))
37 } 38 }
39
40 removeFriend (friend: Pod) {
41 return this.authHttp.delete(FriendService.BASE_FRIEND_URL + friend.id)
42 .map(this.restExtractor.extractDataBool)
43 .catch((res) => this.restExtractor.handleError(res))
44 }
38} 45}
diff --git a/server/controllers/api/pods.ts b/server/controllers/api/pods.ts
index 5210f9fe4..916b131d9 100644
--- a/server/controllers/api/pods.ts
+++ b/server/controllers/api/pods.ts
@@ -10,7 +10,8 @@ import {
10import { 10import {
11 sendOwnedVideosToPod, 11 sendOwnedVideosToPod,
12 makeFriends, 12 makeFriends,
13 quitFriends 13 quitFriends,
14 removeFriend
14} from '../../lib' 15} from '../../lib'
15import { 16import {
16 podsAddValidator, 17 podsAddValidator,
@@ -18,7 +19,8 @@ import {
18 ensureIsAdmin, 19 ensureIsAdmin,
19 makeFriendsValidator, 20 makeFriendsValidator,
20 setBodyHostPort, 21 setBodyHostPort,
21 setBodyHostsPort 22 setBodyHostsPort,
23 podRemoveValidator
22} from '../../middlewares' 24} from '../../middlewares'
23import { 25import {
24 PodInstance 26 PodInstance
@@ -45,6 +47,12 @@ podsRouter.get('/quitfriends',
45 ensureIsAdmin, 47 ensureIsAdmin,
46 quitFriendsController 48 quitFriendsController
47) 49)
50podsRouter.delete('/:id',
51 authenticate,
52 ensureIsAdmin,
53 podRemoveValidator,
54 removeFriendController
55)
48 56
49// --------------------------------------------------------------------------- 57// ---------------------------------------------------------------------------
50 58
@@ -93,3 +101,11 @@ function quitFriendsController (req: express.Request, res: express.Response, nex
93 .then(() => res.type('json').status(204).end()) 101 .then(() => res.type('json').status(204).end())
94 .catch(err => next(err)) 102 .catch(err => next(err))
95} 103}
104
105function removeFriendController (req: express.Request, res: express.Response, next: express.NextFunction) {
106 const pod = res.locals.pod as PodInstance
107
108 removeFriend(pod)
109 .then(() => (res.type('json').status(204).end()))
110 .catch(err => next(err))
111}
diff --git a/server/lib/friends.ts b/server/lib/friends.ts
index 50355d5d1..bd3ff97a5 100644
--- a/server/lib/friends.ts
+++ b/server/lib/friends.ts
@@ -242,6 +242,23 @@ function fetchRemotePreview (pod: PodInstance, video: VideoInstance) {
242 return request.get(REMOTE_SCHEME.HTTP + '://' + host + path) 242 return request.get(REMOTE_SCHEME.HTTP + '://' + host + path)
243} 243}
244 244
245function removeFriend (pod: PodInstance) {
246 const requestParams = {
247 method: 'POST' as 'POST',
248 path: '/api/' + API_VERSION + '/remote/pods/remove',
249 toPod: pod
250 }
251
252 return makeSecureRequest(requestParams)
253 .then(() => pod.destroy())
254 .then(() => {
255 logger.info('Removed friend.')
256 })
257 .catch(err => {
258 logger.error('Some errors while quitting friend %s (id: %d).', pod.host, pod.id, err)
259 })
260}
261
245function getRequestScheduler () { 262function getRequestScheduler () {
246 return requestScheduler 263 return requestScheduler
247} 264}
@@ -268,6 +285,7 @@ export {
268 hasFriends, 285 hasFriends,
269 makeFriends, 286 makeFriends,
270 quitFriends, 287 quitFriends,
288 removeFriend,
271 removeVideoToFriends, 289 removeVideoToFriends,
272 sendOwnedVideosToPod, 290 sendOwnedVideosToPod,
273 getRequestScheduler, 291 getRequestScheduler,
diff --git a/server/middlewares/validators/pods.ts b/server/middlewares/validators/pods.ts
index 481a66957..d0981cd57 100644
--- a/server/middlewares/validators/pods.ts
+++ b/server/middlewares/validators/pods.ts
@@ -58,9 +58,33 @@ function podsAddValidator (req: express.Request, res: express.Response, next: ex
58 }) 58 })
59} 59}
60 60
61function podRemoveValidator (req: express.Request, res: express.Response, next: express.NextFunction) {
62 req.checkParams('id', 'Should have a valid id').notEmpty().isNumeric()
63
64 logger.debug('Checking podRemoveValidator parameters', { parameters: req.params })
65
66 checkErrors(req, res, function () {
67 db.Pod.load(req.params.id)
68 .then(pod => {
69 if (!pod) {
70 logger.error('Cannot find pod %d.', req.params.id)
71 return res.sendStatus(404)
72 }
73
74 res.locals.pod = pod
75 return next()
76 })
77 .catch(err => {
78 logger.error('Cannot load pod %d.', req.params.id, err)
79 res.sendStatus(500)
80 })
81 })
82}
83
61// --------------------------------------------------------------------------- 84// ---------------------------------------------------------------------------
62 85
63export { 86export {
64 makeFriendsValidator, 87 makeFriendsValidator,
65 podsAddValidator 88 podsAddValidator,
89 podRemoveValidator
66} 90}
diff --git a/server/tests/api/check-params/pods.js b/server/tests/api/check-params/pods.js
index 2567fff5f..35ea59093 100644
--- a/server/tests/api/check-params/pods.js
+++ b/server/tests/api/check-params/pods.js
@@ -17,7 +17,7 @@ describe('Test pods API validators', function () {
17 // --------------------------------------------------------------- 17 // ---------------------------------------------------------------
18 18
19 before(function (done) { 19 before(function (done) {
20 this.timeout(20000) 20 this.timeout(45000)
21 21
22 series([ 22 series([
23 function (next) { 23 function (next) {
@@ -110,7 +110,7 @@ describe('Test pods API validators', function () {
110 .expect(400, done) 110 .expect(400, done)
111 }) 111 })
112 112
113 it('Should fail with a invalid token', function (done) { 113 it('Should fail with an invalid token', function (done) {
114 request(server.url) 114 request(server.url)
115 .post(path + '/makefriends') 115 .post(path + '/makefriends')
116 .send(body) 116 .send(body)
@@ -130,7 +130,7 @@ describe('Test pods API validators', function () {
130 }) 130 })
131 131
132 describe('When quitting friends', function () { 132 describe('When quitting friends', function () {
133 it('Should fail with a invalid token', function (done) { 133 it('Should fail with an invalid token', function (done) {
134 request(server.url) 134 request(server.url)
135 .get(path + '/quitfriends') 135 .get(path + '/quitfriends')
136 .query({ start: 'hello' }) 136 .query({ start: 'hello' })
@@ -148,6 +148,50 @@ describe('Test pods API validators', function () {
148 .expect(403, done) 148 .expect(403, done)
149 }) 149 })
150 }) 150 })
151
152 describe('When removing one friend', function () {
153 it('Should fail with an invalid token', function (done) {
154 request(server.url)
155 .delete(path + '/1')
156 .set('Authorization', 'Bearer faketoken')
157 .set('Accept', 'application/json')
158 .expect(401, done)
159 })
160
161 it('Should fail if the user is not an administrator', function (done) {
162 request(server.url)
163 .delete(path + '/1')
164 .set('Authorization', 'Bearer ' + userAccessToken)
165 .set('Accept', 'application/json')
166 .expect(403, done)
167 })
168
169 it('Should fail with an undefined id', function (done) {
170 request(server.url)
171 .delete(path + '/' + undefined)
172 .set('Authorization', 'Bearer ' + server.accessToken)
173 .set('Accept', 'application/json')
174 .expect(400, done)
175 })
176
177 it('Should fail with an invalid id', function (done) {
178 request(server.url)
179 .delete(path + '/foobar')
180 .set('Authorization', 'Bearer ' + server.accessToken)
181 .set('Accept', 'application/json')
182 .expect(400, done)
183 })
184
185 it('Should fail if the pod is not a friend', function (done) {
186 request(server.url)
187 .delete(path + '/-1')
188 .set('Authorization', 'Bearer ' + server.accessToken)
189 .set('Accept', 'application/json')
190 .expect(404, done)
191 })
192
193 it('Should succeed with the correct parameters')
194 })
151 }) 195 })
152 196
153 describe('When adding a pod', function () { 197 describe('When adding a pod', function () {
@@ -181,7 +225,7 @@ describe('Test pods API validators', function () {
181 requestsUtils.makePostBodyRequest(server.url, path, null, data, done) 225 requestsUtils.makePostBodyRequest(server.url, path, null, data, done)
182 }) 226 })
183 227
184 it('Should fail without an host', function (done) { 228 it('Should fail without a host', function (done) {
185 const data = { 229 const data = {
186 email: 'testexample.com', 230 email: 'testexample.com',
187 publicKey: 'mysuperpublickey' 231 publicKey: 'mysuperpublickey'
diff --git a/server/tests/api/friends-advanced.js b/server/tests/api/friends-advanced.js
index 917583a42..89dc080bc 100644
--- a/server/tests/api/friends-advanced.js
+++ b/server/tests/api/friends-advanced.js
@@ -25,6 +25,20 @@ describe('Test advanced friends', function () {
25 return podsUtils.quitFriends(server.url, server.accessToken, callback) 25 return podsUtils.quitFriends(server.url, server.accessToken, callback)
26 } 26 }
27 27
28 function removeFriend (podNumber, podNumberToRemove, callback) {
29 const server = servers[podNumber - 1]
30 const serverToRemove = servers[podNumberToRemove - 1]
31
32 getFriendsList(podNumber, function (err, res) {
33 if (err) throw err
34
35 let friendsList = res.body.data
36 let podToRemove = friendsList.find((friend) => (friend.host === serverToRemove.host))
37
38 return podsUtils.quitOneFriend(server.url, server.accessToken, podToRemove.id, callback)
39 })
40 }
41
28 function getFriendsList (podNumber, end) { 42 function getFriendsList (podNumber, end) {
29 const server = servers[podNumber - 1] 43 const server = servers[podNumber - 1]
30 return podsUtils.getFriendsList(server.url, end) 44 return podsUtils.getFriendsList(server.url, end)
@@ -288,6 +302,84 @@ describe('Test advanced friends', function () {
288 }) 302 })
289 }) 303 })
290 304
305 it('Should allow pod 6 to quit pod 1 & 2 and be friend with pod 3', function (done) {
306 this.timeout(30000)
307
308 series([
309 // Pod 3 should have 4 friends
310 function (next) {
311 getFriendsList(3, function (err, res) {
312 if (err) throw err
313
314 const friendsList = res.body.data
315 expect(friendsList).to.be.an('array')
316 expect(friendsList.length).to.equal(4)
317
318 next()
319 })
320 },
321 // Pod 1, 2, 6 should have 3 friends each
322 function (next) {
323 each([ 1, 2, 6 ], function (i, callback) {
324 getFriendsList(i, function (err, res) {
325 if (err) throw err
326
327 const friendsList = res.body.data
328 expect(friendsList).to.be.an('array')
329 expect(friendsList.length).to.equal(3)
330
331 callback()
332 })
333 }, next)
334 },
335 function (next) {
336 removeFriend(6, 1, next)
337 },
338 function (next) {
339 removeFriend(6, 2, next)
340 },
341 // Pod 6 should now have only 1 friend (and it should be Pod 3)
342 function (next) {
343 getFriendsList(6, function (err, res) {
344 if (err) throw err
345
346 const friendsList = res.body.data
347 expect(friendsList).to.be.an('array')
348 expect(friendsList.length).to.equal(1)
349 expect(friendsList[0].host).to.equal(servers[2].host)
350
351 next()
352 })
353 },
354 // Pod 1 & 2 should not know friend 6 anymore
355 function (next) {
356 each([ 1, 2 ], function (i, callback) {
357 getFriendsList(i, function (err, res) {
358 if (err) throw err
359
360 const friendsList = res.body.data
361 expect(friendsList).to.be.an('array')
362 expect(friendsList.length).to.equal(2)
363
364 callback()
365 })
366 }, next)
367 },
368 // Pod 3 should know every pod
369 function (next) {
370 getFriendsList(3, function (err, res) {
371 if (err) throw err
372
373 const friendsList = res.body.data
374 expect(friendsList).to.be.an('array')
375 expect(friendsList.length).to.equal(4)
376
377 next()
378 })
379 }
380 ], done)
381 })
382
291 after(function (done) { 383 after(function (done) {
292 servers.forEach(function (server) { 384 servers.forEach(function (server) {
293 process.kill(-server.app.pid) 385 process.kill(-server.app.pid)
diff --git a/server/tests/api/friends-basic.js b/server/tests/api/friends-basic.js
index 4c2043b39..5f1fdd255 100644
--- a/server/tests/api/friends-basic.js
+++ b/server/tests/api/friends-basic.js
@@ -198,6 +198,71 @@ describe('Test basic friends', function () {
198 }) 198 })
199 }) 199 })
200 200
201 it('Should allow pod 1 to quit only pod 2', function (done) {
202 series([
203 // Pod 1 quits pod 2
204 function (next) {
205 const server = servers[0]
206
207 // Get pod 2 id so we can query it
208 podsUtils.getFriendsList(server.url, function (err, res) {
209 if (err) throw err
210
211 const result = res.body.data
212 let pod = result.find((friend) => (friend.host === servers[1].host))
213
214 // Remove it from the friends list
215 podsUtils.quitOneFriend(server.url, server.accessToken, pod.id, next)
216 })
217 },
218
219 // Pod 1 should have only pod 3 in its friends list
220 function (next) {
221 podsUtils.getFriendsList(servers[0].url, function (err, res) {
222 if (err) throw err
223
224 const result = res.body.data
225 expect(result).to.be.an('array')
226 expect(result.length).to.equal(1)
227
228 const pod = result[0]
229 expect(pod.host).to.equal(servers[2].host)
230
231 next()
232 })
233 },
234
235 // Pod 2 should have only pod 3 in its friends list
236 function (next) {
237 podsUtils.getFriendsList(servers[1].url, function (err, res) {
238 if (err) throw err
239
240 const result = res.body.data
241 expect(result).to.be.an('array')
242 expect(result.length).to.equal(1)
243
244 const pod = result[0]
245 expect(pod.host).to.equal(servers[2].host)
246
247 next()
248 })
249 },
250
251 // Pod 3 should have both pods in its friends list
252 function (next) {
253 podsUtils.getFriendsList(servers[2].url, function (err, res) {
254 if (err) throw err
255
256 const result = res.body.data
257 expect(result).to.be.an('array')
258 expect(result.length).to.equal(2)
259
260 next()
261 })
262 }
263 ], done)
264 })
265
201 after(function (done) { 266 after(function (done) {
202 servers.forEach(function (server) { 267 servers.forEach(function (server) {
203 process.kill(-server.app.pid) 268 process.kill(-server.app.pid)
diff --git a/server/tests/utils/pods.js b/server/tests/utils/pods.js
index 25b97edec..cdabb64a6 100644
--- a/server/tests/utils/pods.js
+++ b/server/tests/utils/pods.js
@@ -5,7 +5,8 @@ const request = require('supertest')
5const podsUtils = { 5const podsUtils = {
6 getFriendsList, 6 getFriendsList,
7 makeFriends, 7 makeFriends,
8 quitFriends 8 quitFriends,
9 quitOneFriend
9} 10}
10 11
11// ---------------------- Export functions -------------------- 12// ---------------------- Export functions --------------------
@@ -90,6 +91,26 @@ function quitFriends (url, accessToken, expectedStatus, end) {
90 }) 91 })
91} 92}
92 93
94function quitOneFriend (url, accessToken, friendId, expectedStatus, end) {
95 if (!end) {
96 end = expectedStatus
97 expectedStatus = 204
98 }
99
100 const path = '/api/v1/pods/' + friendId
101
102 request(url)
103 .delete(path)
104 .set('Accept', 'application/json')
105 .set('Authorization', 'Bearer ' + accessToken)
106 .expect(expectedStatus)
107 .end(function (err, res) {
108 if (err) throw err
109
110 end()
111 })
112}
113
93// --------------------------------------------------------------------------- 114// ---------------------------------------------------------------------------
94 115
95module.exports = podsUtils 116module.exports = podsUtils