]>
Commit | Line | Data |
---|---|---|
d26836cd C |
1 | import { MUser, MUserDefault } from '@server/types/models/user' |
2 | import { MVideoBlacklistLightVideo, MVideoBlacklistVideo } from '@server/types/models/video/video-blacklist' | |
3 | import { UserNotificationSettingValue } from '../../../shared/models/users' | |
4 | import { logger } from '../../helpers/logger' | |
5 | import { CONFIG } from '../../initializers/config' | |
6 | import { MAbuseFull, MAbuseMessage, MActorFollowFull, MApplication, MPlugin } from '../../types/models' | |
7 | import { MCommentOwnerVideo, MVideoAccountLight, MVideoFullLight } from '../../types/models/video' | |
8 | import { JobQueue } from '../job-queue' | |
9 | import { PeerTubeSocket } from '../peertube-socket' | |
10 | import { | |
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 | ||
36 | class 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 | ||
257 | export { | |
258 | Notifier | |
259 | } |