e1655e85ba6773cd51f30f8a52f29b324721b2d3
[oweals/peertube.git] / server / tests / api / check-params / users.ts
1 /* tslint:disable:no-unused-expression */
2
3 import { omit } from 'lodash'
4 import 'mocha'
5 import { join } from 'path'
6 import { UserRole, VideoImport, VideoImportState } from '../../../../shared'
7
8 import {
9   createUser, flushTests, getMyUserInformation, getMyUserVideoRating, getUsersList, immutableAssign, killallServers, makeGetRequest,
10   makePostBodyRequest, makeUploadRequest, makePutBodyRequest, registerUser, removeUser, runServer, ServerInfo, setAccessTokensToServers,
11   updateUser, uploadVideo, userLogin
12 } from '../../utils'
13 import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '../../utils/requests/check-api-params'
14 import { getMagnetURI, getMyVideoImports, getYoutubeVideoUrl, importVideo } from '../../utils/videos/video-imports'
15 import { VideoPrivacy } from '../../../../shared/models/videos'
16 import { waitJobs } from '../../utils/server/jobs'
17 import { expect } from 'chai'
18
19 describe('Test users API validators', function () {
20   const path = '/api/v1/users/'
21   let userId: number
22   let rootId: number
23   let videoId: number
24   let server: ServerInfo
25   let serverWithRegistrationDisabled: ServerInfo
26   let userAccessToken = ''
27   let channelId: number
28   const user = {
29     username: 'user1',
30     password: 'my super password'
31   }
32
33   // ---------------------------------------------------------------
34
35   before(async function () {
36     this.timeout(30000)
37
38     await flushTests()
39
40     server = await runServer(1)
41     serverWithRegistrationDisabled = await runServer(2)
42
43     await setAccessTokensToServers([ server ])
44
45     const videoQuota = 42000000
46     await createUser(server.url, server.accessToken, user.username, user.password, videoQuota)
47     userAccessToken = await userLogin(server, user)
48
49     {
50       const res = await getMyUserInformation(server.url, server.accessToken)
51       channelId = res.body.videoChannels[ 0 ].id
52     }
53
54     {
55       const res = await uploadVideo(server.url, server.accessToken, {})
56       videoId = res.body.video.id
57     }
58   })
59
60   describe('When listing users', function () {
61     it('Should fail with a bad start pagination', async function () {
62       await checkBadStartPagination(server.url, path, server.accessToken)
63     })
64
65     it('Should fail with a bad count pagination', async function () {
66       await checkBadCountPagination(server.url, path, server.accessToken)
67     })
68
69     it('Should fail with an incorrect sort', async function () {
70       await checkBadSortPagination(server.url, path, server.accessToken)
71     })
72
73     it('Should fail with a non authenticated user', async function () {
74       await makeGetRequest({
75         url: server.url,
76         path,
77         statusCodeExpected: 401
78       })
79     })
80
81     it('Should fail with a non admin user', async function () {
82       await makeGetRequest({
83         url: server.url,
84         path,
85         token: userAccessToken,
86         statusCodeExpected: 403
87       })
88     })
89   })
90
91   describe('When adding a new user', function () {
92     const baseCorrectParams = {
93       username: 'user2',
94       email: 'test@example.com',
95       password: 'my super password',
96       videoQuota: -1,
97       role: UserRole.USER
98     }
99
100     it('Should fail with a too small username', async function () {
101       const fields = immutableAssign(baseCorrectParams, { username: 'fi' })
102
103       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
104     })
105
106     it('Should fail with a too long username', async function () {
107       const fields = immutableAssign(baseCorrectParams, { username: 'my_super_username_which_is_very_long' })
108
109       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
110     })
111
112     it('Should fail with a not lowercase username', async function () {
113       const fields = immutableAssign(baseCorrectParams, { username: 'Toto' })
114
115       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
116     })
117
118     it('Should fail with an incorrect username', async function () {
119       const fields = immutableAssign(baseCorrectParams, { username: 'my username' })
120
121       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
122     })
123
124     it('Should fail with a missing email', async function () {
125       const fields = omit(baseCorrectParams, 'email')
126
127       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
128     })
129
130     it('Should fail with an invalid email', async function () {
131       const fields = immutableAssign(baseCorrectParams, { email: 'test_example.com' })
132
133       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
134     })
135
136     it('Should fail with a too small password', async function () {
137       const fields = immutableAssign(baseCorrectParams, { password: 'bla' })
138
139       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
140     })
141
142     it('Should fail with a too long password', async function () {
143       const fields = immutableAssign(baseCorrectParams, { password: 'super'.repeat(61) })
144
145       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
146     })
147
148     it('Should fail with an non authenticated user', async function () {
149       await makePostBodyRequest({
150         url: server.url,
151         path,
152         token: 'super token',
153         fields: baseCorrectParams,
154         statusCodeExpected: 401
155       })
156     })
157
158     it('Should fail if we add a user with the same username', async function () {
159       const fields = immutableAssign(baseCorrectParams, { username: 'user1' })
160
161       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 409 })
162     })
163
164     it('Should fail if we add a user with the same email', async function () {
165       const fields = immutableAssign(baseCorrectParams, { email: 'user1@example.com' })
166
167       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 409 })
168     })
169
170     it('Should fail without a videoQuota', async function () {
171       const fields = omit(baseCorrectParams, 'videoQuota')
172
173       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
174     })
175
176     it('Should fail with an invalid videoQuota', async function () {
177       const fields = immutableAssign(baseCorrectParams, { videoQuota: -5 })
178
179       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
180     })
181
182     it('Should fail without a user role', async function () {
183       const fields = omit(baseCorrectParams, 'role')
184
185       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
186     })
187
188     it('Should fail with an invalid user role', async function () {
189       const fields = immutableAssign(baseCorrectParams, { role: 88989 })
190
191       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
192     })
193
194     it('Should fail with a "peertube" username', async function () {
195       const fields = immutableAssign(baseCorrectParams, { username: 'peertube' })
196
197       await makePostBodyRequest({
198         url: server.url,
199         path,
200         token: server.accessToken,
201         fields,
202         statusCodeExpected: 409
203       })
204     })
205
206     it('Should succeed with the correct params', async function () {
207       await makePostBodyRequest({
208         url: server.url,
209         path,
210         token: server.accessToken,
211         fields: baseCorrectParams,
212         statusCodeExpected: 200
213       })
214     })
215
216     it('Should fail with a non admin user', async function () {
217       const user = {
218         username: 'user1',
219         password: 'my super password'
220       }
221       userAccessToken = await userLogin(server, user)
222
223       const fields = {
224         username: 'user3',
225         email: 'test@example.com',
226         password: 'my super password',
227         videoQuota: 42000000
228       }
229       await makePostBodyRequest({ url: server.url, path, token: userAccessToken, fields, statusCodeExpected: 403 })
230     })
231   })
232
233   describe('When updating my account', function () {
234     it('Should fail with an invalid email attribute', async function () {
235       const fields = {
236         email: 'blabla'
237       }
238
239       await makePutBodyRequest({ url: server.url, path: path + 'me', token: server.accessToken, fields })
240     })
241
242     it('Should fail with a too small password', async function () {
243       const fields = {
244         password: 'bla'
245       }
246
247       await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
248     })
249
250     it('Should fail with a too long password', async function () {
251       const fields = {
252         password: 'super'.repeat(61)
253       }
254
255       await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
256     })
257
258     it('Should fail with an invalid NSFW policy attribute', async function () {
259       const fields = {
260         nsfwPolicy: 'hello'
261       }
262
263       await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
264     })
265
266     it('Should fail with an invalid autoPlayVideo attribute', async function () {
267       const fields = {
268         autoPlayVideo: -1
269       }
270
271       await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
272     })
273
274     it('Should fail with an non authenticated user', async function () {
275       const fields = {
276         password: 'my super password'
277       }
278
279       await makePutBodyRequest({ url: server.url, path: path + 'me', token: 'super token', fields, statusCodeExpected: 401 })
280     })
281
282     it('Should fail with a too long description', async function () {
283       const fields = {
284         description: 'super'.repeat(60)
285       }
286
287       await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
288     })
289
290     it('Should succeed with the correct params', async function () {
291       const fields = {
292         password: 'my super password',
293         nsfwPolicy: 'blur',
294         autoPlayVideo: false,
295         email: 'super_email@example.com'
296       }
297
298       await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields, statusCodeExpected: 204 })
299     })
300   })
301
302   describe('When updating my avatar', function () {
303     it('Should fail without an incorrect input file', async function () {
304       const fields = {}
305       const attaches = {
306         'avatarfile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4')
307       }
308       await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
309     })
310
311     it('Should fail with a big file', async function () {
312       const fields = {}
313       const attaches = {
314         'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
315       }
316       await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
317     })
318
319     it('Should fail with an unauthenticated user', async function () {
320       const fields = {}
321       const attaches = {
322         'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
323       }
324       await makeUploadRequest({
325         url: server.url,
326         path: path + '/me/avatar/pick',
327         fields,
328         attaches,
329         statusCodeExpected: 401
330       })
331     })
332
333     it('Should succeed with the correct params', async function () {
334       const fields = {}
335       const attaches = {
336         'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
337       }
338       await makeUploadRequest({
339         url: server.url,
340         path: path + '/me/avatar/pick',
341         token: server.accessToken,
342         fields,
343         attaches,
344         statusCodeExpected: 200
345       })
346     })
347   })
348
349   describe('When getting a user', function () {
350     before(async function () {
351       const res = await getUsersList(server.url, server.accessToken)
352
353       userId = res.body.data[1].id
354     })
355
356     it('Should fail with an non authenticated user', async function () {
357       await makeGetRequest({ url: server.url, path: path + userId, token: 'super token', statusCodeExpected: 401 })
358     })
359
360     it('Should fail with a non admin user', async function () {
361       await makeGetRequest({ url: server.url, path, token: userAccessToken, statusCodeExpected: 403 })
362     })
363
364     it('Should succeed with the correct params', async function () {
365       await makeGetRequest({ url: server.url, path: path + userId, token: server.accessToken, statusCodeExpected: 200 })
366     })
367   })
368
369   describe('When updating a user', function () {
370
371     before(async function () {
372       const res = await getUsersList(server.url, server.accessToken)
373
374       userId = res.body.data[1].id
375       rootId = res.body.data[2].id
376     })
377
378     it('Should fail with an invalid email attribute', async function () {
379       const fields = {
380         email: 'blabla'
381       }
382
383       await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
384     })
385
386     it('Should fail with an invalid videoQuota attribute', async function () {
387       const fields = {
388         videoQuota: -90
389       }
390
391       await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
392     })
393
394     it('Should fail with an invalid user role attribute', async function () {
395       const fields = {
396         role: 54878
397       }
398
399       await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
400     })
401
402     it('Should fail with an non authenticated user', async function () {
403       const fields = {
404         videoQuota: 42
405       }
406
407       await makePutBodyRequest({ url: server.url, path: path + userId, token: 'super token', fields, statusCodeExpected: 401 })
408     })
409
410     it('Should fail when updating root role', async function () {
411       const fields = {
412         role: UserRole.MODERATOR
413       }
414
415       await makePutBodyRequest({ url: server.url, path: path + rootId, token: server.accessToken, fields })
416     })
417
418     it('Should succeed with the correct params', async function () {
419       const fields = {
420         email: 'email@example.com',
421         videoQuota: 42,
422         role: UserRole.MODERATOR
423       }
424
425       await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields, statusCodeExpected: 204 })
426       userAccessToken = await userLogin(server, user)
427     })
428   })
429
430   describe('When getting my information', function () {
431     it('Should fail with a non authenticated user', async function () {
432       await getMyUserInformation(server.url, 'fake_token', 401)
433     })
434
435     it('Should success with the correct parameters', async function () {
436       await getMyUserInformation(server.url, userAccessToken)
437     })
438   })
439
440   describe('When getting my video rating', function () {
441     it('Should fail with a non authenticated user', async function () {
442       await getMyUserVideoRating(server.url, 'fake_token', videoId, 401)
443     })
444
445     it('Should fail with an incorrect video uuid', async function () {
446       await getMyUserVideoRating(server.url, server.accessToken, 'blabla', 400)
447     })
448
449     it('Should fail with an unknown video', async function () {
450       await getMyUserVideoRating(server.url, server.accessToken, '4da6fde3-88f7-4d16-b119-108df5630b06', 404)
451     })
452
453     it('Should succeed with the correct parameters', async function () {
454       await getMyUserVideoRating(server.url, server.accessToken, videoId)
455     })
456   })
457
458   describe('When removing an user', function () {
459     it('Should fail with an incorrect id', async function () {
460       await removeUser(server.url, 'blabla', server.accessToken, 400)
461     })
462
463     it('Should fail with the root user', async function () {
464       await removeUser(server.url, rootId, server.accessToken, 400)
465     })
466
467     it('Should return 404 with a non existing id', async function () {
468       await removeUser(server.url, 4545454, server.accessToken, 404)
469     })
470   })
471
472   describe('When register a new user', function () {
473     const registrationPath = path + '/register'
474     const baseCorrectParams = {
475       username: 'user3',
476       email: 'test3@example.com',
477       password: 'my super password'
478     }
479
480     it('Should fail with a too small username', async function () {
481       const fields = immutableAssign(baseCorrectParams, { username: 'ji' })
482
483       await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
484     })
485
486     it('Should fail with a too long username', async function () {
487       const fields = immutableAssign(baseCorrectParams, { username: 'my_super_username_which_is_very_long' })
488
489       await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
490     })
491
492     it('Should fail with an incorrect username', async function () {
493       const fields = immutableAssign(baseCorrectParams, { username: 'my username' })
494
495       await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
496     })
497
498     it('Should fail with a missing email', async function () {
499       const fields = omit(baseCorrectParams, 'email')
500
501       await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
502     })
503
504     it('Should fail with an invalid email', async function () {
505       const fields = immutableAssign(baseCorrectParams, { email: 'test_example.com' })
506
507       await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
508     })
509
510     it('Should fail with a too small password', async function () {
511       const fields = immutableAssign(baseCorrectParams, { password: 'bla' })
512
513       await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
514     })
515
516     it('Should fail with a too long password', async function () {
517       const fields = immutableAssign(baseCorrectParams, { password: 'super'.repeat(61) })
518
519       await makePostBodyRequest({ url: server.url, path: registrationPath, token: server.accessToken, fields })
520     })
521
522     it('Should fail if we register a user with the same username', async function () {
523       const fields = immutableAssign(baseCorrectParams, { username: 'root' })
524
525       await makePostBodyRequest({
526         url: server.url,
527         path: registrationPath,
528         token: server.accessToken,
529         fields,
530         statusCodeExpected: 409
531       })
532     })
533
534     it('Should fail with a "peertube" username', async function () {
535       const fields = immutableAssign(baseCorrectParams, { username: 'peertube' })
536
537       await makePostBodyRequest({
538         url: server.url,
539         path: registrationPath,
540         token: server.accessToken,
541         fields,
542         statusCodeExpected: 409
543       })
544     })
545
546     it('Should fail if we register a user with the same email', async function () {
547       const fields = immutableAssign(baseCorrectParams, { email: 'admin1@example.com' })
548
549       await makePostBodyRequest({
550         url: server.url,
551         path: registrationPath,
552         token: server.accessToken,
553         fields,
554         statusCodeExpected: 409
555       })
556     })
557
558     it('Should succeed with the correct params', async function () {
559       await makePostBodyRequest({
560         url: server.url,
561         path: registrationPath,
562         token: server.accessToken,
563         fields: baseCorrectParams,
564         statusCodeExpected: 204
565       })
566     })
567
568     it('Should fail on a server with registration disabled', async function () {
569       const fields = {
570         username: 'user4',
571         email: 'test4@example.com',
572         password: 'my super password 4'
573       }
574
575       await makePostBodyRequest({
576         url: serverWithRegistrationDisabled.url,
577         path: registrationPath,
578         token: serverWithRegistrationDisabled.accessToken,
579         fields,
580         statusCodeExpected: 403
581       })
582     })
583   })
584
585   describe('When registering multiple users on a server with users limit', function () {
586     it('Should fail when after 3 registrations', async function () {
587       await registerUser(server.url, 'user42', 'super password', 403)
588     })
589   })
590
591   describe('When having a video quota', function () {
592     it('Should fail with a user having too many video', async function () {
593       await updateUser({
594         url: server.url,
595         userId: rootId,
596         accessToken: server.accessToken,
597         videoQuota: 42
598       })
599
600       await uploadVideo(server.url, server.accessToken, {}, 403)
601     })
602
603     it('Should fail with a registered user having too many video', async function () {
604       this.timeout(30000)
605
606       const user = {
607         username: 'user3',
608         password: 'my super password'
609       }
610       userAccessToken = await userLogin(server, user)
611
612       const videoAttributes = { fixture: 'video_short2.webm' }
613       await uploadVideo(server.url, userAccessToken, videoAttributes)
614       await uploadVideo(server.url, userAccessToken, videoAttributes)
615       await uploadVideo(server.url, userAccessToken, videoAttributes)
616       await uploadVideo(server.url, userAccessToken, videoAttributes)
617       await uploadVideo(server.url, userAccessToken, videoAttributes)
618       await uploadVideo(server.url, userAccessToken, videoAttributes, 403)
619     })
620
621     it('Should fail to import with HTTP/Torrent/magnet', async function () {
622       this.timeout(30000)
623
624       const baseAttributes = {
625         channelId: 1,
626         privacy: VideoPrivacy.PUBLIC
627       }
628       await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { targetUrl: getYoutubeVideoUrl() }))
629       await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { magnetUri: getMagnetURI() }))
630       await importVideo(server.url, server.accessToken, immutableAssign(baseAttributes, { torrentfile: '60fps_small-240p.torrent' }))
631
632       await waitJobs([ server ])
633
634       const res = await getMyVideoImports(server.url, server.accessToken)
635
636       expect(res.body.total).to.equal(3)
637       const videoImports: VideoImport[] = res.body.data
638       expect(videoImports).to.have.lengthOf(3)
639
640       for (const videoImport of videoImports) {
641         expect(videoImport.state.id).to.equal(VideoImportState.FAILED)
642         expect(videoImport.error).not.to.be.undefined
643         expect(videoImport.error).to.contain('user video quota is exceeded')
644       }
645     })
646   })
647
648   describe('When asking a password reset', function () {
649     const path = '/api/v1/users/ask-reset-password'
650
651     it('Should fail with a missing email', async function () {
652       const fields = {}
653
654       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
655     })
656
657     it('Should fail with an invalid email', async function () {
658       const fields = { email: 'hello' }
659
660       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields })
661     })
662
663     it('Should success with the correct params', async function () {
664       const fields = { email: 'admin@example.com' }
665
666       await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields, statusCodeExpected: 204 })
667     })
668   })
669
670   after(async function () {
671     killallServers([ server, serverWithRegistrationDisabled ])
672
673     // Keep the logs if the test failed
674     if (this['ok']) {
675       await flushTests()
676     }
677   })
678 })