video-channel-syncs.ts 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import { checkBadCountPagination, checkBadSortPagination, checkBadStartPagination } from '@tests/shared/checks.js'
  2. import { FIXTURE_URLS } from '@tests/shared/fixture-urls.js'
  3. import { HttpStatusCode, VideoChannelSyncCreate } from '@peertube/peertube-models'
  4. import {
  5. ChannelSyncsCommand,
  6. createSingleServer,
  7. makePostBodyRequest,
  8. PeerTubeServer,
  9. setAccessTokensToServers,
  10. setDefaultVideoChannel
  11. } from '@peertube/peertube-server-commands'
  12. describe('Test video channel sync API validator', () => {
  13. const path = '/api/v1/video-channel-syncs'
  14. let server: PeerTubeServer
  15. let command: ChannelSyncsCommand
  16. let rootChannelId: number
  17. let rootChannelSyncId: number
  18. const userInfo = {
  19. accessToken: '',
  20. username: 'user1',
  21. id: -1,
  22. channelId: -1,
  23. syncId: -1
  24. }
  25. async function withChannelSyncDisabled<T> (callback: () => Promise<T>): Promise<void> {
  26. try {
  27. await server.config.disableChannelSync()
  28. await callback()
  29. } finally {
  30. await server.config.enableChannelSync()
  31. }
  32. }
  33. async function withMaxSyncsPerUser<T> (maxSync: number, callback: () => Promise<T>): Promise<void> {
  34. const origConfig = await server.config.getCustomConfig()
  35. await server.config.updateExistingConfig({
  36. newConfig: {
  37. import: {
  38. videoChannelSynchronization: {
  39. maxPerUser: maxSync
  40. }
  41. }
  42. }
  43. })
  44. try {
  45. await callback()
  46. } finally {
  47. await server.config.updateCustomConfig({ newCustomConfig: origConfig })
  48. }
  49. }
  50. before(async function () {
  51. this.timeout(30_000)
  52. server = await createSingleServer(1)
  53. await setAccessTokensToServers([ server ])
  54. await setDefaultVideoChannel([ server ])
  55. command = server.channelSyncs
  56. rootChannelId = server.store.channel.id
  57. {
  58. userInfo.accessToken = await server.users.generateUserAndToken(userInfo.username)
  59. const { videoChannels, id: userId } = await server.users.getMyInfo({ token: userInfo.accessToken })
  60. userInfo.id = userId
  61. userInfo.channelId = videoChannels[0].id
  62. }
  63. await server.config.enableChannelSync()
  64. })
  65. describe('When creating a sync', function () {
  66. let baseCorrectParams: VideoChannelSyncCreate
  67. before(function () {
  68. baseCorrectParams = {
  69. externalChannelUrl: FIXTURE_URLS.youtubeChannel,
  70. videoChannelId: rootChannelId
  71. }
  72. })
  73. it('Should fail when sync is disabled', async function () {
  74. await withChannelSyncDisabled(async () => {
  75. await command.create({
  76. token: server.accessToken,
  77. attributes: baseCorrectParams,
  78. expectedStatus: HttpStatusCode.FORBIDDEN_403
  79. })
  80. })
  81. })
  82. it('Should fail with nothing', async function () {
  83. const fields = {}
  84. await makePostBodyRequest({
  85. url: server.url,
  86. path,
  87. token: server.accessToken,
  88. fields,
  89. expectedStatus: HttpStatusCode.BAD_REQUEST_400
  90. })
  91. })
  92. it('Should fail with no authentication', async function () {
  93. await command.create({
  94. token: null,
  95. attributes: baseCorrectParams,
  96. expectedStatus: HttpStatusCode.UNAUTHORIZED_401
  97. })
  98. })
  99. it('Should fail without a target url', async function () {
  100. const attributes: VideoChannelSyncCreate = {
  101. ...baseCorrectParams,
  102. externalChannelUrl: null
  103. }
  104. await command.create({
  105. token: server.accessToken,
  106. attributes,
  107. expectedStatus: HttpStatusCode.BAD_REQUEST_400
  108. })
  109. })
  110. it('Should fail without a channelId', async function () {
  111. const attributes: VideoChannelSyncCreate = {
  112. ...baseCorrectParams,
  113. videoChannelId: null
  114. }
  115. await command.create({
  116. token: server.accessToken,
  117. attributes,
  118. expectedStatus: HttpStatusCode.BAD_REQUEST_400
  119. })
  120. })
  121. it('Should fail with a channelId referring nothing', async function () {
  122. const attributes: VideoChannelSyncCreate = {
  123. ...baseCorrectParams,
  124. videoChannelId: 42
  125. }
  126. await command.create({
  127. token: server.accessToken,
  128. attributes,
  129. expectedStatus: HttpStatusCode.NOT_FOUND_404
  130. })
  131. })
  132. it('Should fail to create a sync when the user does not own the channel', async function () {
  133. await command.create({
  134. token: userInfo.accessToken,
  135. attributes: baseCorrectParams,
  136. expectedStatus: HttpStatusCode.FORBIDDEN_403
  137. })
  138. })
  139. it('Should succeed to create a sync with root and for another user\'s channel', async function () {
  140. const { videoChannelSync } = await command.create({
  141. token: server.accessToken,
  142. attributes: {
  143. ...baseCorrectParams,
  144. videoChannelId: userInfo.channelId
  145. },
  146. expectedStatus: HttpStatusCode.OK_200
  147. })
  148. userInfo.syncId = videoChannelSync.id
  149. })
  150. it('Should succeed with the correct parameters', async function () {
  151. const { videoChannelSync } = await command.create({
  152. token: server.accessToken,
  153. attributes: baseCorrectParams,
  154. expectedStatus: HttpStatusCode.OK_200
  155. })
  156. rootChannelSyncId = videoChannelSync.id
  157. })
  158. it('Should fail when the user exceeds allowed number of synchronizations', async function () {
  159. await withMaxSyncsPerUser(1, async () => {
  160. await command.create({
  161. token: server.accessToken,
  162. attributes: {
  163. ...baseCorrectParams,
  164. videoChannelId: userInfo.channelId
  165. },
  166. expectedStatus: HttpStatusCode.BAD_REQUEST_400
  167. })
  168. })
  169. })
  170. })
  171. describe('When listing my channel syncs', function () {
  172. const myPath = '/api/v1/accounts/root/video-channel-syncs'
  173. it('Should fail with a bad start pagination', async function () {
  174. await checkBadStartPagination(server.url, myPath, server.accessToken)
  175. })
  176. it('Should fail with a bad count pagination', async function () {
  177. await checkBadCountPagination(server.url, myPath, server.accessToken)
  178. })
  179. it('Should fail with an incorrect sort', async function () {
  180. await checkBadSortPagination(server.url, myPath, server.accessToken)
  181. })
  182. it('Should succeed with the correct parameters', async function () {
  183. await command.listByAccount({
  184. accountName: 'root',
  185. token: server.accessToken,
  186. expectedStatus: HttpStatusCode.OK_200
  187. })
  188. })
  189. it('Should fail with no authentication', async function () {
  190. await command.listByAccount({
  191. accountName: 'root',
  192. token: null,
  193. expectedStatus: HttpStatusCode.UNAUTHORIZED_401
  194. })
  195. })
  196. it('Should fail when a simple user lists another user\'s synchronizations', async function () {
  197. await command.listByAccount({
  198. accountName: 'root',
  199. token: userInfo.accessToken,
  200. expectedStatus: HttpStatusCode.FORBIDDEN_403
  201. })
  202. })
  203. it('Should succeed when root lists another user\'s synchronizations', async function () {
  204. await command.listByAccount({
  205. accountName: userInfo.username,
  206. token: server.accessToken,
  207. expectedStatus: HttpStatusCode.OK_200
  208. })
  209. })
  210. it('Should succeed even with synchronization disabled', async function () {
  211. await withChannelSyncDisabled(async function () {
  212. await command.listByAccount({
  213. accountName: 'root',
  214. token: server.accessToken,
  215. expectedStatus: HttpStatusCode.OK_200
  216. })
  217. })
  218. })
  219. })
  220. describe('When triggering deletion', function () {
  221. it('should fail with no authentication', async function () {
  222. await command.delete({
  223. channelSyncId: userInfo.syncId,
  224. token: null,
  225. expectedStatus: HttpStatusCode.UNAUTHORIZED_401
  226. })
  227. })
  228. it('Should fail when channelSyncId does not refer to any sync', async function () {
  229. await command.delete({
  230. channelSyncId: 42,
  231. token: server.accessToken,
  232. expectedStatus: HttpStatusCode.NOT_FOUND_404
  233. })
  234. })
  235. it('Should fail when sync is not owned by the user', async function () {
  236. await command.delete({
  237. channelSyncId: rootChannelSyncId,
  238. token: userInfo.accessToken,
  239. expectedStatus: HttpStatusCode.FORBIDDEN_403
  240. })
  241. })
  242. it('Should succeed when root delete a sync they do not own', async function () {
  243. await command.delete({
  244. channelSyncId: userInfo.syncId,
  245. token: server.accessToken,
  246. expectedStatus: HttpStatusCode.NO_CONTENT_204
  247. })
  248. })
  249. it('should succeed when user delete a sync they own', async function () {
  250. const { videoChannelSync } = await command.create({
  251. attributes: {
  252. externalChannelUrl: FIXTURE_URLS.youtubeChannel,
  253. videoChannelId: userInfo.channelId
  254. },
  255. token: server.accessToken,
  256. expectedStatus: HttpStatusCode.OK_200
  257. })
  258. await command.delete({
  259. channelSyncId: videoChannelSync.id,
  260. token: server.accessToken,
  261. expectedStatus: HttpStatusCode.NO_CONTENT_204
  262. })
  263. })
  264. it('Should succeed even when synchronization is disabled', async function () {
  265. await withChannelSyncDisabled(async function () {
  266. await command.delete({
  267. channelSyncId: rootChannelSyncId,
  268. token: server.accessToken,
  269. expectedStatus: HttpStatusCode.NO_CONTENT_204
  270. })
  271. })
  272. })
  273. })
  274. after(async function () {
  275. await server?.kill()
  276. })
  277. })