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