]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - shared/utils/users/user-notifications.ts
Add notifications in the client
[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 }
150
151 function checkComment (comment: any, commentId: number, threadId: number) {
152 expect(comment.id).to.equal(commentId)
153 expect(comment.threadId).to.equal(threadId)
154 }
155
156 async function checkNewVideoFromSubscription (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
157 const notificationType = UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION
158
159 function notificationChecker (notification: UserNotification, type: CheckerType) {
160 if (type === 'presence') {
161 expect(notification).to.not.be.undefined
162 expect(notification.type).to.equal(notificationType)
163
164 checkVideo(notification.video, videoName, videoUUID)
165 checkActor(notification.video.channel)
166 } else {
167 expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
168 }
169 }
170
171 function emailFinder (email: object) {
172 return email[ 'text' ].indexOf(videoUUID) !== -1
173 }
174
175 await checkNotification(base, notificationChecker, emailFinder, type)
176 }
177
178 async function checkVideoIsPublished (base: CheckerBaseParams, videoName: string, videoUUID: string, type: CheckerType) {
179 const notificationType = UserNotificationType.MY_VIDEO_PUBLISHED
180
181 function notificationChecker (notification: UserNotification, type: CheckerType) {
182 if (type === 'presence') {
183 expect(notification).to.not.be.undefined
184 expect(notification.type).to.equal(notificationType)
185
186 checkVideo(notification.video, videoName, videoUUID)
187 checkActor(notification.video.channel)
188 } else {
189 expect(notification.video).to.satisfy(v => v === undefined || v.name !== videoName)
190 }
191 }
192
193 function emailFinder (email: object) {
194 const text: string = email[ 'text' ]
195 return text.includes(videoUUID) && text.includes('Your video')
196 }
197
198 await checkNotification(base, notificationChecker, emailFinder, type)
199 }
200
201 async function checkMyVideoImportIsFinished (
202 base: CheckerBaseParams,
203 videoName: string,
204 videoUUID: string,
205 url: string,
206 success: boolean,
207 type: CheckerType
208 ) {
209 const notificationType = success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR
210
211 function notificationChecker (notification: UserNotification, type: CheckerType) {
212 if (type === 'presence') {
213 expect(notification).to.not.be.undefined
214 expect(notification.type).to.equal(notificationType)
215
216 expect(notification.videoImport.targetUrl).to.equal(url)
217
218 if (success) checkVideo(notification.videoImport.video, videoName, videoUUID)
219 } else {
220 expect(notification.videoImport).to.satisfy(i => i === undefined || i.targetUrl !== url)
221 }
222 }
223
224 function emailFinder (email: object) {
225 const text: string = email[ 'text' ]
226 const toFind = success ? ' finished' : ' error'
227
228 return text.includes(url) && text.includes(toFind)
229 }
230
231 await checkNotification(base, notificationChecker, emailFinder, type)
232 }
233
234 async function checkUserRegistered (base: CheckerBaseParams, username: string, type: CheckerType) {
235 const notificationType = UserNotificationType.NEW_USER_REGISTRATION
236
237 function notificationChecker (notification: UserNotification, type: CheckerType) {
238 if (type === 'presence') {
239 expect(notification).to.not.be.undefined
240 expect(notification.type).to.equal(notificationType)
241
242 checkActor(notification.account)
243 expect(notification.account.name).to.equal(username)
244 } else {
245 expect(notification).to.satisfy(n => n.type !== notificationType || n.account.name !== username)
246 }
247 }
248
249 function emailFinder (email: object) {
250 const text: string = email[ 'text' ]
251
252 return text.includes(' registered ') && text.includes(username)
253 }
254
255 await checkNotification(base, notificationChecker, emailFinder, type)
256 }
257
258 async function checkNewActorFollow (
259 base: CheckerBaseParams,
260 followType: 'channel' | 'account',
261 followerName: string,
262 followerDisplayName: string,
263 followingDisplayName: string,
264 type: CheckerType
265 ) {
266 const notificationType = UserNotificationType.NEW_FOLLOW
267
268 function notificationChecker (notification: UserNotification, type: CheckerType) {
269 if (type === 'presence') {
270 expect(notification).to.not.be.undefined
271 expect(notification.type).to.equal(notificationType)
272
273 checkActor(notification.actorFollow.follower)
274 expect(notification.actorFollow.follower.displayName).to.equal(followerDisplayName)
275 expect(notification.actorFollow.follower.name).to.equal(followerName)
276
277 checkActor(notification.actorFollow.following)
278 expect(notification.actorFollow.following.displayName).to.equal(followingDisplayName)
279 expect(notification.actorFollow.following.type).to.equal(followType)
280 } else {
281 expect(notification).to.satisfy(n => {
282 return n.type !== notificationType ||
283 (n.actorFollow.follower.name !== followerName && n.actorFollow.following !== followingDisplayName)
284 })
285 }
286 }
287
288 function emailFinder (email: object) {
289 const text: string = email[ 'text' ]
290
291 return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
292 }
293
294 await checkNotification(base, notificationChecker, emailFinder, type)
295 }
296
297 async function checkCommentMention (
298 base: CheckerBaseParams,
299 uuid: string,
300 commentId: number,
301 threadId: number,
302 byAccountDisplayName: string,
303 type: CheckerType
304 ) {
305 const notificationType = UserNotificationType.COMMENT_MENTION
306
307 function notificationChecker (notification: UserNotification, type: CheckerType) {
308 if (type === 'presence') {
309 expect(notification).to.not.be.undefined
310 expect(notification.type).to.equal(notificationType)
311
312 checkComment(notification.comment, commentId, threadId)
313 checkActor(notification.comment.account)
314 expect(notification.comment.account.displayName).to.equal(byAccountDisplayName)
315
316 checkVideo(notification.comment.video, undefined, uuid)
317 } else {
318 expect(notification).to.satisfy(n => n.type !== notificationType || n.comment.id !== commentId)
319 }
320 }
321
322 function emailFinder (email: object) {
323 const text: string = email[ 'text' ]
324
325 return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName)
326 }
327
328 await checkNotification(base, notificationChecker, emailFinder, type)
329 }
330
331 let lastEmailCount = 0
332 async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) {
333 const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
334
335 function notificationChecker (notification: UserNotification, type: CheckerType) {
336 if (type === 'presence') {
337 expect(notification).to.not.be.undefined
338 expect(notification.type).to.equal(notificationType)
339
340 checkComment(notification.comment, commentId, threadId)
341 checkActor(notification.comment.account)
342 checkVideo(notification.comment.video, undefined, uuid)
343 } else {
344 expect(notification).to.satisfy((n: UserNotification) => {
345 return n === undefined || n.comment === undefined || n.comment.id !== commentId
346 })
347 }
348 }
349
350 const commentUrl = `http://localhost:9001/videos/watch/${uuid};threadId=${threadId}`
351 function emailFinder (email: object) {
352 return email[ 'text' ].indexOf(commentUrl) !== -1
353 }
354
355 await checkNotification(base, notificationChecker, emailFinder, type)
356
357 if (type === 'presence') {
358 // We cannot detect email duplicates, so check we received another email
359 expect(base.emails).to.have.length.above(lastEmailCount)
360 lastEmailCount = base.emails.length
361 }
362 }
363
364 async function checkNewVideoAbuseForModerators (base: CheckerBaseParams, videoUUID: string, videoName: string, type: CheckerType) {
365 const notificationType = UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS
366
367 function notificationChecker (notification: UserNotification, type: CheckerType) {
368 if (type === 'presence') {
369 expect(notification).to.not.be.undefined
370 expect(notification.type).to.equal(notificationType)
371
372 expect(notification.videoAbuse.id).to.be.a('number')
373 checkVideo(notification.videoAbuse.video, videoName, videoUUID)
374 } else {
375 expect(notification).to.satisfy((n: UserNotification) => {
376 return n === undefined || n.videoAbuse === undefined || n.videoAbuse.video.uuid !== videoUUID
377 })
378 }
379 }
380
381 function emailFinder (email: object) {
382 const text = email[ 'text' ]
383 return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1
384 }
385
386 await checkNotification(base, notificationChecker, emailFinder, type)
387 }
388
389 async function checkNewBlacklistOnMyVideo (
390 base: CheckerBaseParams,
391 videoUUID: string,
392 videoName: string,
393 blacklistType: 'blacklist' | 'unblacklist'
394 ) {
395 const notificationType = blacklistType === 'blacklist'
396 ? UserNotificationType.BLACKLIST_ON_MY_VIDEO
397 : UserNotificationType.UNBLACKLIST_ON_MY_VIDEO
398
399 function notificationChecker (notification: UserNotification) {
400 expect(notification).to.not.be.undefined
401 expect(notification.type).to.equal(notificationType)
402
403 const video = blacklistType === 'blacklist' ? notification.videoBlacklist.video : notification.video
404
405 checkVideo(video, videoName, videoUUID)
406 }
407
408 function emailFinder (email: object) {
409 const text = email[ 'text' ]
410 return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1
411 }
412
413 await checkNotification(base, notificationChecker, emailFinder, 'presence')
414 }
415
416 // ---------------------------------------------------------------------------
417
418 export {
419 CheckerBaseParams,
420 CheckerType,
421 checkNotification,
422 markAsReadAllNotifications,
423 checkMyVideoImportIsFinished,
424 checkUserRegistered,
425 checkVideoIsPublished,
426 checkNewVideoFromSubscription,
427 checkNewActorFollow,
428 checkNewCommentOnMyVideo,
429 checkNewBlacklistOnMyVideo,
430 checkCommentMention,
431 updateMyNotificationSettings,
432 checkNewVideoAbuseForModerators,
433 getUserNotifications,
434 markAsReadNotifications,
435 getLastNotification
436 }