diff options
Diffstat (limited to 'server/lib/notifier.ts')
-rw-r--r-- | server/lib/notifier.ts | 154 |
1 files changed, 149 insertions, 5 deletions
diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts index 11b0937e9..2c51d7101 100644 --- a/server/lib/notifier.ts +++ b/server/lib/notifier.ts | |||
@@ -13,6 +13,8 @@ import { VideoBlacklistModel } from '../models/video/video-blacklist' | |||
13 | import * as Bluebird from 'bluebird' | 13 | import * as Bluebird from 'bluebird' |
14 | import { VideoImportModel } from '../models/video/video-import' | 14 | import { VideoImportModel } from '../models/video/video-import' |
15 | import { AccountBlocklistModel } from '../models/account/account-blocklist' | 15 | import { AccountBlocklistModel } from '../models/account/account-blocklist' |
16 | import { ActorFollowModel } from '../models/activitypub/actor-follow' | ||
17 | import { AccountModel } from '../models/account/account' | ||
16 | 18 | ||
17 | class Notifier { | 19 | class Notifier { |
18 | 20 | ||
@@ -38,7 +40,10 @@ class Notifier { | |||
38 | 40 | ||
39 | notifyOnNewComment (comment: VideoCommentModel): void { | 41 | notifyOnNewComment (comment: VideoCommentModel): void { |
40 | this.notifyVideoOwnerOfNewComment(comment) | 42 | this.notifyVideoOwnerOfNewComment(comment) |
41 | .catch(err => logger.error('Cannot notify of new comment %s.', comment.url, { err })) | 43 | .catch(err => logger.error('Cannot notify video owner of new comment %s.', comment.url, { err })) |
44 | |||
45 | this.notifyOfCommentMention(comment) | ||
46 | .catch(err => logger.error('Cannot notify mentions of comment %s.', comment.url, { err })) | ||
42 | } | 47 | } |
43 | 48 | ||
44 | notifyOnNewVideoAbuse (videoAbuse: VideoAbuseModel): void { | 49 | notifyOnNewVideoAbuse (videoAbuse: VideoAbuseModel): void { |
@@ -61,6 +66,23 @@ class Notifier { | |||
61 | .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) | 66 | .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) |
62 | } | 67 | } |
63 | 68 | ||
69 | notifyOnNewUserRegistration (user: UserModel): void { | ||
70 | this.notifyModeratorsOfNewUserRegistration(user) | ||
71 | .catch(err => logger.error('Cannot notify moderators of new user registration (%s).', user.username, { err })) | ||
72 | } | ||
73 | |||
74 | notifyOfNewFollow (actorFollow: ActorFollowModel): void { | ||
75 | this.notifyUserOfNewActorFollow(actorFollow) | ||
76 | .catch(err => { | ||
77 | logger.error( | ||
78 | 'Cannot notify owner of channel %s of a new follow by %s.', | ||
79 | actorFollow.ActorFollowing.VideoChannel.getDisplayName(), | ||
80 | actorFollow.ActorFollower.Account.getDisplayName(), | ||
81 | err | ||
82 | ) | ||
83 | }) | ||
84 | } | ||
85 | |||
64 | private async notifySubscribersOfNewVideo (video: VideoModel) { | 86 | private async notifySubscribersOfNewVideo (video: VideoModel) { |
65 | // List all followers that are users | 87 | // List all followers that are users |
66 | const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId) | 88 | const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId) |
@@ -90,6 +112,8 @@ class Notifier { | |||
90 | } | 112 | } |
91 | 113 | ||
92 | private async notifyVideoOwnerOfNewComment (comment: VideoCommentModel) { | 114 | private async notifyVideoOwnerOfNewComment (comment: VideoCommentModel) { |
115 | if (comment.Video.isOwned() === false) return | ||
116 | |||
93 | const user = await UserModel.loadByVideoId(comment.videoId) | 117 | const user = await UserModel.loadByVideoId(comment.videoId) |
94 | 118 | ||
95 | // Not our user or user comments its own video | 119 | // Not our user or user comments its own video |
@@ -122,11 +146,100 @@ class Notifier { | |||
122 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | 146 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) |
123 | } | 147 | } |
124 | 148 | ||
125 | private async notifyModeratorsOfNewVideoAbuse (videoAbuse: VideoAbuseModel) { | 149 | private async notifyOfCommentMention (comment: VideoCommentModel) { |
126 | const users = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_ABUSES) | 150 | const usernames = comment.extractMentions() |
151 | let users = await UserModel.listByUsernames(usernames) | ||
152 | |||
153 | if (comment.Video.isOwned()) { | ||
154 | const userException = await UserModel.loadByVideoId(comment.videoId) | ||
155 | users = users.filter(u => u.id !== userException.id) | ||
156 | } | ||
157 | |||
158 | // Don't notify if I mentioned myself | ||
159 | users = users.filter(u => u.Account.id !== comment.accountId) | ||
160 | |||
127 | if (users.length === 0) return | 161 | if (users.length === 0) return |
128 | 162 | ||
129 | logger.info('Notifying %s user/moderators of new video abuse %s.', users.length, videoAbuse.Video.url) | 163 | const accountMutedHash = await AccountBlocklistModel.isAccountMutedByMulti(users.map(u => u.Account.id), comment.accountId) |
164 | |||
165 | logger.info('Notifying %d users of new comment %s.', users.length, comment.url) | ||
166 | |||
167 | function settingGetter (user: UserModel) { | ||
168 | if (accountMutedHash[user.Account.id] === true) return UserNotificationSettingValue.NONE | ||
169 | |||
170 | return user.NotificationSetting.commentMention | ||
171 | } | ||
172 | |||
173 | async function notificationCreator (user: UserModel) { | ||
174 | const notification = await UserNotificationModel.create({ | ||
175 | type: UserNotificationType.COMMENT_MENTION, | ||
176 | userId: user.id, | ||
177 | commentId: comment.id | ||
178 | }) | ||
179 | notification.Comment = comment | ||
180 | |||
181 | return notification | ||
182 | } | ||
183 | |||
184 | function emailSender (emails: string[]) { | ||
185 | return Emailer.Instance.addNewCommentMentionNotification(emails, comment) | ||
186 | } | ||
187 | |||
188 | return this.notify({ users, settingGetter, notificationCreator, emailSender }) | ||
189 | } | ||
190 | |||
191 | private async notifyUserOfNewActorFollow (actorFollow: ActorFollowModel) { | ||
192 | if (actorFollow.ActorFollowing.isOwned() === false) return | ||
193 | |||
194 | // Account follows one of our account? | ||
195 | let followType: 'account' | 'channel' = 'channel' | ||
196 | let user = await UserModel.loadByChannelActorId(actorFollow.ActorFollowing.id) | ||
197 | |||
198 | // Account follows one of our channel? | ||
199 | if (!user) { | ||
200 | user = await UserModel.loadByAccountActorId(actorFollow.ActorFollowing.id) | ||
201 | followType = 'account' | ||
202 | } | ||
203 | |||
204 | if (!user) return | ||
205 | |||
206 | if (!actorFollow.ActorFollower.Account || !actorFollow.ActorFollower.Account.name) { | ||
207 | actorFollow.ActorFollower.Account = await actorFollow.ActorFollower.$get('Account') as AccountModel | ||
208 | } | ||
209 | const followerAccount = actorFollow.ActorFollower.Account | ||
210 | |||
211 | const accountMuted = await AccountBlocklistModel.isAccountMutedBy(user.Account.id, followerAccount.id) | ||
212 | if (accountMuted) return | ||
213 | |||
214 | logger.info('Notifying user %s of new follower: %s.', user.username, followerAccount.getDisplayName()) | ||
215 | |||
216 | function settingGetter (user: UserModel) { | ||
217 | return user.NotificationSetting.newFollow | ||
218 | } | ||
219 | |||
220 | async function notificationCreator (user: UserModel) { | ||
221 | const notification = await UserNotificationModel.create({ | ||
222 | type: UserNotificationType.NEW_FOLLOW, | ||
223 | userId: user.id, | ||
224 | actorFollowId: actorFollow.id | ||
225 | }) | ||
226 | notification.ActorFollow = actorFollow | ||
227 | |||
228 | return notification | ||
229 | } | ||
230 | |||
231 | function emailSender (emails: string[]) { | ||
232 | return Emailer.Instance.addNewFollowNotification(emails, actorFollow, followType) | ||
233 | } | ||
234 | |||
235 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | ||
236 | } | ||
237 | |||
238 | private async notifyModeratorsOfNewVideoAbuse (videoAbuse: VideoAbuseModel) { | ||
239 | const moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_ABUSES) | ||
240 | if (moderators.length === 0) return | ||
241 | |||
242 | logger.info('Notifying %s user/moderators of new video abuse %s.', moderators.length, videoAbuse.Video.url) | ||
130 | 243 | ||
131 | function settingGetter (user: UserModel) { | 244 | function settingGetter (user: UserModel) { |
132 | return user.NotificationSetting.videoAbuseAsModerator | 245 | return user.NotificationSetting.videoAbuseAsModerator |
@@ -147,7 +260,7 @@ class Notifier { | |||
147 | return Emailer.Instance.addVideoAbuseModeratorsNotification(emails, videoAbuse) | 260 | return Emailer.Instance.addVideoAbuseModeratorsNotification(emails, videoAbuse) |
148 | } | 261 | } |
149 | 262 | ||
150 | return this.notify({ users, settingGetter, notificationCreator, emailSender }) | 263 | return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender }) |
151 | } | 264 | } |
152 | 265 | ||
153 | private async notifyVideoOwnerOfBlacklist (videoBlacklist: VideoBlacklistModel) { | 266 | private async notifyVideoOwnerOfBlacklist (videoBlacklist: VideoBlacklistModel) { |
@@ -264,6 +377,37 @@ class Notifier { | |||
264 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) | 377 | return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) |
265 | } | 378 | } |
266 | 379 | ||
380 | private async notifyModeratorsOfNewUserRegistration (registeredUser: UserModel) { | ||
381 | const moderators = await UserModel.listWithRight(UserRight.MANAGE_USERS) | ||
382 | if (moderators.length === 0) return | ||
383 | |||
384 | logger.info( | ||
385 | 'Notifying %s moderators of new user registration of %s.', | ||
386 | moderators.length, registeredUser.Account.Actor.preferredUsername | ||
387 | ) | ||
388 | |||
389 | function settingGetter (user: UserModel) { | ||
390 | return user.NotificationSetting.newUserRegistration | ||
391 | } | ||
392 | |||
393 | async function notificationCreator (user: UserModel) { | ||
394 | const notification = await UserNotificationModel.create({ | ||
395 | type: UserNotificationType.NEW_USER_REGISTRATION, | ||
396 | userId: user.id, | ||
397 | accountId: registeredUser.Account.id | ||
398 | }) | ||
399 | notification.Account = registeredUser.Account | ||
400 | |||
401 | return notification | ||
402 | } | ||
403 | |||
404 | function emailSender (emails: string[]) { | ||
405 | return Emailer.Instance.addNewUserRegistrationNotification(emails, registeredUser) | ||
406 | } | ||
407 | |||
408 | return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender }) | ||
409 | } | ||
410 | |||
267 | private async notify (options: { | 411 | private async notify (options: { |
268 | users: UserModel[], | 412 | users: UserModel[], |
269 | notificationCreator: (user: UserModel) => Promise<UserNotificationModel>, | 413 | notificationCreator: (user: UserModel) => Promise<UserNotificationModel>, |