diff options
Diffstat (limited to 'server/lib/notifier.ts')
-rw-r--r-- | server/lib/notifier.ts | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts new file mode 100644 index 000000000..a21b50b2d --- /dev/null +++ b/server/lib/notifier.ts | |||
@@ -0,0 +1,235 @@ | |||
1 | import { UserNotificationSettingValue, UserNotificationType, UserRight } from '../../shared/models/users' | ||
2 | import { logger } from '../helpers/logger' | ||
3 | import { VideoModel } from '../models/video/video' | ||
4 | import { Emailer } from './emailer' | ||
5 | import { UserNotificationModel } from '../models/account/user-notification' | ||
6 | import { VideoCommentModel } from '../models/video/video-comment' | ||
7 | import { UserModel } from '../models/account/user' | ||
8 | import { PeerTubeSocket } from './peertube-socket' | ||
9 | import { CONFIG } from '../initializers/constants' | ||
10 | import { VideoPrivacy, VideoState } from '../../shared/models/videos' | ||
11 | import { VideoAbuseModel } from '../models/video/video-abuse' | ||
12 | import { VideoBlacklistModel } from '../models/video/video-blacklist' | ||
13 | import * as Bluebird from 'bluebird' | ||
14 | |||
15 | class Notifier { | ||
16 | |||
17 | private static instance: Notifier | ||
18 | |||
19 | private constructor () {} | ||
20 | |||
21 | notifyOnNewVideo (video: VideoModel): void { | ||
22 | // Only notify on public and published videos | ||
23 | if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED) return | ||
24 | |||
25 | this.notifySubscribersOfNewVideo(video) | ||
26 | .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) | ||
27 | } | ||
28 | |||
29 | notifyOnNewComment (comment: VideoCommentModel): void { | ||
30 | this.notifyVideoOwnerOfNewComment(comment) | ||
31 | .catch(err => logger.error('Cannot notify of new comment %s.', comment.url, { err })) | ||
32 | } | ||
33 | |||
34 | notifyOnNewVideoAbuse (videoAbuse: VideoAbuseModel): void { | ||
35 | this.notifyModeratorsOfNewVideoAbuse(videoAbuse) | ||
36 | .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err })) | ||
37 | } | ||
38 | |||
39 | notifyOnVideoBlacklist (videoBlacklist: VideoBlacklistModel): void { | ||
40 | this.notifyVideoOwnerOfBlacklist(videoBlacklist) | ||
41 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err })) | ||
42 | } | ||
43 | |||
44 | notifyOnVideoUnblacklist (video: VideoModel): void { | ||
45 | this.notifyVideoOwnerOfUnblacklist(video) | ||
46 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', video.url, { err })) | ||
47 | } | ||
48 | |||
49 | private async notifySubscribersOfNewVideo (video: VideoModel) { | ||
50 | // List all followers that are users | ||
51 | const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId) | ||
52 | |||
53 | logger.info('Notifying %d users of new video %s.', users.length, video.url) | ||
54 | |||
55 | function settingGetter (user: UserModel) { | ||
56 | return user.NotificationSetting.newVideoFromSubscription | ||
57 | } | ||
58 | |||
59 | async function notificationCreator (user: UserModel) { | ||
60 | const notification = await UserNotificationModel.create({ | ||
61 | type: UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION, | ||
62 | userId: user.id, | ||
63 | videoId: video.id | ||
64 | }) | ||
65 | notification.Video = video | ||
66 | |||
67 | return notification | ||
68 | } | ||
69 | |||
70 | function emailSender (emails: string[]) { | ||
71 | return Emailer.Instance.addNewVideoFromSubscriberNotification(emails, video) | ||
72 | } | ||
73 | |||
74 | return this.notify({ users, settingGetter, notificationCreator, emailSender }) | ||
75 | } | ||
76 | |||
77 | private async notifyVideoOwnerOfNewComment (comment: VideoCommentModel) { | ||
78 | const user = await UserModel.loadByVideoId(comment.videoId) | ||
79 | |||
80 | // Not our user or user comments its own video | ||
81 | if (!user || comment.Account.userId === user.id) return | ||
82 | |||
83 | logger.info('Notifying user %s of new comment %s.', user.username, comment.url) | ||
84 | |||
85 | function settingGetter (user: UserModel) { | ||
86 | return user.NotificationSetting.newCommentOnMyVideo | ||
87 | } | ||
88 | |||
89 | async function notificationCreator (user: UserModel) { | ||
90 | const notification = await UserNotificationModel.create({ | ||
91 | type: UserNotificationType.NEW_COMMENT_ON_MY_VIDEO, | ||
92 | userId: user.id, | ||
93 | commentId: comment.id | ||
94 | }) | ||
95 | notification.Comment = comment | ||
96 | |||
97 | return notification | ||
98 | } | ||
99 | |||
100 | function emailSender (emails: string[]) { | ||
101 | return Emailer.Instance.addNewCommentOnMyVideoNotification(emails, comment) | ||
102 | } | ||
103 | |||
104 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | ||
105 | } | ||
106 | |||
107 | private async notifyModeratorsOfNewVideoAbuse (videoAbuse: VideoAbuseModel) { | ||
108 | const users = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_ABUSES) | ||
109 | if (users.length === 0) return | ||
110 | |||
111 | logger.info('Notifying %s user/moderators of new video abuse %s.', users.length, videoAbuse.Video.url) | ||
112 | |||
113 | function settingGetter (user: UserModel) { | ||
114 | return user.NotificationSetting.videoAbuseAsModerator | ||
115 | } | ||
116 | |||
117 | async function notificationCreator (user: UserModel) { | ||
118 | const notification = await UserNotificationModel.create({ | ||
119 | type: UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS, | ||
120 | userId: user.id, | ||
121 | videoAbuseId: videoAbuse.id | ||
122 | }) | ||
123 | notification.VideoAbuse = videoAbuse | ||
124 | |||
125 | return notification | ||
126 | } | ||
127 | |||
128 | function emailSender (emails: string[]) { | ||
129 | return Emailer.Instance.addVideoAbuseModeratorsNotification(emails, videoAbuse) | ||
130 | } | ||
131 | |||
132 | return this.notify({ users, settingGetter, notificationCreator, emailSender }) | ||
133 | } | ||
134 | |||
135 | private async notifyVideoOwnerOfBlacklist (videoBlacklist: VideoBlacklistModel) { | ||
136 | const user = await UserModel.loadByVideoId(videoBlacklist.videoId) | ||
137 | if (!user) return | ||
138 | |||
139 | logger.info('Notifying user %s that its video %s has been blacklisted.', user.username, videoBlacklist.Video.url) | ||
140 | |||
141 | function settingGetter (user: UserModel) { | ||
142 | return user.NotificationSetting.blacklistOnMyVideo | ||
143 | } | ||
144 | |||
145 | async function notificationCreator (user: UserModel) { | ||
146 | const notification = await UserNotificationModel.create({ | ||
147 | type: UserNotificationType.BLACKLIST_ON_MY_VIDEO, | ||
148 | userId: user.id, | ||
149 | videoBlacklistId: videoBlacklist.id | ||
150 | }) | ||
151 | notification.VideoBlacklist = videoBlacklist | ||
152 | |||
153 | return notification | ||
154 | } | ||
155 | |||
156 | function emailSender (emails: string[]) { | ||
157 | return Emailer.Instance.addVideoBlacklistNotification(emails, videoBlacklist) | ||
158 | } | ||
159 | |||
160 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | ||
161 | } | ||
162 | |||
163 | private async notifyVideoOwnerOfUnblacklist (video: VideoModel) { | ||
164 | const user = await UserModel.loadByVideoId(video.id) | ||
165 | if (!user) return | ||
166 | |||
167 | logger.info('Notifying user %s that its video %s has been unblacklisted.', user.username, video.url) | ||
168 | |||
169 | function settingGetter (user: UserModel) { | ||
170 | return user.NotificationSetting.blacklistOnMyVideo | ||
171 | } | ||
172 | |||
173 | async function notificationCreator (user: UserModel) { | ||
174 | const notification = await UserNotificationModel.create({ | ||
175 | type: UserNotificationType.UNBLACKLIST_ON_MY_VIDEO, | ||
176 | userId: user.id, | ||
177 | videoId: video.id | ||
178 | }) | ||
179 | notification.Video = video | ||
180 | |||
181 | return notification | ||
182 | } | ||
183 | |||
184 | function emailSender (emails: string[]) { | ||
185 | return Emailer.Instance.addVideoUnblacklistNotification(emails, video) | ||
186 | } | ||
187 | |||
188 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | ||
189 | } | ||
190 | |||
191 | private async notify (options: { | ||
192 | users: UserModel[], | ||
193 | notificationCreator: (user: UserModel) => Promise<UserNotificationModel>, | ||
194 | emailSender: (emails: string[]) => Promise<any> | Bluebird<any>, | ||
195 | settingGetter: (user: UserModel) => UserNotificationSettingValue | ||
196 | }) { | ||
197 | const emails: string[] = [] | ||
198 | |||
199 | for (const user of options.users) { | ||
200 | if (this.isWebNotificationEnabled(options.settingGetter(user))) { | ||
201 | const notification = await options.notificationCreator(user) | ||
202 | |||
203 | PeerTubeSocket.Instance.sendNotification(user.id, notification) | ||
204 | } | ||
205 | |||
206 | if (this.isEmailEnabled(user, options.settingGetter(user))) { | ||
207 | emails.push(user.email) | ||
208 | } | ||
209 | } | ||
210 | |||
211 | if (emails.length !== 0) { | ||
212 | await options.emailSender(emails) | ||
213 | } | ||
214 | } | ||
215 | |||
216 | private isEmailEnabled (user: UserModel, value: UserNotificationSettingValue) { | ||
217 | if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION === true && user.emailVerified !== true) return false | ||
218 | |||
219 | return value === UserNotificationSettingValue.EMAIL || value === UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL | ||
220 | } | ||
221 | |||
222 | private isWebNotificationEnabled (value: UserNotificationSettingValue) { | ||
223 | return value === UserNotificationSettingValue.WEB_NOTIFICATION || value === UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL | ||
224 | } | ||
225 | |||
226 | static get Instance () { | ||
227 | return this.instance || (this.instance = new this()) | ||
228 | } | ||
229 | } | ||
230 | |||
231 | // --------------------------------------------------------------------------- | ||
232 | |||
233 | export { | ||
234 | Notifier | ||
235 | } | ||