user-subscriptions.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
  2. import { expect } from 'chai'
  3. import { VideoPrivacy } from '@shared/models'
  4. import {
  5. cleanupTests,
  6. createMultipleServers,
  7. doubleFollow,
  8. PeerTubeServer,
  9. setAccessTokensToServers,
  10. setDefaultAccountAvatar,
  11. setDefaultChannelAvatar,
  12. SubscriptionsCommand,
  13. waitJobs
  14. } from '@shared/server-commands'
  15. describe('Test users subscriptions', function () {
  16. let servers: PeerTubeServer[] = []
  17. const users: { accessToken: string }[] = []
  18. let video3UUID: string
  19. let command: SubscriptionsCommand
  20. before(async function () {
  21. this.timeout(240000)
  22. servers = await createMultipleServers(3)
  23. // Get the access tokens
  24. await setAccessTokensToServers(servers)
  25. await setDefaultChannelAvatar(servers)
  26. await setDefaultAccountAvatar(servers)
  27. // Server 1 and server 2 follow each other
  28. await doubleFollow(servers[0], servers[1])
  29. for (const server of servers) {
  30. const user = { username: 'user' + server.serverNumber, password: 'password' }
  31. await server.users.create({ username: user.username, password: user.password })
  32. const accessToken = await server.login.getAccessToken(user)
  33. users.push({ accessToken })
  34. const videoName1 = 'video 1-' + server.serverNumber
  35. await server.videos.upload({ token: accessToken, attributes: { name: videoName1 } })
  36. const videoName2 = 'video 2-' + server.serverNumber
  37. await server.videos.upload({ token: accessToken, attributes: { name: videoName2 } })
  38. }
  39. await waitJobs(servers)
  40. command = servers[0].subscriptions
  41. })
  42. describe('Destinction between server videos and user videos', function () {
  43. it('Should display videos of server 2 on server 1', async function () {
  44. const { total } = await servers[0].videos.list()
  45. expect(total).to.equal(4)
  46. })
  47. it('User of server 1 should follow user of server 3 and root of server 1', async function () {
  48. this.timeout(60000)
  49. await command.add({ token: users[0].accessToken, targetUri: 'user3_channel@localhost:' + servers[2].port })
  50. await command.add({ token: users[0].accessToken, targetUri: 'root_channel@localhost:' + servers[0].port })
  51. await waitJobs(servers)
  52. const attributes = { name: 'video server 3 added after follow' }
  53. const { uuid } = await servers[2].videos.upload({ token: users[2].accessToken, attributes })
  54. video3UUID = uuid
  55. await waitJobs(servers)
  56. })
  57. it('Should not display videos of server 3 on server 1', async function () {
  58. const { total, data } = await servers[0].videos.list()
  59. expect(total).to.equal(4)
  60. for (const video of data) {
  61. expect(video.name).to.not.contain('1-3')
  62. expect(video.name).to.not.contain('2-3')
  63. expect(video.name).to.not.contain('video server 3 added after follow')
  64. }
  65. })
  66. })
  67. describe('Subscription endpoints', function () {
  68. it('Should list subscriptions', async function () {
  69. {
  70. const body = await command.list()
  71. expect(body.total).to.equal(0)
  72. expect(body.data).to.be.an('array')
  73. expect(body.data).to.have.lengthOf(0)
  74. }
  75. {
  76. const body = await command.list({ token: users[0].accessToken, sort: 'createdAt' })
  77. expect(body.total).to.equal(2)
  78. const subscriptions = body.data
  79. expect(subscriptions).to.be.an('array')
  80. expect(subscriptions).to.have.lengthOf(2)
  81. expect(subscriptions[0].name).to.equal('user3_channel')
  82. expect(subscriptions[1].name).to.equal('root_channel')
  83. }
  84. })
  85. it('Should get subscription', async function () {
  86. {
  87. const videoChannel = await command.get({ token: users[0].accessToken, uri: 'user3_channel@localhost:' + servers[2].port })
  88. expect(videoChannel.name).to.equal('user3_channel')
  89. expect(videoChannel.host).to.equal('localhost:' + servers[2].port)
  90. expect(videoChannel.displayName).to.equal('Main user3 channel')
  91. expect(videoChannel.followingCount).to.equal(0)
  92. expect(videoChannel.followersCount).to.equal(1)
  93. }
  94. {
  95. const videoChannel = await command.get({ token: users[0].accessToken, uri: 'root_channel@localhost:' + servers[0].port })
  96. expect(videoChannel.name).to.equal('root_channel')
  97. expect(videoChannel.host).to.equal('localhost:' + servers[0].port)
  98. expect(videoChannel.displayName).to.equal('Main root channel')
  99. expect(videoChannel.followingCount).to.equal(0)
  100. expect(videoChannel.followersCount).to.equal(1)
  101. }
  102. })
  103. it('Should return the existing subscriptions', async function () {
  104. const uris = [
  105. 'user3_channel@localhost:' + servers[2].port,
  106. 'root2_channel@localhost:' + servers[0].port,
  107. 'root_channel@localhost:' + servers[0].port,
  108. 'user3_channel@localhost:' + servers[0].port
  109. ]
  110. const body = await command.exist({ token: users[0].accessToken, uris })
  111. expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true
  112. expect(body['root2_channel@localhost:' + servers[0].port]).to.be.false
  113. expect(body['root_channel@localhost:' + servers[0].port]).to.be.true
  114. expect(body['user3_channel@localhost:' + servers[0].port]).to.be.false
  115. })
  116. it('Should search among subscriptions', async function () {
  117. {
  118. const body = await command.list({ token: users[0].accessToken, sort: '-createdAt', search: 'user3_channel' })
  119. expect(body.total).to.equal(1)
  120. expect(body.data).to.have.lengthOf(1)
  121. }
  122. {
  123. const body = await command.list({ token: users[0].accessToken, sort: '-createdAt', search: 'toto' })
  124. expect(body.total).to.equal(0)
  125. expect(body.data).to.have.lengthOf(0)
  126. }
  127. })
  128. })
  129. describe('Subscription videos', function () {
  130. it('Should list subscription videos', async function () {
  131. {
  132. const body = await command.listVideos()
  133. expect(body.total).to.equal(0)
  134. expect(body.data).to.be.an('array')
  135. expect(body.data).to.have.lengthOf(0)
  136. }
  137. {
  138. const body = await command.listVideos({ token: users[0].accessToken, sort: 'createdAt' })
  139. expect(body.total).to.equal(3)
  140. const videos = body.data
  141. expect(videos).to.be.an('array')
  142. expect(videos).to.have.lengthOf(3)
  143. expect(videos[0].name).to.equal('video 1-3')
  144. expect(videos[1].name).to.equal('video 2-3')
  145. expect(videos[2].name).to.equal('video server 3 added after follow')
  146. }
  147. })
  148. it('Should upload a video by root on server 1 and see it in the subscription videos', async function () {
  149. this.timeout(60000)
  150. const videoName = 'video server 1 added after follow'
  151. await servers[0].videos.upload({ attributes: { name: videoName } })
  152. await waitJobs(servers)
  153. {
  154. const body = await command.listVideos()
  155. expect(body.total).to.equal(0)
  156. expect(body.data).to.be.an('array')
  157. expect(body.data).to.have.lengthOf(0)
  158. }
  159. {
  160. const body = await command.listVideos({ token: users[0].accessToken, sort: 'createdAt' })
  161. expect(body.total).to.equal(4)
  162. const videos = body.data
  163. expect(videos).to.be.an('array')
  164. expect(videos).to.have.lengthOf(4)
  165. expect(videos[0].name).to.equal('video 1-3')
  166. expect(videos[1].name).to.equal('video 2-3')
  167. expect(videos[2].name).to.equal('video server 3 added after follow')
  168. expect(videos[3].name).to.equal('video server 1 added after follow')
  169. }
  170. {
  171. const { data, total } = await servers[0].videos.list()
  172. expect(total).to.equal(5)
  173. for (const video of data) {
  174. expect(video.name).to.not.contain('1-3')
  175. expect(video.name).to.not.contain('2-3')
  176. expect(video.name).to.not.contain('video server 3 added after follow')
  177. }
  178. }
  179. })
  180. it('Should have server 1 following server 3 and display server 3 videos', async function () {
  181. this.timeout(60000)
  182. await servers[0].follows.follow({ hosts: [ servers[2].url ] })
  183. await waitJobs(servers)
  184. const { data, total } = await servers[0].videos.list()
  185. expect(total).to.equal(8)
  186. const names = [ '1-3', '2-3', 'video server 3 added after follow' ]
  187. for (const name of names) {
  188. const video = data.find(v => v.name.includes(name))
  189. expect(video).to.not.be.undefined
  190. }
  191. })
  192. it('Should remove follow server 1 -> server 3 and hide server 3 videos', async function () {
  193. this.timeout(60000)
  194. await servers[0].follows.unfollow({ target: servers[2] })
  195. await waitJobs(servers)
  196. const { total, data } = await servers[0].videos.list()
  197. expect(total).to.equal(5)
  198. for (const video of data) {
  199. expect(video.name).to.not.contain('1-3')
  200. expect(video.name).to.not.contain('2-3')
  201. expect(video.name).to.not.contain('video server 3 added after follow')
  202. }
  203. })
  204. it('Should still list subscription videos', async function () {
  205. {
  206. const body = await command.listVideos()
  207. expect(body.total).to.equal(0)
  208. expect(body.data).to.be.an('array')
  209. expect(body.data).to.have.lengthOf(0)
  210. }
  211. {
  212. const body = await command.listVideos({ token: users[0].accessToken, sort: 'createdAt' })
  213. expect(body.total).to.equal(4)
  214. const videos = body.data
  215. expect(videos).to.be.an('array')
  216. expect(videos).to.have.lengthOf(4)
  217. expect(videos[0].name).to.equal('video 1-3')
  218. expect(videos[1].name).to.equal('video 2-3')
  219. expect(videos[2].name).to.equal('video server 3 added after follow')
  220. expect(videos[3].name).to.equal('video server 1 added after follow')
  221. }
  222. })
  223. })
  224. describe('Existing subscription video update', function () {
  225. it('Should update a video of server 3 and see the updated video on server 1', async function () {
  226. this.timeout(30000)
  227. await servers[2].videos.update({ id: video3UUID, attributes: { name: 'video server 3 added after follow updated' } })
  228. await waitJobs(servers)
  229. const body = await command.listVideos({ token: users[0].accessToken, sort: 'createdAt' })
  230. expect(body.data[2].name).to.equal('video server 3 added after follow updated')
  231. })
  232. })
  233. describe('Subscription removal', function () {
  234. it('Should remove user of server 3 subscription', async function () {
  235. this.timeout(30000)
  236. await command.remove({ token: users[0].accessToken, uri: 'user3_channel@localhost:' + servers[2].port })
  237. await waitJobs(servers)
  238. })
  239. it('Should not display its videos anymore', async function () {
  240. const body = await command.listVideos({ token: users[0].accessToken, sort: 'createdAt' })
  241. expect(body.total).to.equal(1)
  242. const videos = body.data
  243. expect(videos).to.be.an('array')
  244. expect(videos).to.have.lengthOf(1)
  245. expect(videos[0].name).to.equal('video server 1 added after follow')
  246. })
  247. it('Should remove the root subscription and not display the videos anymore', async function () {
  248. this.timeout(30000)
  249. await command.remove({ token: users[0].accessToken, uri: 'root_channel@localhost:' + servers[0].port })
  250. await waitJobs(servers)
  251. {
  252. const body = await command.list({ token: users[0].accessToken, sort: 'createdAt' })
  253. expect(body.total).to.equal(0)
  254. const videos = body.data
  255. expect(videos).to.be.an('array')
  256. expect(videos).to.have.lengthOf(0)
  257. }
  258. })
  259. it('Should correctly display public videos on server 1', async function () {
  260. const { total, data } = await servers[0].videos.list()
  261. expect(total).to.equal(5)
  262. for (const video of data) {
  263. expect(video.name).to.not.contain('1-3')
  264. expect(video.name).to.not.contain('2-3')
  265. expect(video.name).to.not.contain('video server 3 added after follow updated')
  266. }
  267. })
  268. })
  269. describe('Re-follow', function () {
  270. it('Should follow user of server 3 again', async function () {
  271. this.timeout(60000)
  272. await command.add({ token: users[0].accessToken, targetUri: 'user3_channel@localhost:' + servers[2].port })
  273. await waitJobs(servers)
  274. {
  275. const body = await command.listVideos({ token: users[0].accessToken, sort: 'createdAt' })
  276. expect(body.total).to.equal(3)
  277. const videos = body.data
  278. expect(videos).to.be.an('array')
  279. expect(videos).to.have.lengthOf(3)
  280. expect(videos[0].name).to.equal('video 1-3')
  281. expect(videos[1].name).to.equal('video 2-3')
  282. expect(videos[2].name).to.equal('video server 3 added after follow updated')
  283. }
  284. {
  285. const { total, data } = await servers[0].videos.list()
  286. expect(total).to.equal(5)
  287. for (const video of data) {
  288. expect(video.name).to.not.contain('1-3')
  289. expect(video.name).to.not.contain('2-3')
  290. expect(video.name).to.not.contain('video server 3 added after follow updated')
  291. }
  292. }
  293. })
  294. it('Should follow user channels of server 3 by root of server 3', async function () {
  295. this.timeout(60000)
  296. await servers[2].channels.create({ token: users[2].accessToken, attributes: { name: 'user3_channel2' } })
  297. await servers[2].subscriptions.add({ token: servers[2].accessToken, targetUri: 'user3_channel@localhost:' + servers[2].port })
  298. await servers[2].subscriptions.add({ token: servers[2].accessToken, targetUri: 'user3_channel2@localhost:' + servers[2].port })
  299. await waitJobs(servers)
  300. })
  301. })
  302. describe('Followers listing', function () {
  303. it('Should list user 3 followers', async function () {
  304. {
  305. const { total, data } = await servers[2].accounts.listFollowers({
  306. token: users[2].accessToken,
  307. accountName: 'user3',
  308. start: 0,
  309. count: 5,
  310. sort: 'createdAt'
  311. })
  312. expect(total).to.equal(3)
  313. expect(data).to.have.lengthOf(3)
  314. expect(data[0].following.host).to.equal(servers[2].host)
  315. expect(data[0].following.name).to.equal('user3_channel')
  316. expect(data[0].follower.host).to.equal(servers[0].host)
  317. expect(data[0].follower.name).to.equal('user1')
  318. expect(data[1].following.host).to.equal(servers[2].host)
  319. expect(data[1].following.name).to.equal('user3_channel')
  320. expect(data[1].follower.host).to.equal(servers[2].host)
  321. expect(data[1].follower.name).to.equal('root')
  322. expect(data[2].following.host).to.equal(servers[2].host)
  323. expect(data[2].following.name).to.equal('user3_channel2')
  324. expect(data[2].follower.host).to.equal(servers[2].host)
  325. expect(data[2].follower.name).to.equal('root')
  326. }
  327. {
  328. const { total, data } = await servers[2].accounts.listFollowers({
  329. token: users[2].accessToken,
  330. accountName: 'user3',
  331. start: 0,
  332. count: 1,
  333. sort: '-createdAt'
  334. })
  335. expect(total).to.equal(3)
  336. expect(data).to.have.lengthOf(1)
  337. expect(data[0].following.host).to.equal(servers[2].host)
  338. expect(data[0].following.name).to.equal('user3_channel2')
  339. expect(data[0].follower.host).to.equal(servers[2].host)
  340. expect(data[0].follower.name).to.equal('root')
  341. }
  342. {
  343. const { total, data } = await servers[2].accounts.listFollowers({
  344. token: users[2].accessToken,
  345. accountName: 'user3',
  346. start: 1,
  347. count: 1,
  348. sort: '-createdAt'
  349. })
  350. expect(total).to.equal(3)
  351. expect(data).to.have.lengthOf(1)
  352. expect(data[0].following.host).to.equal(servers[2].host)
  353. expect(data[0].following.name).to.equal('user3_channel')
  354. expect(data[0].follower.host).to.equal(servers[2].host)
  355. expect(data[0].follower.name).to.equal('root')
  356. }
  357. {
  358. const { total, data } = await servers[2].accounts.listFollowers({
  359. token: users[2].accessToken,
  360. accountName: 'user3',
  361. search: 'user1',
  362. sort: '-createdAt'
  363. })
  364. expect(total).to.equal(1)
  365. expect(data).to.have.lengthOf(1)
  366. expect(data[0].following.host).to.equal(servers[2].host)
  367. expect(data[0].following.name).to.equal('user3_channel')
  368. expect(data[0].follower.host).to.equal(servers[0].host)
  369. expect(data[0].follower.name).to.equal('user1')
  370. }
  371. })
  372. it('Should list user3_channel followers', async function () {
  373. {
  374. const { total, data } = await servers[2].channels.listFollowers({
  375. token: users[2].accessToken,
  376. channelName: 'user3_channel',
  377. start: 0,
  378. count: 5,
  379. sort: 'createdAt'
  380. })
  381. expect(total).to.equal(2)
  382. expect(data).to.have.lengthOf(2)
  383. expect(data[0].following.host).to.equal(servers[2].host)
  384. expect(data[0].following.name).to.equal('user3_channel')
  385. expect(data[0].follower.host).to.equal(servers[0].host)
  386. expect(data[0].follower.name).to.equal('user1')
  387. expect(data[1].following.host).to.equal(servers[2].host)
  388. expect(data[1].following.name).to.equal('user3_channel')
  389. expect(data[1].follower.host).to.equal(servers[2].host)
  390. expect(data[1].follower.name).to.equal('root')
  391. }
  392. {
  393. const { total, data } = await servers[2].channels.listFollowers({
  394. token: users[2].accessToken,
  395. channelName: 'user3_channel',
  396. start: 0,
  397. count: 1,
  398. sort: '-createdAt'
  399. })
  400. expect(total).to.equal(2)
  401. expect(data).to.have.lengthOf(1)
  402. expect(data[0].following.host).to.equal(servers[2].host)
  403. expect(data[0].following.name).to.equal('user3_channel')
  404. expect(data[0].follower.host).to.equal(servers[2].host)
  405. expect(data[0].follower.name).to.equal('root')
  406. }
  407. {
  408. const { total, data } = await servers[2].channels.listFollowers({
  409. token: users[2].accessToken,
  410. channelName: 'user3_channel',
  411. start: 1,
  412. count: 1,
  413. sort: '-createdAt'
  414. })
  415. expect(total).to.equal(2)
  416. expect(data).to.have.lengthOf(1)
  417. expect(data[0].following.host).to.equal(servers[2].host)
  418. expect(data[0].following.name).to.equal('user3_channel')
  419. expect(data[0].follower.host).to.equal(servers[0].host)
  420. expect(data[0].follower.name).to.equal('user1')
  421. }
  422. {
  423. const { total, data } = await servers[2].channels.listFollowers({
  424. token: users[2].accessToken,
  425. channelName: 'user3_channel',
  426. search: 'user1',
  427. sort: '-createdAt'
  428. })
  429. expect(total).to.equal(1)
  430. expect(data).to.have.lengthOf(1)
  431. expect(data[0].following.host).to.equal(servers[2].host)
  432. expect(data[0].following.name).to.equal('user3_channel')
  433. expect(data[0].follower.host).to.equal(servers[0].host)
  434. expect(data[0].follower.name).to.equal('user1')
  435. }
  436. })
  437. })
  438. describe('Subscription videos privacy', function () {
  439. it('Should update video as internal and not see from remote server', async function () {
  440. this.timeout(30000)
  441. await servers[2].videos.update({ id: video3UUID, attributes: { name: 'internal', privacy: VideoPrivacy.INTERNAL } })
  442. await waitJobs(servers)
  443. {
  444. const { data } = await command.listVideos({ token: users[0].accessToken })
  445. expect(data.find(v => v.name === 'internal')).to.not.exist
  446. }
  447. })
  448. it('Should see internal from local user', async function () {
  449. const { data } = await servers[2].subscriptions.listVideos({ token: servers[2].accessToken })
  450. expect(data.find(v => v.name === 'internal')).to.exist
  451. })
  452. it('Should update video as private and not see from anyone server', async function () {
  453. this.timeout(30000)
  454. await servers[2].videos.update({ id: video3UUID, attributes: { name: 'private', privacy: VideoPrivacy.PRIVATE } })
  455. await waitJobs(servers)
  456. {
  457. const { data } = await command.listVideos({ token: users[0].accessToken })
  458. expect(data.find(v => v.name === 'private')).to.not.exist
  459. }
  460. {
  461. const { data } = await servers[2].subscriptions.listVideos({ token: servers[2].accessToken })
  462. expect(data.find(v => v.name === 'private')).to.not.exist
  463. }
  464. })
  465. })
  466. after(async function () {
  467. await cleanupTests(servers)
  468. })
  469. })