Fix express validator
[oweals/peertube.git] / server / tests / api / check-params / video-playlists.ts
1 /* tslint:disable:no-unused-expression */
2
3 import 'mocha'
4 import {
5   addVideoInPlaylist,
6   cleanupTests,
7   createVideoPlaylist,
8   deleteVideoPlaylist,
9   flushAndRunServer,
10   generateUserAccessToken,
11   getAccountPlaylistsListWithToken,
12   getVideoPlaylist,
13   immutableAssign,
14   makeGetRequest,
15   removeVideoFromPlaylist,
16   reorderVideosPlaylist,
17   ServerInfo,
18   setAccessTokensToServers,
19   setDefaultVideoChannel,
20   updateVideoPlaylist,
21   updateVideoPlaylistElement,
22   uploadVideoAndGetId
23 } from '../../../../shared/extra-utils'
24 import {
25   checkBadCountPagination,
26   checkBadSortPagination,
27   checkBadStartPagination
28 } from '../../../../shared/extra-utils/requests/check-api-params'
29 import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
30 import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
31
32 describe('Test video playlists API validator', function () {
33   let server: ServerInfo
34   let userAccessToken: string
35   let playlistUUID: string
36   let privatePlaylistUUID: string
37   let watchLaterPlaylistId: number
38   let videoId: number
39   let videoId2: number
40
41   // ---------------------------------------------------------------
42
43   before(async function () {
44     this.timeout(30000)
45
46     server = await flushAndRunServer(1)
47
48     await setAccessTokensToServers([ server ])
49     await setDefaultVideoChannel([ server ])
50
51     userAccessToken = await generateUserAccessToken(server, 'user1')
52     videoId = (await uploadVideoAndGetId({ server, videoName: 'video 1' })).id
53     videoId2 = (await uploadVideoAndGetId({ server, videoName: 'video 2' })).id
54
55     {
56       const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root',0, 5, VideoPlaylistType.WATCH_LATER)
57       watchLaterPlaylistId = res.body.data[0].id
58     }
59
60     {
61       const res = await createVideoPlaylist({
62         url: server.url,
63         token: server.accessToken,
64         playlistAttrs: {
65           displayName: 'super playlist',
66           privacy: VideoPlaylistPrivacy.PUBLIC,
67           videoChannelId: server.videoChannel.id
68         }
69       })
70       playlistUUID = res.body.videoPlaylist.uuid
71     }
72
73     {
74       const res = await createVideoPlaylist({
75         url: server.url,
76         token: server.accessToken,
77         playlistAttrs: {
78           displayName: 'private',
79           privacy: VideoPlaylistPrivacy.PRIVATE
80         }
81       })
82       privatePlaylistUUID = res.body.videoPlaylist.uuid
83     }
84   })
85
86   describe('When listing playlists', function () {
87     const globalPath = '/api/v1/video-playlists'
88     const accountPath = '/api/v1/accounts/root/video-playlists'
89     const videoChannelPath = '/api/v1/video-channels/root_channel/video-playlists'
90
91     it('Should fail with a bad start pagination', async function () {
92       await checkBadStartPagination(server.url, globalPath, server.accessToken)
93       await checkBadStartPagination(server.url, accountPath, server.accessToken)
94       await checkBadStartPagination(server.url, videoChannelPath, server.accessToken)
95     })
96
97     it('Should fail with a bad count pagination', async function () {
98       await checkBadCountPagination(server.url, globalPath, server.accessToken)
99       await checkBadCountPagination(server.url, accountPath, server.accessToken)
100       await checkBadCountPagination(server.url, videoChannelPath, server.accessToken)
101     })
102
103     it('Should fail with an incorrect sort', async function () {
104       await checkBadSortPagination(server.url, globalPath, server.accessToken)
105       await checkBadSortPagination(server.url, accountPath, server.accessToken)
106       await checkBadSortPagination(server.url, videoChannelPath, server.accessToken)
107     })
108
109     it('Should fail with a bad playlist type', async function () {
110       await makeGetRequest({ url: server.url, path: globalPath, query: { playlistType: 3 } })
111       await makeGetRequest({ url: server.url, path: accountPath, query: { playlistType: 3 } })
112       await makeGetRequest({ url: server.url, path: videoChannelPath, query: { playlistType: 3 } })
113     })
114
115     it('Should fail with a bad account parameter', async function () {
116       const accountPath = '/api/v1/accounts/root2/video-playlists'
117
118       await makeGetRequest({ url: server.url, path: accountPath, statusCodeExpected: 404, token: server.accessToken })
119     })
120
121     it('Should fail with a bad video channel parameter', async function () {
122       const accountPath = '/api/v1/video-channels/bad_channel/video-playlists'
123
124       await makeGetRequest({ url: server.url, path: accountPath, statusCodeExpected: 404, token: server.accessToken })
125     })
126
127     it('Should success with the correct parameters', async function () {
128       await makeGetRequest({ url: server.url, path: globalPath, statusCodeExpected: 200, token: server.accessToken })
129       await makeGetRequest({ url: server.url, path: accountPath, statusCodeExpected: 200, token: server.accessToken })
130       await makeGetRequest({ url: server.url, path: videoChannelPath, statusCodeExpected: 200, token: server.accessToken })
131     })
132   })
133
134   describe('When listing videos of a playlist', function () {
135     const path = '/api/v1/video-playlists'
136
137     it('Should fail with a bad start pagination', async function () {
138       await checkBadStartPagination(server.url, path, server.accessToken)
139     })
140
141     it('Should fail with a bad count pagination', async function () {
142       await checkBadCountPagination(server.url, path, server.accessToken)
143     })
144
145     it('Should fail with a bad filter', async function () {
146       await checkBadSortPagination(server.url, path, server.accessToken)
147     })
148   })
149
150   describe('When getting a video playlist', function () {
151     it('Should fail with a bad id or uuid', async function () {
152       await getVideoPlaylist(server.url, 'toto', 400)
153     })
154
155     it('Should fail with an unknown playlist', async function () {
156       await getVideoPlaylist(server.url, 42, 404)
157     })
158
159     it('Should fail to get an unlisted playlist with the number id', async function () {
160       const res = await createVideoPlaylist({
161         url: server.url,
162         token: server.accessToken,
163         playlistAttrs: {
164           displayName: 'super playlist',
165           privacy: VideoPlaylistPrivacy.UNLISTED
166         }
167       })
168       const playlist = res.body.videoPlaylist
169
170       await getVideoPlaylist(server.url, playlist.id, 404)
171       await getVideoPlaylist(server.url, playlist.uuid, 200)
172     })
173
174     it('Should succeed with the correct params', async function () {
175       await getVideoPlaylist(server.url, playlistUUID, 200)
176     })
177   })
178
179   describe('When creating/updating a video playlist', function () {
180     const getBase = (playlistAttrs: any = {}, wrapper: any = {}) => {
181       return Object.assign({
182         expectedStatus: 400,
183         url: server.url,
184         token: server.accessToken,
185         playlistAttrs: Object.assign({
186           displayName: 'display name',
187           privacy: VideoPlaylistPrivacy.UNLISTED,
188           thumbnailfile: 'thumbnail.jpg',
189           videoChannelId: server.videoChannel.id
190         }, playlistAttrs)
191       }, wrapper)
192     }
193     const getUpdate = (params: any, playlistId: number | string) => {
194       return immutableAssign(params, { playlistId: playlistId })
195     }
196
197     it('Should fail with an unauthenticated user', async function () {
198       const params = getBase({}, { token: null, expectedStatus: 401 })
199
200       await createVideoPlaylist(params)
201       await updateVideoPlaylist(getUpdate(params, playlistUUID))
202     })
203
204     it('Should fail without displayName', async function () {
205       const params = getBase({ displayName: undefined })
206
207       await createVideoPlaylist(params)
208     })
209
210     it('Should fail with an incorrect display name', async function () {
211       const params = getBase({ displayName: 's'.repeat(300) })
212
213       await createVideoPlaylist(params)
214       await updateVideoPlaylist(getUpdate(params, playlistUUID))
215     })
216
217     it('Should fail with an incorrect description', async function () {
218       const params = getBase({ description: 't' })
219
220       await createVideoPlaylist(params)
221       await updateVideoPlaylist(getUpdate(params, playlistUUID))
222     })
223
224     it('Should fail with an incorrect privacy', async function () {
225       const params = getBase({ privacy: 45 })
226
227       await createVideoPlaylist(params)
228       await updateVideoPlaylist(getUpdate(params, playlistUUID))
229     })
230
231     it('Should fail with an unknown video channel id', async function () {
232       const params = getBase({ videoChannelId: 42 }, { expectedStatus: 404 })
233
234       await createVideoPlaylist(params)
235       await updateVideoPlaylist(getUpdate(params, playlistUUID))
236     })
237
238     it('Should fail with an incorrect thumbnail file', async function () {
239       const params = getBase({ thumbnailfile: 'avatar.png' })
240
241       await createVideoPlaylist(params)
242       await updateVideoPlaylist(getUpdate(params, playlistUUID))
243     })
244
245     it('Should fail to set "public" a playlist not assigned to a channel', async function () {
246       const params = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: undefined })
247       const params2 = getBase({ privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: 'null' })
248       const params3 = getBase({ privacy: undefined, videoChannelId: 'null' })
249
250       await createVideoPlaylist(params)
251       await createVideoPlaylist(params2)
252       await updateVideoPlaylist(getUpdate(params, privatePlaylistUUID))
253       await updateVideoPlaylist(getUpdate(params2, playlistUUID))
254       await updateVideoPlaylist(getUpdate(params3, playlistUUID))
255     })
256
257     it('Should fail with an unknown playlist to update', async function () {
258       await updateVideoPlaylist(getUpdate(
259         getBase({}, { expectedStatus: 404 }),
260         42
261       ))
262     })
263
264     it('Should fail to update a playlist of another user', async function () {
265       await updateVideoPlaylist(getUpdate(
266         getBase({}, { token: userAccessToken, expectedStatus: 403 }),
267         playlistUUID
268       ))
269     })
270
271     it('Should fail to update the watch later playlist', async function () {
272       await updateVideoPlaylist(getUpdate(
273         getBase({}, { expectedStatus: 400 }),
274         watchLaterPlaylistId
275       ))
276     })
277
278     it('Should succeed with the correct params', async function () {
279       {
280         const params = getBase({}, { expectedStatus: 200 })
281         await createVideoPlaylist(params)
282       }
283
284       {
285         const params = getBase({}, { expectedStatus: 204 })
286         await updateVideoPlaylist(getUpdate(params, playlistUUID))
287       }
288     })
289   })
290
291   describe('When adding an element in a playlist', function () {
292     const getBase = (elementAttrs: any = {}, wrapper: any = {}) => {
293       return Object.assign({
294         expectedStatus: 400,
295         url: server.url,
296         token: server.accessToken,
297         playlistId: playlistUUID,
298         elementAttrs: Object.assign({
299           videoId: videoId,
300           startTimestamp: 2,
301           stopTimestamp: 3
302         }, elementAttrs)
303       }, wrapper)
304     }
305
306     it('Should fail with an unauthenticated user', async function () {
307       const params = getBase({}, { token: null, expectedStatus: 401 })
308       await addVideoInPlaylist(params)
309     })
310
311     it('Should fail with the playlist of another user', async function () {
312       const params = getBase({}, { token: userAccessToken, expectedStatus: 403 })
313       await addVideoInPlaylist(params)
314     })
315
316     it('Should fail with an unknown or incorrect playlist id', async function () {
317       {
318         const params = getBase({}, { playlistId: 'toto' })
319         await addVideoInPlaylist(params)
320       }
321
322       {
323         const params = getBase({}, { playlistId: 42, expectedStatus: 404 })
324         await addVideoInPlaylist(params)
325       }
326     })
327
328     it('Should fail with an unknown or incorrect video id', async function () {
329       const params = getBase({ videoId: 42 }, { expectedStatus: 404 })
330       await addVideoInPlaylist(params)
331     })
332
333     it('Should fail with a bad start/stop timestamp', async function () {
334       {
335         const params = getBase({ startTimestamp: -42 })
336         await addVideoInPlaylist(params)
337       }
338
339       {
340         const params = getBase({ stopTimestamp: 'toto' as any })
341         await addVideoInPlaylist(params)
342       }
343     })
344
345     it('Succeed with the correct params', async function () {
346       const params = getBase({}, { expectedStatus: 200 })
347       await addVideoInPlaylist(params)
348     })
349
350     it('Should fail if the video was already added in the playlist', async function () {
351       const params = getBase({}, { expectedStatus: 409 })
352       await addVideoInPlaylist(params)
353     })
354   })
355
356   describe('When updating an element in a playlist', function () {
357     const getBase = (elementAttrs: any = {}, wrapper: any = {}) => {
358       return Object.assign({
359         url: server.url,
360         token: server.accessToken,
361         elementAttrs: Object.assign({
362           startTimestamp: 1,
363           stopTimestamp: 2
364         }, elementAttrs),
365         videoId: videoId,
366         playlistId: playlistUUID,
367         expectedStatus: 400
368       }, wrapper)
369     }
370
371     it('Should fail with an unauthenticated user', async function () {
372       const params = getBase({}, { token: null, expectedStatus: 401 })
373       await updateVideoPlaylistElement(params)
374     })
375
376     it('Should fail with the playlist of another user', async function () {
377       const params = getBase({}, { token: userAccessToken, expectedStatus: 403 })
378       await updateVideoPlaylistElement(params)
379     })
380
381     it('Should fail with an unknown or incorrect playlist id', async function () {
382       {
383         const params = getBase({}, { playlistId: 'toto' })
384         await updateVideoPlaylistElement(params)
385       }
386
387       {
388         const params = getBase({}, { playlistId: 42, expectedStatus: 404 })
389         await updateVideoPlaylistElement(params)
390       }
391     })
392
393     it('Should fail with an unknown or incorrect video id', async function () {
394       {
395         const params = getBase({}, { videoId: 'toto' })
396         await updateVideoPlaylistElement(params)
397       }
398
399       {
400         const params = getBase({}, { videoId: 42, expectedStatus: 404 })
401         await updateVideoPlaylistElement(params)
402       }
403     })
404
405     it('Should fail with a bad start/stop timestamp', async function () {
406       {
407         const params = getBase({ startTimestamp: 'toto' as any })
408         await updateVideoPlaylistElement(params)
409       }
410
411       {
412         const params = getBase({ stopTimestamp: -42 })
413         await updateVideoPlaylistElement(params)
414       }
415     })
416
417     it('Should fail with an unknown element', async function () {
418       const params = getBase({}, { videoId: videoId2, expectedStatus: 404 })
419       await updateVideoPlaylistElement(params)
420     })
421
422     it('Succeed with the correct params', async function () {
423       const params = getBase({}, { expectedStatus: 204 })
424       await updateVideoPlaylistElement(params)
425     })
426   })
427
428   describe('When reordering elements of a playlist', function () {
429     let videoId3: number
430     let videoId4: number
431
432     const getBase = (elementAttrs: any = {}, wrapper: any = {}) => {
433       return Object.assign({
434         url: server.url,
435         token: server.accessToken,
436         playlistId: playlistUUID,
437         elementAttrs: Object.assign({
438           startPosition: 1,
439           insertAfterPosition: 2,
440           reorderLength: 3
441         }, elementAttrs),
442         expectedStatus: 400
443       }, wrapper)
444     }
445
446     before(async function () {
447       videoId3 = (await uploadVideoAndGetId({ server, videoName: 'video 3' })).id
448       videoId4 = (await uploadVideoAndGetId({ server, videoName: 'video 4' })).id
449
450       for (let id of [ videoId3, videoId4 ]) {
451         await addVideoInPlaylist({
452           url: server.url,
453           token: server.accessToken,
454           playlistId: playlistUUID,
455           elementAttrs: { videoId: id }
456         })
457       }
458     })
459
460     it('Should fail with an unauthenticated user', async function () {
461       const params = getBase({}, { token: null, expectedStatus: 401 })
462       await reorderVideosPlaylist(params)
463     })
464
465     it('Should fail with the playlist of another user', async function () {
466       const params = getBase({}, { token: userAccessToken, expectedStatus: 403 })
467       await reorderVideosPlaylist(params)
468     })
469
470     it('Should fail with an invalid playlist', async function () {
471       {
472         const params = getBase({}, { playlistId: 'toto' })
473         await reorderVideosPlaylist(params)
474       }
475
476       {
477         const params = getBase({}, {  playlistId: 42, expectedStatus: 404 })
478         await reorderVideosPlaylist(params)
479       }
480     })
481
482     it('Should fail with an invalid start position', async function () {
483       {
484         const params = getBase({ startPosition: -1 })
485         await reorderVideosPlaylist(params)
486       }
487
488       {
489         const params = getBase({ startPosition: 'toto' as any })
490         await reorderVideosPlaylist(params)
491       }
492
493       {
494         const params = getBase({ startPosition: 42 })
495         await reorderVideosPlaylist(params)
496       }
497     })
498
499     it('Should fail with an invalid insert after position', async function () {
500       {
501         const params = getBase({ insertAfterPosition: 'toto' as any })
502         await reorderVideosPlaylist(params)
503       }
504
505       {
506         const params = getBase({ insertAfterPosition: -2 })
507         await reorderVideosPlaylist(params)
508       }
509
510       {
511         const params = getBase({ insertAfterPosition: 42 })
512         await reorderVideosPlaylist(params)
513       }
514     })
515
516     it('Should fail with an invalid reorder length', async function () {
517       {
518         const params = getBase({ reorderLength: 'toto' as any })
519         await reorderVideosPlaylist(params)
520       }
521
522       {
523         const params = getBase({ reorderLength: -2 })
524         await reorderVideosPlaylist(params)
525       }
526
527       {
528         const params = getBase({ reorderLength: 42 })
529         await reorderVideosPlaylist(params)
530       }
531     })
532
533     it('Succeed with the correct params', async function () {
534       const params = getBase({}, { expectedStatus: 204 })
535       await reorderVideosPlaylist(params)
536     })
537   })
538
539   describe('When checking exists in playlist endpoint', function () {
540     const path = '/api/v1/users/me/video-playlists/videos-exist'
541
542     it('Should fail with an unauthenticated user', async function () {
543       await makeGetRequest({
544         url: server.url,
545         path,
546         query: { videoIds: [ 1, 2 ] },
547         statusCodeExpected: 401
548       })
549     })
550
551     it('Should fail with invalid video ids', async function () {
552       await makeGetRequest({
553         url: server.url,
554         token: server.accessToken,
555         path,
556         query: { videoIds: 'toto' }
557       })
558
559       await makeGetRequest({
560         url: server.url,
561         token: server.accessToken,
562         path,
563         query: { videoIds: [ 'toto' ] }
564       })
565
566       await makeGetRequest({
567         url: server.url,
568         token: server.accessToken,
569         path,
570         query: { videoIds: [ 1, 'toto' ] }
571       })
572     })
573
574     it('Should succeed with the correct params', async function () {
575       await makeGetRequest({
576         url: server.url,
577         token: server.accessToken,
578         path,
579         query: { videoIds: [ 1, 2 ] },
580         statusCodeExpected: 200
581       })
582     })
583   })
584
585   describe('When deleting an element in a playlist', function () {
586     const getBase = (wrapper: any = {}) => {
587       return Object.assign({
588         url: server.url,
589         token: server.accessToken,
590         videoId: videoId,
591         playlistId: playlistUUID,
592         expectedStatus: 400
593       }, wrapper)
594     }
595
596     it('Should fail with an unauthenticated user', async function () {
597       const params = getBase({ token: null, expectedStatus: 401 })
598       await removeVideoFromPlaylist(params)
599     })
600
601     it('Should fail with the playlist of another user', async function () {
602       const params = getBase({ token: userAccessToken, expectedStatus: 403 })
603       await removeVideoFromPlaylist(params)
604     })
605
606     it('Should fail with an unknown or incorrect playlist id', async function () {
607       {
608         const params = getBase({ playlistId: 'toto' })
609         await removeVideoFromPlaylist(params)
610       }
611
612       {
613         const params = getBase({ playlistId: 42, expectedStatus: 404 })
614         await removeVideoFromPlaylist(params)
615       }
616     })
617
618     it('Should fail with an unknown or incorrect video id', async function () {
619       {
620         const params = getBase({ videoId: 'toto' })
621         await removeVideoFromPlaylist(params)
622       }
623
624       {
625         const params = getBase({ videoId: 42, expectedStatus: 404 })
626         await removeVideoFromPlaylist(params)
627       }
628     })
629
630     it('Should fail with an unknown element', async function () {
631       const params = getBase({ videoId: videoId2, expectedStatus: 404 })
632       await removeVideoFromPlaylist(params)
633     })
634
635     it('Succeed with the correct params', async function () {
636       const params = getBase({ expectedStatus: 204 })
637       await removeVideoFromPlaylist(params)
638     })
639   })
640
641   describe('When deleting a playlist', function () {
642     it('Should fail with an unknown playlist', async function () {
643       await deleteVideoPlaylist(server.url, server.accessToken, 42, 404)
644     })
645
646     it('Should fail with a playlist of another user', async function () {
647       await deleteVideoPlaylist(server.url, userAccessToken, playlistUUID, 403)
648     })
649
650     it('Should fail with the watch later playlist', async function () {
651       await deleteVideoPlaylist(server.url, server.accessToken, watchLaterPlaylistId, 400)
652     })
653
654     it('Should succeed with the correct params', async function () {
655       await deleteVideoPlaylist(server.url, server.accessToken, playlistUUID)
656     })
657   })
658
659   after(async function () {
660     await cleanupTests([ server ])
661   })
662 })