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