video-playlists.ts 22 KB

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