allow limiting video-comments rss feeds to an account or video channel
[oweals/peertube.git] / server / tests / api / notifications / user-notifications.ts
1 /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
2
3 import 'mocha'
4 import * as chai from 'chai'
5 import { v4 as uuidv4 } from 'uuid'
6 import {
7   cleanupTests,
8   updateMyUser,
9   updateVideo,
10   updateVideoChannel,
11   uploadRandomVideoOnServers,
12   wait
13 } from '../../../../shared/extra-utils'
14 import { ServerInfo } from '../../../../shared/extra-utils/index'
15 import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
16 import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
17 import {
18   CheckerBaseParams,
19   checkMyVideoImportIsFinished,
20   checkNewActorFollow,
21   checkNewVideoFromSubscription,
22   checkVideoIsPublished,
23   getLastNotification,
24   prepareNotificationsTest
25 } from '../../../../shared/extra-utils/users/user-notifications'
26 import { addUserSubscription, removeUserSubscription } from '../../../../shared/extra-utils/users/user-subscriptions'
27 import { getBadVideoUrl, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
28 import { UserNotification, UserNotificationType } from '../../../../shared/models/users'
29 import { VideoPrivacy } from '../../../../shared/models/videos'
30
31 const expect = chai.expect
32
33 describe('Test user notifications', function () {
34   let servers: ServerInfo[] = []
35   let userAccessToken: string
36   let userNotifications: UserNotification[] = []
37   let adminNotifications: UserNotification[] = []
38   let adminNotificationsServer2: UserNotification[] = []
39   let emails: object[] = []
40   let channelId: number
41
42   before(async function () {
43     this.timeout(120000)
44
45     const res = await prepareNotificationsTest(3)
46     emails = res.emails
47     userAccessToken = res.userAccessToken
48     servers = res.servers
49     userNotifications = res.userNotifications
50     adminNotifications = res.adminNotifications
51     adminNotificationsServer2 = res.adminNotificationsServer2
52     channelId = res.channelId
53   })
54
55   describe('New video from my subscription notification', function () {
56     let baseParams: CheckerBaseParams
57
58     before(() => {
59       baseParams = {
60         server: servers[0],
61         emails,
62         socketNotifications: userNotifications,
63         token: userAccessToken
64       }
65     })
66
67     it('Should not send notifications if the user does not follow the video publisher', async function () {
68       this.timeout(10000)
69
70       await uploadRandomVideoOnServers(servers, 1)
71
72       const notification = await getLastNotification(servers[0].url, userAccessToken)
73       expect(notification).to.be.undefined
74
75       expect(emails).to.have.lengthOf(0)
76       expect(userNotifications).to.have.lengthOf(0)
77     })
78
79     it('Should send a new video notification if the user follows the local video publisher', async function () {
80       this.timeout(15000)
81
82       await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:' + servers[0].port)
83       await waitJobs(servers)
84
85       const { name, uuid } = await uploadRandomVideoOnServers(servers, 1)
86       await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence')
87     })
88
89     it('Should send a new video notification from a remote account', async function () {
90       this.timeout(50000) // Server 2 has transcoding enabled
91
92       await addUserSubscription(servers[0].url, userAccessToken, 'root_channel@localhost:' + servers[1].port)
93       await waitJobs(servers)
94
95       const { name, uuid } = await uploadRandomVideoOnServers(servers, 2)
96       await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence')
97     })
98
99     it('Should send a new video notification on a scheduled publication', async function () {
100       this.timeout(20000)
101
102       // In 2 seconds
103       const updateAt = new Date(new Date().getTime() + 2000)
104
105       const data = {
106         privacy: VideoPrivacy.PRIVATE,
107         scheduleUpdate: {
108           updateAt: updateAt.toISOString(),
109           privacy: VideoPrivacy.PUBLIC
110         }
111       }
112       const { name, uuid } = await uploadRandomVideoOnServers(servers, 1, data)
113
114       await wait(6000)
115       await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence')
116     })
117
118     it('Should send a new video notification on a remote scheduled publication', async function () {
119       this.timeout(50000)
120
121       // In 2 seconds
122       const updateAt = new Date(new Date().getTime() + 2000)
123
124       const data = {
125         privacy: VideoPrivacy.PRIVATE,
126         scheduleUpdate: {
127           updateAt: updateAt.toISOString(),
128           privacy: VideoPrivacy.PUBLIC
129         }
130       }
131       const { name, uuid } = await uploadRandomVideoOnServers(servers, 2, data)
132       await waitJobs(servers)
133
134       await wait(6000)
135       await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence')
136     })
137
138     it('Should not send a notification before the video is published', async function () {
139       this.timeout(20000)
140
141       const updateAt = new Date(new Date().getTime() + 1000000)
142
143       const data = {
144         privacy: VideoPrivacy.PRIVATE,
145         scheduleUpdate: {
146           updateAt: updateAt.toISOString(),
147           privacy: VideoPrivacy.PUBLIC
148         }
149       }
150       const { name, uuid } = await uploadRandomVideoOnServers(servers, 1, data)
151
152       await wait(6000)
153       await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence')
154     })
155
156     it('Should send a new video notification when a video becomes public', async function () {
157       this.timeout(10000)
158
159       const data = { privacy: VideoPrivacy.PRIVATE }
160       const { name, uuid } = await uploadRandomVideoOnServers(servers, 1, data)
161
162       await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence')
163
164       await updateVideo(servers[0].url, servers[0].accessToken, uuid, { privacy: VideoPrivacy.PUBLIC })
165
166       await wait(500)
167       await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence')
168     })
169
170     it('Should send a new video notification when a remote video becomes public', async function () {
171       this.timeout(20000)
172
173       const data = { privacy: VideoPrivacy.PRIVATE }
174       const { name, uuid } = await uploadRandomVideoOnServers(servers, 2, data)
175
176       await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence')
177
178       await updateVideo(servers[1].url, servers[1].accessToken, uuid, { privacy: VideoPrivacy.PUBLIC })
179
180       await waitJobs(servers)
181       await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence')
182     })
183
184     it('Should not send a new video notification when a video becomes unlisted', async function () {
185       this.timeout(20000)
186
187       const data = { privacy: VideoPrivacy.PRIVATE }
188       const { name, uuid } = await uploadRandomVideoOnServers(servers, 1, data)
189
190       await updateVideo(servers[0].url, servers[0].accessToken, uuid, { privacy: VideoPrivacy.UNLISTED })
191
192       await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence')
193     })
194
195     it('Should not send a new video notification when a remote video becomes unlisted', async function () {
196       this.timeout(20000)
197
198       const data = { privacy: VideoPrivacy.PRIVATE }
199       const { name, uuid } = await uploadRandomVideoOnServers(servers, 2, data)
200
201       await updateVideo(servers[1].url, servers[1].accessToken, uuid, { privacy: VideoPrivacy.UNLISTED })
202
203       await waitJobs(servers)
204       await checkNewVideoFromSubscription(baseParams, name, uuid, 'absence')
205     })
206
207     it('Should send a new video notification after a video import', async function () {
208       this.timeout(100000)
209
210       const name = 'video import ' + uuidv4()
211
212       const attributes = {
213         name,
214         channelId,
215         privacy: VideoPrivacy.PUBLIC,
216         targetUrl: getYoutubeVideoUrl()
217       }
218       const res = await importVideo(servers[0].url, servers[0].accessToken, attributes)
219       const uuid = res.body.video.uuid
220
221       await waitJobs(servers)
222
223       await checkNewVideoFromSubscription(baseParams, name, uuid, 'presence')
224     })
225   })
226
227   describe('My video is published', function () {
228     let baseParams: CheckerBaseParams
229
230     before(() => {
231       baseParams = {
232         server: servers[1],
233         emails,
234         socketNotifications: adminNotificationsServer2,
235         token: servers[1].accessToken
236       }
237     })
238
239     it('Should not send a notification if transcoding is not enabled', async function () {
240       this.timeout(10000)
241
242       const { name, uuid } = await uploadRandomVideoOnServers(servers, 1)
243       await waitJobs(servers)
244
245       await checkVideoIsPublished(baseParams, name, uuid, 'absence')
246     })
247
248     it('Should not send a notification if the wait transcoding is false', async function () {
249       this.timeout(50000)
250
251       await uploadRandomVideoOnServers(servers, 2, { waitTranscoding: false })
252       await waitJobs(servers)
253
254       const notification = await getLastNotification(servers[0].url, userAccessToken)
255       if (notification) {
256         expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED)
257       }
258     })
259
260     it('Should send a notification even if the video is not transcoded in other resolutions', async function () {
261       this.timeout(50000)
262
263       const { name, uuid } = await uploadRandomVideoOnServers(servers, 2, { waitTranscoding: true, fixture: 'video_short_240p.mp4' })
264       await waitJobs(servers)
265
266       await checkVideoIsPublished(baseParams, name, uuid, 'presence')
267     })
268
269     it('Should send a notification with a transcoded video', async function () {
270       this.timeout(50000)
271
272       const { name, uuid } = await uploadRandomVideoOnServers(servers, 2, { waitTranscoding: true })
273       await waitJobs(servers)
274
275       await checkVideoIsPublished(baseParams, name, uuid, 'presence')
276     })
277
278     it('Should send a notification when an imported video is transcoded', async function () {
279       this.timeout(50000)
280
281       const name = 'video import ' + uuidv4()
282
283       const attributes = {
284         name,
285         channelId,
286         privacy: VideoPrivacy.PUBLIC,
287         targetUrl: getYoutubeVideoUrl(),
288         waitTranscoding: true
289       }
290       const res = await importVideo(servers[1].url, servers[1].accessToken, attributes)
291       const uuid = res.body.video.uuid
292
293       await waitJobs(servers)
294       await checkVideoIsPublished(baseParams, name, uuid, 'presence')
295     })
296
297     it('Should send a notification when the scheduled update has been proceeded', async function () {
298       this.timeout(70000)
299
300       // In 2 seconds
301       const updateAt = new Date(new Date().getTime() + 2000)
302
303       const data = {
304         privacy: VideoPrivacy.PRIVATE,
305         scheduleUpdate: {
306           updateAt: updateAt.toISOString(),
307           privacy: VideoPrivacy.PUBLIC
308         }
309       }
310       const { name, uuid } = await uploadRandomVideoOnServers(servers, 2, data)
311
312       await wait(6000)
313       await checkVideoIsPublished(baseParams, name, uuid, 'presence')
314     })
315
316     it('Should not send a notification before the video is published', async function () {
317       this.timeout(40000)
318
319       const updateAt = new Date(new Date().getTime() + 1000000)
320
321       const data = {
322         privacy: VideoPrivacy.PRIVATE,
323         scheduleUpdate: {
324           updateAt: updateAt.toISOString(),
325           privacy: VideoPrivacy.PUBLIC
326         }
327       }
328       const { name, uuid } = await uploadRandomVideoOnServers(servers, 2, data)
329
330       await wait(6000)
331       await checkVideoIsPublished(baseParams, name, uuid, 'absence')
332     })
333   })
334
335   describe('My video is imported', function () {
336     let baseParams: CheckerBaseParams
337
338     before(() => {
339       baseParams = {
340         server: servers[0],
341         emails,
342         socketNotifications: adminNotifications,
343         token: servers[0].accessToken
344       }
345     })
346
347     it('Should send a notification when the video import failed', async function () {
348       this.timeout(70000)
349
350       const name = 'video import ' + uuidv4()
351
352       const attributes = {
353         name,
354         channelId,
355         privacy: VideoPrivacy.PRIVATE,
356         targetUrl: getBadVideoUrl()
357       }
358       const res = await importVideo(servers[0].url, servers[0].accessToken, attributes)
359       const uuid = res.body.video.uuid
360
361       await waitJobs(servers)
362       await checkMyVideoImportIsFinished(baseParams, name, uuid, getBadVideoUrl(), false, 'presence')
363     })
364
365     it('Should send a notification when the video import succeeded', async function () {
366       this.timeout(70000)
367
368       const name = 'video import ' + uuidv4()
369
370       const attributes = {
371         name,
372         channelId,
373         privacy: VideoPrivacy.PRIVATE,
374         targetUrl: getYoutubeVideoUrl()
375       }
376       const res = await importVideo(servers[0].url, servers[0].accessToken, attributes)
377       const uuid = res.body.video.uuid
378
379       await waitJobs(servers)
380       await checkMyVideoImportIsFinished(baseParams, name, uuid, getYoutubeVideoUrl(), true, 'presence')
381     })
382   })
383
384   describe('New actor follow', function () {
385     let baseParams: CheckerBaseParams
386     const myChannelName = 'super channel name'
387     const myUserName = 'super user name'
388
389     before(async () => {
390       baseParams = {
391         server: servers[0],
392         emails,
393         socketNotifications: userNotifications,
394         token: userAccessToken
395       }
396
397       await updateMyUser({
398         url: servers[0].url,
399         accessToken: servers[0].accessToken,
400         displayName: 'super root name'
401       })
402
403       await updateMyUser({
404         url: servers[0].url,
405         accessToken: userAccessToken,
406         displayName: myUserName
407       })
408
409       await updateMyUser({
410         url: servers[1].url,
411         accessToken: servers[1].accessToken,
412         displayName: 'super root 2 name'
413       })
414
415       await updateVideoChannel(servers[0].url, userAccessToken, 'user_1_channel', { displayName: myChannelName })
416     })
417
418     it('Should notify when a local channel is following one of our channel', async function () {
419       this.timeout(10000)
420
421       await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
422       await waitJobs(servers)
423
424       await checkNewActorFollow(baseParams, 'channel', 'root', 'super root name', myChannelName, 'presence')
425
426       await removeUserSubscription(servers[0].url, servers[0].accessToken, 'user_1_channel@localhost:' + servers[0].port)
427     })
428
429     it('Should notify when a remote channel is following one of our channel', async function () {
430       this.timeout(10000)
431
432       await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
433       await waitJobs(servers)
434
435       await checkNewActorFollow(baseParams, 'channel', 'root', 'super root 2 name', myChannelName, 'presence')
436
437       await removeUserSubscription(servers[1].url, servers[1].accessToken, 'user_1_channel@localhost:' + servers[0].port)
438     })
439
440     // PeerTube does not support accout -> account follows
441     // it('Should notify when a local account is following one of our channel', async function () {
442     //   this.timeout(10000)
443     //
444     //   await addUserSubscription(servers[0].url, servers[0].accessToken, 'user_1@localhost:' + servers[0].port)
445     //
446     //   await waitJobs(servers)
447     //
448     //   await checkNewActorFollow(baseParams, 'account', 'root', 'super root name', myUserName, 'presence')
449     // })
450
451     // it('Should notify when a remote account is following one of our channel', async function () {
452     //   this.timeout(10000)
453     //
454     //   await addUserSubscription(servers[1].url, servers[1].accessToken, 'user_1@localhost:' + servers[0].port)
455     //
456     //   await waitJobs(servers)
457     //
458     //   await checkNewActorFollow(baseParams, 'account', 'root', 'super root 2 name', myUserName, 'presence')
459     // })
460   })
461
462   after(async function () {
463     MockSmtpServer.Instance.kill()
464
465     await cleanupTests(servers)
466   })
467 })