]>
Commit | Line | Data |
---|---|---|
cef534ed C |
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' | |
dc133480 C |
14 | import { VideoImportModel } from '../models/video/video-import' |
15 | import { AccountBlocklistModel } from '../models/account/account-blocklist' | |
cef534ed C |
16 | |
17 | class Notifier { | |
18 | ||
19 | private static instance: Notifier | |
20 | ||
21 | private constructor () {} | |
22 | ||
23 | notifyOnNewVideo (video: VideoModel): void { | |
24 | // Only notify on public and published videos | |
25 | if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED) return | |
26 | ||
27 | this.notifySubscribersOfNewVideo(video) | |
28 | .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) | |
29 | } | |
30 | ||
dc133480 C |
31 | notifyOnPendingVideoPublished (video: VideoModel): void { |
32 | // Only notify on public videos that has been published while the user waited transcoding/scheduled update | |
33 | if (video.waitTranscoding === false && !video.ScheduleVideoUpdate) return | |
34 | ||
35 | this.notifyOwnedVideoHasBeenPublished(video) | |
36 | .catch(err => logger.error('Cannot notify owner that its video %s has been published.', video.url, { err })) | |
37 | } | |
38 | ||
cef534ed C |
39 | notifyOnNewComment (comment: VideoCommentModel): void { |
40 | this.notifyVideoOwnerOfNewComment(comment) | |
41 | .catch(err => logger.error('Cannot notify of new comment %s.', comment.url, { err })) | |
42 | } | |
43 | ||
44 | notifyOnNewVideoAbuse (videoAbuse: VideoAbuseModel): void { | |
45 | this.notifyModeratorsOfNewVideoAbuse(videoAbuse) | |
46 | .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err })) | |
47 | } | |
48 | ||
49 | notifyOnVideoBlacklist (videoBlacklist: VideoBlacklistModel): void { | |
50 | this.notifyVideoOwnerOfBlacklist(videoBlacklist) | |
51 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err })) | |
52 | } | |
53 | ||
54 | notifyOnVideoUnblacklist (video: VideoModel): void { | |
55 | this.notifyVideoOwnerOfUnblacklist(video) | |
56 | .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', video.url, { err })) | |
57 | } | |
58 | ||
dc133480 C |
59 | notifyOnFinishedVideoImport (videoImport: VideoImportModel, success: boolean): void { |
60 | this.notifyOwnerVideoImportIsFinished(videoImport, success) | |
61 | .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) | |
62 | } | |
63 | ||
cef534ed C |
64 | private async notifySubscribersOfNewVideo (video: VideoModel) { |
65 | // List all followers that are users | |
66 | const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId) | |
67 | ||
68 | logger.info('Notifying %d users of new video %s.', users.length, video.url) | |
69 | ||
70 | function settingGetter (user: UserModel) { | |
71 | return user.NotificationSetting.newVideoFromSubscription | |
72 | } | |
73 | ||
74 | async function notificationCreator (user: UserModel) { | |
75 | const notification = await UserNotificationModel.create({ | |
76 | type: UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION, | |
77 | userId: user.id, | |
78 | videoId: video.id | |
79 | }) | |
80 | notification.Video = video | |
81 | ||
82 | return notification | |
83 | } | |
84 | ||
85 | function emailSender (emails: string[]) { | |
86 | return Emailer.Instance.addNewVideoFromSubscriberNotification(emails, video) | |
87 | } | |
88 | ||
89 | return this.notify({ users, settingGetter, notificationCreator, emailSender }) | |
90 | } | |
91 | ||
92 | private async notifyVideoOwnerOfNewComment (comment: VideoCommentModel) { | |
93 | const user = await UserModel.loadByVideoId(comment.videoId) | |
94 | ||
95 | // Not our user or user comments its own video | |
96 | if (!user || comment.Account.userId === user.id) return | |
97 | ||
dc133480 C |
98 | const accountMuted = await AccountBlocklistModel.isAccountMutedBy(user.Account.id, comment.accountId) |
99 | if (accountMuted) return | |
100 | ||
cef534ed C |
101 | logger.info('Notifying user %s of new comment %s.', user.username, comment.url) |
102 | ||
103 | function settingGetter (user: UserModel) { | |
104 | return user.NotificationSetting.newCommentOnMyVideo | |
105 | } | |
106 | ||
107 | async function notificationCreator (user: UserModel) { | |
108 | const notification = await UserNotificationModel.create({ | |
109 | type: UserNotificationType.NEW_COMMENT_ON_MY_VIDEO, | |
110 | userId: user.id, | |
111 | commentId: comment.id | |
112 | }) | |
113 | notification.Comment = comment | |
114 | ||
115 | return notification | |
116 | } | |
117 | ||
118 | function emailSender (emails: string[]) { | |
119 | return Emailer.Instance.addNewCommentOnMyVideoNotification(emails, comment) | |
120 | } | |
121 | ||
122 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | |
123 | } | |
124 | ||
125 | private async notifyModeratorsOfNewVideoAbuse (videoAbuse: VideoAbuseModel) { | |
126 | const users = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_ABUSES) | |
127 | if (users.length === 0) return | |
128 | ||
129 | logger.info('Notifying %s user/moderators of new video abuse %s.', users.length, videoAbuse.Video.url) | |
130 | ||
131 | function settingGetter (user: UserModel) { | |
132 | return user.NotificationSetting.videoAbuseAsModerator | |
133 | } | |
134 | ||
135 | async function notificationCreator (user: UserModel) { | |
136 | const notification = await UserNotificationModel.create({ | |
137 | type: UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS, | |
138 | userId: user.id, | |
139 | videoAbuseId: videoAbuse.id | |
140 | }) | |
141 | notification.VideoAbuse = videoAbuse | |
142 | ||
143 | return notification | |
144 | } | |
145 | ||
146 | function emailSender (emails: string[]) { | |
147 | return Emailer.Instance.addVideoAbuseModeratorsNotification(emails, videoAbuse) | |
148 | } | |
149 | ||
150 | return this.notify({ users, settingGetter, notificationCreator, emailSender }) | |
151 | } | |
152 | ||
153 | private async notifyVideoOwnerOfBlacklist (videoBlacklist: VideoBlacklistModel) { | |
154 | const user = await UserModel.loadByVideoId(videoBlacklist.videoId) | |
155 | if (!user) return | |
156 | ||
157 | logger.info('Notifying user %s that its video %s has been blacklisted.', user.username, videoBlacklist.Video.url) | |
158 | ||
159 | function settingGetter (user: UserModel) { | |
160 | return user.NotificationSetting.blacklistOnMyVideo | |
161 | } | |
162 | ||
163 | async function notificationCreator (user: UserModel) { | |
164 | const notification = await UserNotificationModel.create({ | |
165 | type: UserNotificationType.BLACKLIST_ON_MY_VIDEO, | |
166 | userId: user.id, | |
167 | videoBlacklistId: videoBlacklist.id | |
168 | }) | |
169 | notification.VideoBlacklist = videoBlacklist | |
170 | ||
171 | return notification | |
172 | } | |
173 | ||
174 | function emailSender (emails: string[]) { | |
175 | return Emailer.Instance.addVideoBlacklistNotification(emails, videoBlacklist) | |
176 | } | |
177 | ||
178 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | |
179 | } | |
180 | ||
181 | private async notifyVideoOwnerOfUnblacklist (video: VideoModel) { | |
182 | const user = await UserModel.loadByVideoId(video.id) | |
183 | if (!user) return | |
184 | ||
185 | logger.info('Notifying user %s that its video %s has been unblacklisted.', user.username, video.url) | |
186 | ||
187 | function settingGetter (user: UserModel) { | |
188 | return user.NotificationSetting.blacklistOnMyVideo | |
189 | } | |
190 | ||
191 | async function notificationCreator (user: UserModel) { | |
192 | const notification = await UserNotificationModel.create({ | |
193 | type: UserNotificationType.UNBLACKLIST_ON_MY_VIDEO, | |
194 | userId: user.id, | |
195 | videoId: video.id | |
196 | }) | |
197 | notification.Video = video | |
198 | ||
199 | return notification | |
200 | } | |
201 | ||
202 | function emailSender (emails: string[]) { | |
203 | return Emailer.Instance.addVideoUnblacklistNotification(emails, video) | |
204 | } | |
205 | ||
206 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | |
207 | } | |
208 | ||
dc133480 C |
209 | private async notifyOwnedVideoHasBeenPublished (video: VideoModel) { |
210 | const user = await UserModel.loadByVideoId(video.id) | |
211 | if (!user) return | |
212 | ||
213 | logger.info('Notifying user %s of the publication of its video %s.', user.username, video.url) | |
214 | ||
215 | function settingGetter (user: UserModel) { | |
216 | return user.NotificationSetting.myVideoPublished | |
217 | } | |
218 | ||
219 | async function notificationCreator (user: UserModel) { | |
220 | const notification = await UserNotificationModel.create({ | |
221 | type: UserNotificationType.MY_VIDEO_PUBLISHED, | |
222 | userId: user.id, | |
223 | videoId: video.id | |
224 | }) | |
225 | notification.Video = video | |
226 | ||
227 | return notification | |
228 | } | |
229 | ||
230 | function emailSender (emails: string[]) { | |
231 | return Emailer.Instance.myVideoPublishedNotification(emails, video) | |
232 | } | |
233 | ||
234 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | |
235 | } | |
236 | ||
237 | private async notifyOwnerVideoImportIsFinished (videoImport: VideoImportModel, success: boolean) { | |
238 | const user = await UserModel.loadByVideoImportId(videoImport.id) | |
239 | if (!user) return | |
240 | ||
241 | logger.info('Notifying user %s its video import %s is finished.', user.username, videoImport.getTargetIdentifier()) | |
242 | ||
243 | function settingGetter (user: UserModel) { | |
244 | return user.NotificationSetting.myVideoImportFinished | |
245 | } | |
246 | ||
247 | async function notificationCreator (user: UserModel) { | |
248 | const notification = await UserNotificationModel.create({ | |
249 | type: success ? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS : UserNotificationType.MY_VIDEO_IMPORT_ERROR, | |
250 | userId: user.id, | |
251 | videoImportId: videoImport.id | |
252 | }) | |
253 | notification.VideoImport = videoImport | |
254 | ||
255 | return notification | |
256 | } | |
257 | ||
258 | function emailSender (emails: string[]) { | |
259 | return success | |
260 | ? Emailer.Instance.myVideoImportSuccessNotification(emails, videoImport) | |
261 | : Emailer.Instance.myVideoImportErrorNotification(emails, videoImport) | |
262 | } | |
263 | ||
264 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | |
265 | } | |
266 | ||
cef534ed C |
267 | private async notify (options: { |
268 | users: UserModel[], | |
269 | notificationCreator: (user: UserModel) => Promise<UserNotificationModel>, | |
270 | emailSender: (emails: string[]) => Promise<any> | Bluebird<any>, | |
271 | settingGetter: (user: UserModel) => UserNotificationSettingValue | |
272 | }) { | |
273 | const emails: string[] = [] | |
274 | ||
275 | for (const user of options.users) { | |
276 | if (this.isWebNotificationEnabled(options.settingGetter(user))) { | |
277 | const notification = await options.notificationCreator(user) | |
278 | ||
279 | PeerTubeSocket.Instance.sendNotification(user.id, notification) | |
280 | } | |
281 | ||
282 | if (this.isEmailEnabled(user, options.settingGetter(user))) { | |
283 | emails.push(user.email) | |
284 | } | |
285 | } | |
286 | ||
287 | if (emails.length !== 0) { | |
288 | await options.emailSender(emails) | |
289 | } | |
290 | } | |
291 | ||
292 | private isEmailEnabled (user: UserModel, value: UserNotificationSettingValue) { | |
293 | if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION === true && user.emailVerified !== true) return false | |
294 | ||
295 | return value === UserNotificationSettingValue.EMAIL || value === UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL | |
296 | } | |
297 | ||
298 | private isWebNotificationEnabled (value: UserNotificationSettingValue) { | |
299 | return value === UserNotificationSettingValue.WEB_NOTIFICATION || value === UserNotificationSettingValue.WEB_NOTIFICATION_AND_EMAIL | |
300 | } | |
301 | ||
302 | static get Instance () { | |
303 | return this.instance || (this.instance = new this()) | |
304 | } | |
305 | } | |
306 | ||
307 | // --------------------------------------------------------------------------- | |
308 | ||
309 | export { | |
310 | Notifier | |
311 | } |