aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/notifier/notifier.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-07-30 16:51:27 +0200
committerChocobozzz <me@florianbigard.com>2021-08-02 10:39:51 +0200
commitd26836cd95e981d636006652927773c7943e77ce (patch)
tree934a4a835bfddbf1c2c7da98d84ebd7623d60d49 /server/lib/notifier/notifier.ts
parent2bee9db56ade2b3b1bb0efa8716840d87efdb93f (diff)
downloadPeerTube-d26836cd95e981d636006652927773c7943e77ce.tar.gz
PeerTube-d26836cd95e981d636006652927773c7943e77ce.tar.zst
PeerTube-d26836cd95e981d636006652927773c7943e77ce.zip
Refactor notifier
Diffstat (limited to 'server/lib/notifier/notifier.ts')
-rw-r--r--server/lib/notifier/notifier.ts259
1 files changed, 259 insertions, 0 deletions
diff --git a/server/lib/notifier/notifier.ts b/server/lib/notifier/notifier.ts
new file mode 100644
index 000000000..8b68d2e69
--- /dev/null
+++ b/server/lib/notifier/notifier.ts
@@ -0,0 +1,259 @@
1import { MUser, MUserDefault } from '@server/types/models/user'
2import { MVideoBlacklistLightVideo, MVideoBlacklistVideo } from '@server/types/models/video/video-blacklist'
3import { UserNotificationSettingValue } from '../../../shared/models/users'
4import { logger } from '../../helpers/logger'
5import { CONFIG } from '../../initializers/config'
6import { MAbuseFull, MAbuseMessage, MActorFollowFull, MApplication, MPlugin } from '../../types/models'
7import { MCommentOwnerVideo, MVideoAccountLight, MVideoFullLight } from '../../types/models/video'
8import { JobQueue } from '../job-queue'
9import { PeerTubeSocket } from '../peertube-socket'
10import {
11 AbstractNotification,
12 AbuseStateChangeForReporter,
13 AutoFollowForInstance,
14 CommentMention,
15 FollowForInstance,
16 FollowForUser,
17 ImportFinishedForOwner,
18 ImportFinishedForOwnerPayload,
19 NewAbuseForModerators,
20 NewAbuseMessageForModerators,
21 NewAbuseMessageForReporter,
22 NewAbusePayload,
23 NewAutoBlacklistForModerators,
24 NewBlacklistForOwner,
25 NewCommentForVideoOwner,
26 NewPeerTubeVersionForAdmins,
27 NewPluginVersionForAdmins,
28 NewVideoForSubscribers,
29 OwnedPublicationAfterAutoUnblacklist,
30 OwnedPublicationAfterScheduleUpdate,
31 OwnedPublicationAfterTranscoding,
32 RegistrationForModerators,
33 UnblacklistForOwner
34} from './shared'
35
36class Notifier {
37
38 private readonly notificationModels = {
39 newVideo: [ NewVideoForSubscribers ],
40 publicationAfterTranscoding: [ OwnedPublicationAfterTranscoding ],
41 publicationAfterScheduleUpdate: [ OwnedPublicationAfterScheduleUpdate ],
42 publicationAfterAutoUnblacklist: [ OwnedPublicationAfterAutoUnblacklist ],
43 newComment: [ CommentMention, NewCommentForVideoOwner ],
44 newAbuse: [ NewAbuseForModerators ],
45 newBlacklist: [ NewBlacklistForOwner ],
46 unblacklist: [ UnblacklistForOwner ],
47 importFinished: [ ImportFinishedForOwner ],
48 userRegistration: [ RegistrationForModerators ],
49 userFollow: [ FollowForUser ],
50 instanceFollow: [ FollowForInstance ],
51 autoInstanceFollow: [ AutoFollowForInstance ],
52 newAutoBlacklist: [ NewAutoBlacklistForModerators ],
53 abuseStateChange: [ AbuseStateChangeForReporter ],
54 newAbuseMessage: [ NewAbuseMessageForReporter, NewAbuseMessageForModerators ],
55 newPeertubeVersion: [ NewPeerTubeVersionForAdmins ],
56 newPluginVersion: [ NewPluginVersionForAdmins ]
57 }
58
59 private static instance: Notifier
60
61 private constructor () {
62 }
63
64 notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void {
65 const models = this.notificationModels.newVideo
66
67 this.sendNotifications(models, video)
68 .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err }))
69 }
70
71 notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void {
72 const models = this.notificationModels.publicationAfterTranscoding
73
74 this.sendNotifications(models, video)
75 .catch(err => logger.error('Cannot notify owner that its video %s has been published after transcoding.', video.url, { err }))
76 }
77
78 notifyOnVideoPublishedAfterScheduledUpdate (video: MVideoFullLight): void {
79 const models = this.notificationModels.publicationAfterScheduleUpdate
80
81 this.sendNotifications(models, video)
82 .catch(err => logger.error('Cannot notify owner that its video %s has been published after scheduled update.', video.url, { err }))
83 }
84
85 notifyOnVideoPublishedAfterRemovedFromAutoBlacklist (video: MVideoFullLight): void {
86 const models = this.notificationModels.publicationAfterAutoUnblacklist
87
88 this.sendNotifications(models, video)
89 .catch(err => {
90 logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err })
91 })
92 }
93
94 notifyOnNewComment (comment: MCommentOwnerVideo): void {
95 const models = this.notificationModels.newComment
96
97 this.sendNotifications(models, comment)
98 .catch(err => logger.error('Cannot notify of new comment.', comment.url, { err }))
99 }
100
101 notifyOnNewAbuse (payload: NewAbusePayload): void {
102 const models = this.notificationModels.newAbuse
103
104 this.sendNotifications(models, payload)
105 .catch(err => logger.error('Cannot notify of new abuse %d.', payload.abuseInstance.id, { err }))
106 }
107
108 notifyOnVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo): void {
109 const models = this.notificationModels.newAutoBlacklist
110
111 this.sendNotifications(models, videoBlacklist)
112 .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err }))
113 }
114
115 notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void {
116 const models = this.notificationModels.newBlacklist
117
118 this.sendNotifications(models, videoBlacklist)
119 .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err }))
120 }
121
122 notifyOnVideoUnblacklist (video: MVideoFullLight): void {
123 const models = this.notificationModels.unblacklist
124
125 this.sendNotifications(models, video)
126 .catch(err => logger.error('Cannot notify video owner of unblacklist of %s.', video.url, { err }))
127 }
128
129 notifyOnFinishedVideoImport (payload: ImportFinishedForOwnerPayload): void {
130 const models = this.notificationModels.importFinished
131
132 this.sendNotifications(models, payload)
133 .catch(err => {
134 logger.error('Cannot notify owner that its video import %s is finished.', payload.videoImport.getTargetIdentifier(), { err })
135 })
136 }
137
138 notifyOnNewUserRegistration (user: MUserDefault): void {
139 const models = this.notificationModels.userRegistration
140
141 this.sendNotifications(models, user)
142 .catch(err => logger.error('Cannot notify moderators of new user registration (%s).', user.username, { err }))
143 }
144
145 notifyOfNewUserFollow (actorFollow: MActorFollowFull): void {
146 const models = this.notificationModels.userFollow
147
148 this.sendNotifications(models, actorFollow)
149 .catch(err => {
150 logger.error(
151 'Cannot notify owner of channel %s of a new follow by %s.',
152 actorFollow.ActorFollowing.VideoChannel.getDisplayName(),
153 actorFollow.ActorFollower.Account.getDisplayName(),
154 { err }
155 )
156 })
157 }
158
159 notifyOfNewInstanceFollow (actorFollow: MActorFollowFull): void {
160 const models = this.notificationModels.instanceFollow
161
162 this.sendNotifications(models, actorFollow)
163 .catch(err => logger.error('Cannot notify administrators of new follower %s.', actorFollow.ActorFollower.url, { err }))
164 }
165
166 notifyOfAutoInstanceFollowing (actorFollow: MActorFollowFull): void {
167 const models = this.notificationModels.autoInstanceFollow
168
169 this.sendNotifications(models, actorFollow)
170 .catch(err => logger.error('Cannot notify administrators of auto instance following %s.', actorFollow.ActorFollowing.url, { err }))
171 }
172
173 notifyOnAbuseStateChange (abuse: MAbuseFull): void {
174 const models = this.notificationModels.abuseStateChange
175
176 this.sendNotifications(models, abuse)
177 .catch(err => logger.error('Cannot notify of abuse %d state change.', abuse.id, { err }))
178 }
179
180 notifyOnAbuseMessage (abuse: MAbuseFull, message: MAbuseMessage): void {
181 const models = this.notificationModels.newAbuseMessage
182
183 this.sendNotifications(models, { abuse, message })
184 .catch(err => logger.error('Cannot notify on new abuse %d message.', abuse.id, { err }))
185 }
186
187 notifyOfNewPeerTubeVersion (application: MApplication, latestVersion: string) {
188 const models = this.notificationModels.newPeertubeVersion
189
190 this.sendNotifications(models, { application, latestVersion })
191 .catch(err => logger.error('Cannot notify on new PeerTubeb version %s.', latestVersion, { err }))
192 }
193
194 notifyOfNewPluginVersion (plugin: MPlugin) {
195 const models = this.notificationModels.newPluginVersion
196
197 this.sendNotifications(models, plugin)
198 .catch(err => logger.error('Cannot notify on new plugin version %s.', plugin.name, { err }))
199 }
200
201 private async notify <T> (object: AbstractNotification<T>) {
202 await object.prepare()
203
204 const users = object.getTargetUsers()
205
206 if (users.length === 0) return
207 if (await object.isDisabled()) return
208
209 object.log()
210
211 const toEmails: string[] = []
212
213 for (const user of users) {
214 const setting = object.getSetting(user)
215
216 if (this.isWebNotificationEnabled(setting)) {
217 const notification = await object.createNotification(user)
218
219 PeerTubeSocket.Instance.sendNotification(user.id, notification)
220 }
221
222 if (this.isEmailEnabled(user, setting)) {
223 toEmails.push(user.email)
224 }
225 }
226
227 for (const to of toEmails) {
228 const payload = await object.createEmail(to)
229 JobQueue.Instance.createJob({ type: 'email', payload })
230 }
231 }
232
233 private isEmailEnabled (user: MUser, value: UserNotificationSettingValue) {
234 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION === true && user.emailVerified === false) return false
235
236 return value & UserNotificationSettingValue.EMAIL
237 }
238
239 private isWebNotificationEnabled (value: UserNotificationSettingValue) {
240 return value & UserNotificationSettingValue.WEB
241 }
242
243 private async sendNotifications <T> (models: (new (payload: T) => AbstractNotification<T>)[], payload: T) {
244 for (const model of models) {
245 // eslint-disable-next-line new-cap
246 await this.notify(new model(payload))
247 }
248 }
249
250 static get Instance () {
251 return this.instance || (this.instance = new this())
252 }
253}
254
255// ---------------------------------------------------------------------------
256
257export {
258 Notifier
259}