]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - shared/utils/users/user-notifications.ts
b85d5d2f19f6dc629960babef51171c0f91407ea
[github/Chocobozzz/PeerTube.git] / shared / utils / users / user-notifications.ts
1 /* tslint:disable:no-unused-expression */
2
3 import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
4 import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users'
5 import { ServerInfo } from '..'
6 import { expect } from 'chai'
7 import { inspect } from 'util'
8
9 function updateMyNotificationSettings (url: string, token: string, settings: UserNotificationSetting, statusCodeExpected = 204) {
10 const path = '/api/v1/users/me/notification-settings'
11
12 return makePutBodyRequest({
13 url,
14 path,
15 token,
16 fields: settings,
17 statusCodeExpected
18 })
19 }
20
21 function getUserNotifications (
22 url: string,
23 token: string,
24 start: number,
25 count: number,
26 unread?: boolean,
27 sort = '-createdAt',
28 statusCodeExpected = 200
29 ) {
30 const path = '/api/v1/users/me/notifications'
31
32 return makeGetRequest({
33 url,
34 path,
35 token,
36 query: {
37 start,
38 count,
39 sort,
40 unread
41 },
42 statusCodeExpected
43 })
44 }
45
46 function markAsReadNotifications (url: string, token: string, ids: number[], statusCodeExpected = 204) {
47 const path = '/api/v1/users/me/notifications/read'
48
49 return makePostBodyRequest({
50 url,
51 path,
52 token,
53 fields: { ids },
54 statusCodeExpected
55 })
56 }
57 function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) {
58 const path = '/api/v1/users/me/notifications/read-all'
59
60 return makePostBodyRequest({
61 url,
62 path,
63 token,
64 statusCodeExpected
65 })
66 }
67
68 async function getLastNotification (serverUrl: string, accessToken: string) {
69 const res = await getUserNotifications(serverUrl, accessToken, 0, 1, undefined, '-createdAt')
70
71 if (res.body.total === 0) return undefined
72
73 return res.body.data[0] as UserNotification
74 }
75
76 type CheckerBaseParams = {
77 server: ServerInfo
78 emails: object[]
79 socketNotifications: UserNotification[]
80 token: string,
81 check?: { web: boolean, mail: boolean }
82 }
83
84 type CheckerType = 'presence' | 'absence'
85
86 async function checkNotification (
87 base: CheckerBaseParams,
88 notificationChecker: (notification: UserNotification, type: CheckerType) => void,
89 emailNotificationFinder: (email: object) => boolean,
90 checkType: CheckerType
91 ) {
92 const check = base.check || { web: true, mail: true }
93
94 if (check.web) {
95 const notification = await getLastNotification(base.server.url, base.token)
96
97 if (notification || checkType !== 'absence') {
98 notificationChecker(notification, checkType)
99 }
100
101 const socketNotification = base.socketNotifications.find(n => {
102 try {
103 notificationChecker(n, 'presence')
104 return true
105 } catch {
106 return false
107 }
108 })
109
110 if (checkType === 'presence') {
111 const obj = inspect(base.socketNotifications, { depth: 5 })
112 expect(socketNotification, 'The socket notification is absent. ' + obj).to.not.be.undefined
113 } else {
114 const obj = inspect(socketNotification, { depth: 5 })
115 expect(socketNotification, 'The socket notification is present. ' + obj).to.be.undefined
116 }
117 }
118
119 if (check.mail) {
120 // Last email
121 const email = base.emails
122 .slice()
123 .reverse()
124 .find(e => emailNotificationFinder(e))
125
126 if (checkType === 'presence') {
127 expect(email, 'The email is absent. ' + inspect(base.emails)).to.not.be.undefined
128 } else {
129 expect(email, 'The email is present. ' + inspect(email)).to.be.undefined
130 }
131 }
132 }
133
134 function checkVideo (video: any, videoName?: string, videoUUID?: string) {
135 expect(video.name).to.be.a('string')
136 expect(video.name).to.not.be.empty
137 if (videoName) expect(video.name).to.equal(videoName)
138
139 expect(video.uuid).to.be.a('string')
140 expect(video.uuid).to.not.be.empty
141 if (videoUUID) expect(video.uuid).to.equal(videoUUID)
142
143 expect(video.id).to.be.a('number')
144 }
145
146 function checkActor (actor: any) {
147 expect(actor.displayName).to.be.a('string')
148 expect(actor.displayName).to.not.be.empty
149 expect(actor.host).to.not.be.undefined
150 }
151
152 function checkComment (comment: any, commentId: number, threadId: number) {
153 expect(comment.id).to.equal(commentId)
154 expect(comment.threadId).to.equal(threadId)
155 }
156
157 async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
158 const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION
159
160 function notificationChecker (notification: UserNotification, type: CheckerType) {
161 if (type === 'presence') {
162 expect(notification).to.not.be.undefined
163 expect(notification.type).to.equal(notificationType)
164
165 checkVideo(notification.video, videoName, videoUUID)
166 checkActor(notification.video.channel)
167 } else {
168 expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
169 }
170 }
171
172 function emailFinder (email: object) {
173 return email[ 'text' ].indexOf(videoUUID) !== -1
174 }
175
176 await checkNotification(base, notificationChecker, emailFinder, type)
177 }
178
179 async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
180 const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED
181
182 function notificationChecker (notification: UserNotification, type: CheckerType) {
183 if (type === 'presence') {
184 expect(notification).to.not.be.undefined
185 expect(notification.type).to.equal(notificationType)
186
187 checkVideo(notification.video, videoName, videoUUID)
188 checkActor(notification.video.channel)
189 } else {
190 expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
191 }
192 }
193
194 function emailFinder (email: object) {
195 const text: string = email[ 'text' ]
196 return text.includes(videoUUID) && text.includes('Your video')
197 }
198
199 await checkNotification(base, notificationChecker, emailFinder, type)
200 }
201
202 async function checkMyVideoImportIsFinished (
203 base: CheckerBaseParams,
204 videoName: string,
205 videoUUID: string,
206 url: string,
207 success: boolean,
208 type: CheckerType
209 ) {
210 const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR
211
212 function notificationChecker (notification: UserNotification, type: CheckerType) {
213 if (type === 'presence') {
214 expect(notification).to.not.be.undefined
215 expect(notification.type).to.equal(notificationType)
216
217 expect(notification.videoImport.targetUrl).to.equal(url)
218
219 if (success) checkVideo(notification.videoImport.video, videoName, videoUUID)
220 } else {
221 expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url)
222 }
223 }
224
225 function emailFinder (email: object) {
226 const text: string = email[ 'text' ]
227 const toFind = success ? ' finished' : ' error'
228
229 return text.includes(url) && text.includes(toFind)
230 }
231
232 await checkNotification(base, notificationChecker, emailFinder, type)
233 }
234
235 async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) {
236 const notificationType = UserNotificationType.NEW_USER_REGISTRATION
237
238 function notificationChecker (notification: UserNotification, type: CheckerType) {
239 if (type === 'presence') {
240 expect(notification).to.not.be.undefined
241 expect(notification.type).to.equal(notificationType)
242
243 checkActor(notification.account)
244 expect(notification.account.name).to.equal(username)
245 } else {
246 expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username)
247 }
248 }
249
250 function emailFinder (email: object) {
251 const text: string = email[ 'text' ]
252
253 return text.includes(' registered ') && text.includes(username)
254 }
255
256 await checkNotification(base, notificationChecker, emailFinder, type)
257 }
258
259 async function checkNewActorFollow (
260 base: CheckerBaseParams,
261 followType: 'channel' | 'account',
262 followerName: string,
263 followerDisplayName: string,
264 followingDisplayName: string,
265 type: CheckerType
266 ) {
267 const notificationType = UserNotificationType.NEW_FOLLOW
268
269 function notificationChecker (notification: UserNotification, type: CheckerType) {
270 if (type === 'presence') {
271 expect(notification).to.not.be.undefined
272 expect(notification.type).to.equal(notificationType)
273
274 checkActor(notification.actorFollow.follower)
275 expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName)
276 expect(notification.actorFollow.follower.name).to.equal(followerName)
277
278 checkActor(notification.actorFollow.following)
279 expect(notification.actorFollow.following.displayName).to.equal(followingDisplayName)
280 expect(notification.actorFollow.following.type).to.equal(followType)
281 } else {
282 expect(notification).to.satisfy(n => {
283 return n.type !== notificationType ||
284 (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName)
285 })
286 }
287 }
288
289 function emailFinder (email: object) {
290 const text: string = email[ 'text' ]
291
292 return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
293 }
294
295 await checkNotification(base, notificationChecker, emailFinder, type)
296 }
297
298 async function checkCommentMention (
299 base: CheckerBaseParams,
300 uuid: string,
301 commentId: number,
302 threadId: number,
303 byAccountDisplayName: string,
304 type: CheckerType
305 ) {
306 const notificationType = UserNotificationType.COMMENT_MENTION
307
308 function notificationChecker (notification: UserNotification, type: CheckerType) {
309 if (type === 'presence') {
310 expect(notification).to.not.be.undefined
311 expect(notification.type).to.equal(notificationType)
312
313 checkComment(notification.comment, commentId, threadId)
314 checkActor(notification.comment.account)
315 expect(notification.comment.account.displayName).to.equal(byAccountDisplayName)
316
317 checkVideo(notification.comment.video, undefined, uuid)
318 } else {
319 expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId)
320 }
321 }
322
323 function emailFinder (email: object) {
324 const text: string = email[ 'text' ]
325
326 return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName)
327 }
328
329 await checkNotification(base, notificationChecker, emailFinder, type)
330 }
331
332 let lastEmailCount = 0
333 async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) {
334 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
335
336 function notificationChecker (notification: UserNotification, type: CheckerType) {
337 if (type === 'presence') {
338 expect(notification).to.not.be.undefined
339 expect(notification.type).to.equal(notificationType)
340
341 checkComment(notification.comment, commentId, threadId)
342 checkActor(notification.comment.account)
343 checkVideo(notification.comment.video, undefined, uuid)
344 } else {
345 expect(notification).to.satisfy((n: UserNotification) => {
346 return n === undefined || n.comment === undefined || n.comment.id !== commentId
347 })
348 }
349 }
350
351 const commentUrl = `http://localhost:9001/videos/watch/${uuid};threadId=${threadId}`
352 function emailFinder (email: object) {
353 return email[ 'text' ].indexOf(commentUrl) !== -1
354 }
355
356 await checkNotification(base, notificationChecker, emailFinder, type)
357
358 if (type === 'presence') {
359 // We cannot detect email duplicates, so check we received another email
360 expect(base.emails).to.have.length.above(lastEmailCount)
361 lastEmailCount = base.emails.length
362 }
363 }
364
365 async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
366 const notificationType = UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS
367
368 function notificationChecker (notification: UserNotification, type: CheckerType) {
369 if (type === 'presence') {
370 expect(notification).to.not.be.undefined
371 expect(notification.type).to.equal(notificationType)
372
373 expect(notification.videoAbuse.id).to.be.a('number')
374 checkVideo(notification.videoAbuse.video, videoName, videoUUID)
375 } else {
376 expect(notification).to.satisfy((n: UserNotification) => {
377 return n === undefined || n.videoAbuse === undefined || n.videoAbuse.video.uuid !== videoUUID
378 })
379 }
380 }
381
382 function emailFinder (email: object) {
383 const text = email[ 'text' ]
384 return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1
385 }
386
387 await checkNotification(base, notificationChecker, emailFinder, type)
388 }
389
390 async function checkNewBlacklistOnMyVideo (
391 base: CheckerBaseParams,
392 videoUUID: string,
393 videoName: string,
394 blacklistType: 'blacklist' | 'unblacklist'
395 ) {
396 const notificationType = blacklistType === 'blacklist'
397 ? UserNotificationType.BLACKLIST_ON_MY_VIDEO
398 : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO
399
400 function notificationChecker (notification: UserNotification) {
401 expect(notification).to.not.be.undefined
402 expect(notification.type).to.equal(notificationType)
403
404 const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video
405
406 checkVideo(video, videoName, videoUUID)
407 }
408
409 function emailFinder (email: object) {
410 const text = email[ 'text' ]
411 return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1
412 }
413
414 await checkNotification(base, notificationChecker, emailFinder, 'presence')
415 }
416
417 // ---------------------------------------------------------------------------
418
419 export {
420 CheckerBaseParams,
421 CheckerType,
422 checkNotification,
423 markAsReadAllNotifications,
424 checkMyVideoImportIsFinished,
425 checkUserRegistered,
426 checkVideoIsPublished,
427 checkNewVideoFromSubscription,
428 checkNewActorFollow,
429 checkNewCommentOnMyVideo,
430 checkNewBlacklistOnMyVideo,
431 checkCommentMention,
432 updateMyNotificationSettings,
433 checkNewVideoAbuseForModerators,
434 getUserNotifications,
435 markAsReadNotifications,
436 getLastNotification
437 }