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