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