diff options
Diffstat (limited to 'server/lib/emailer.ts')
-rw-r--r-- | server/lib/emailer.ts | 94 |
1 files changed, 73 insertions, 21 deletions
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index 99010f473..8c06e9751 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { createTransport, Transporter } from 'nodemailer' | 1 | import { createTransport, Transporter } from 'nodemailer' |
2 | import { isTestInstance } from '../helpers/core-utils' | 2 | import { isTestInstance } from '../helpers/core-utils' |
3 | import { bunyanLogger, logger } from '../helpers/logger' | 3 | import { bunyanLogger, logger } from '../helpers/logger' |
4 | import { CONFIG } from '../initializers' | 4 | import { CONFIG } from '../initializers/config' |
5 | import { UserModel } from '../models/account/user' | 5 | import { UserModel } from '../models/account/user' |
6 | import { VideoModel } from '../models/video/video' | 6 | import { VideoModel } from '../models/video/video' |
7 | import { JobQueue } from './job-queue' | 7 | import { JobQueue } from './job-queue' |
@@ -12,6 +12,16 @@ import { VideoAbuseModel } from '../models/video/video-abuse' | |||
12 | import { VideoBlacklistModel } from '../models/video/video-blacklist' | 12 | import { VideoBlacklistModel } from '../models/video/video-blacklist' |
13 | import { VideoImportModel } from '../models/video/video-import' | 13 | import { VideoImportModel } from '../models/video/video-import' |
14 | import { ActorFollowModel } from '../models/activitypub/actor-follow' | 14 | import { ActorFollowModel } from '../models/activitypub/actor-follow' |
15 | import { WEBSERVER } from '../initializers/constants' | ||
16 | |||
17 | type SendEmailOptions = { | ||
18 | to: string[] | ||
19 | subject: string | ||
20 | text: string | ||
21 | |||
22 | fromDisplayName?: string | ||
23 | replyTo?: string | ||
24 | } | ||
15 | 25 | ||
16 | class Emailer { | 26 | class Emailer { |
17 | 27 | ||
@@ -82,7 +92,7 @@ class Emailer { | |||
82 | 92 | ||
83 | addNewVideoFromSubscriberNotification (to: string[], video: VideoModel) { | 93 | addNewVideoFromSubscriberNotification (to: string[], video: VideoModel) { |
84 | const channelName = video.VideoChannel.getDisplayName() | 94 | const channelName = video.VideoChannel.getDisplayName() |
85 | const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath() | 95 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() |
86 | 96 | ||
87 | const text = `Hi dear user,\n\n` + | 97 | const text = `Hi dear user,\n\n` + |
88 | `Your subscription ${channelName} just published a new video: ${video.name}` + | 98 | `Your subscription ${channelName} just published a new video: ${video.name}` + |
@@ -120,8 +130,26 @@ class Emailer { | |||
120 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | 130 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) |
121 | } | 131 | } |
122 | 132 | ||
133 | addNewInstanceFollowerNotification (to: string[], actorFollow: ActorFollowModel) { | ||
134 | const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : '' | ||
135 | |||
136 | const text = `Hi dear admin,\n\n` + | ||
137 | `Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` + | ||
138 | `\n\n` + | ||
139 | `Cheers,\n` + | ||
140 | `PeerTube.` | ||
141 | |||
142 | const emailPayload: EmailPayload = { | ||
143 | to, | ||
144 | subject: 'New instance follower', | ||
145 | text | ||
146 | } | ||
147 | |||
148 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | ||
149 | } | ||
150 | |||
123 | myVideoPublishedNotification (to: string[], video: VideoModel) { | 151 | myVideoPublishedNotification (to: string[], video: VideoModel) { |
124 | const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath() | 152 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() |
125 | 153 | ||
126 | const text = `Hi dear user,\n\n` + | 154 | const text = `Hi dear user,\n\n` + |
127 | `Your video ${video.name} has been published.` + | 155 | `Your video ${video.name} has been published.` + |
@@ -141,7 +169,7 @@ class Emailer { | |||
141 | } | 169 | } |
142 | 170 | ||
143 | myVideoImportSuccessNotification (to: string[], videoImport: VideoImportModel) { | 171 | myVideoImportSuccessNotification (to: string[], videoImport: VideoImportModel) { |
144 | const videoUrl = CONFIG.WEBSERVER.URL + videoImport.Video.getWatchStaticPath() | 172 | const videoUrl = WEBSERVER.URL + videoImport.Video.getWatchStaticPath() |
145 | 173 | ||
146 | const text = `Hi dear user,\n\n` + | 174 | const text = `Hi dear user,\n\n` + |
147 | `Your video import ${videoImport.getTargetIdentifier()} is finished.` + | 175 | `Your video import ${videoImport.getTargetIdentifier()} is finished.` + |
@@ -161,7 +189,7 @@ class Emailer { | |||
161 | } | 189 | } |
162 | 190 | ||
163 | myVideoImportErrorNotification (to: string[], videoImport: VideoImportModel) { | 191 | myVideoImportErrorNotification (to: string[], videoImport: VideoImportModel) { |
164 | const importUrl = CONFIG.WEBSERVER.URL + '/my-account/video-imports' | 192 | const importUrl = WEBSERVER.URL + '/my-account/video-imports' |
165 | 193 | ||
166 | const text = `Hi dear user,\n\n` + | 194 | const text = `Hi dear user,\n\n` + |
167 | `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` + | 195 | `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` + |
@@ -183,7 +211,7 @@ class Emailer { | |||
183 | addNewCommentOnMyVideoNotification (to: string[], comment: VideoCommentModel) { | 211 | addNewCommentOnMyVideoNotification (to: string[], comment: VideoCommentModel) { |
184 | const accountName = comment.Account.getDisplayName() | 212 | const accountName = comment.Account.getDisplayName() |
185 | const video = comment.Video | 213 | const video = comment.Video |
186 | const commentUrl = CONFIG.WEBSERVER.URL + comment.getCommentStaticPath() | 214 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() |
187 | 215 | ||
188 | const text = `Hi dear user,\n\n` + | 216 | const text = `Hi dear user,\n\n` + |
189 | `A new comment has been posted by ${accountName} on your video ${video.name}` + | 217 | `A new comment has been posted by ${accountName} on your video ${video.name}` + |
@@ -205,7 +233,7 @@ class Emailer { | |||
205 | addNewCommentMentionNotification (to: string[], comment: VideoCommentModel) { | 233 | addNewCommentMentionNotification (to: string[], comment: VideoCommentModel) { |
206 | const accountName = comment.Account.getDisplayName() | 234 | const accountName = comment.Account.getDisplayName() |
207 | const video = comment.Video | 235 | const video = comment.Video |
208 | const commentUrl = CONFIG.WEBSERVER.URL + comment.getCommentStaticPath() | 236 | const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() |
209 | 237 | ||
210 | const text = `Hi dear user,\n\n` + | 238 | const text = `Hi dear user,\n\n` + |
211 | `${accountName} mentioned you on video ${video.name}` + | 239 | `${accountName} mentioned you on video ${video.name}` + |
@@ -225,10 +253,10 @@ class Emailer { | |||
225 | } | 253 | } |
226 | 254 | ||
227 | addVideoAbuseModeratorsNotification (to: string[], videoAbuse: VideoAbuseModel) { | 255 | addVideoAbuseModeratorsNotification (to: string[], videoAbuse: VideoAbuseModel) { |
228 | const videoUrl = CONFIG.WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath() | 256 | const videoUrl = WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath() |
229 | 257 | ||
230 | const text = `Hi,\n\n` + | 258 | const text = `Hi,\n\n` + |
231 | `${CONFIG.WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + | 259 | `${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + |
232 | `Cheers,\n` + | 260 | `Cheers,\n` + |
233 | `PeerTube.` | 261 | `PeerTube.` |
234 | 262 | ||
@@ -241,15 +269,38 @@ class Emailer { | |||
241 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | 269 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) |
242 | } | 270 | } |
243 | 271 | ||
272 | addVideoAutoBlacklistModeratorsNotification (to: string[], video: VideoModel) { | ||
273 | const VIDEO_AUTO_BLACKLIST_URL = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list' | ||
274 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() | ||
275 | |||
276 | const text = `Hi,\n\n` + | ||
277 | `A recently added video was auto-blacklisted and requires moderator review before publishing.` + | ||
278 | `\n\n` + | ||
279 | `You can view it and take appropriate action on ${videoUrl}` + | ||
280 | `\n\n` + | ||
281 | `A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` + | ||
282 | `\n\n` + | ||
283 | `Cheers,\n` + | ||
284 | `PeerTube.` | ||
285 | |||
286 | const emailPayload: EmailPayload = { | ||
287 | to, | ||
288 | subject: '[PeerTube] An auto-blacklisted video is awaiting review', | ||
289 | text | ||
290 | } | ||
291 | |||
292 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | ||
293 | } | ||
294 | |||
244 | addNewUserRegistrationNotification (to: string[], user: UserModel) { | 295 | addNewUserRegistrationNotification (to: string[], user: UserModel) { |
245 | const text = `Hi,\n\n` + | 296 | const text = `Hi,\n\n` + |
246 | `User ${user.username} just registered on ${CONFIG.WEBSERVER.HOST} PeerTube instance.\n\n` + | 297 | `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + |
247 | `Cheers,\n` + | 298 | `Cheers,\n` + |
248 | `PeerTube.` | 299 | `PeerTube.` |
249 | 300 | ||
250 | const emailPayload: EmailPayload = { | 301 | const emailPayload: EmailPayload = { |
251 | to, | 302 | to, |
252 | subject: '[PeerTube] New user registration on ' + CONFIG.WEBSERVER.HOST, | 303 | subject: '[PeerTube] New user registration on ' + WEBSERVER.HOST, |
253 | text | 304 | text |
254 | } | 305 | } |
255 | 306 | ||
@@ -258,10 +309,10 @@ class Emailer { | |||
258 | 309 | ||
259 | addVideoBlacklistNotification (to: string[], videoBlacklist: VideoBlacklistModel) { | 310 | addVideoBlacklistNotification (to: string[], videoBlacklist: VideoBlacklistModel) { |
260 | const videoName = videoBlacklist.Video.name | 311 | const videoName = videoBlacklist.Video.name |
261 | const videoUrl = CONFIG.WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath() | 312 | const videoUrl = WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath() |
262 | 313 | ||
263 | const reasonString = videoBlacklist.reason ? ` for the following reason: ${videoBlacklist.reason}` : '' | 314 | const reasonString = videoBlacklist.reason ? ` for the following reason: ${videoBlacklist.reason}` : '' |
264 | const blockedString = `Your video ${videoName} (${videoUrl} on ${CONFIG.WEBSERVER.HOST} has been blacklisted${reasonString}.` | 315 | const blockedString = `Your video ${videoName} (${videoUrl} on ${WEBSERVER.HOST} has been blacklisted${reasonString}.` |
265 | 316 | ||
266 | const text = 'Hi,\n\n' + | 317 | const text = 'Hi,\n\n' + |
267 | blockedString + | 318 | blockedString + |
@@ -279,10 +330,10 @@ class Emailer { | |||
279 | } | 330 | } |
280 | 331 | ||
281 | addVideoUnblacklistNotification (to: string[], video: VideoModel) { | 332 | addVideoUnblacklistNotification (to: string[], video: VideoModel) { |
282 | const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath() | 333 | const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() |
283 | 334 | ||
284 | const text = 'Hi,\n\n' + | 335 | const text = 'Hi,\n\n' + |
285 | `Your video ${video.name} (${videoUrl}) on ${CONFIG.WEBSERVER.HOST} has been unblacklisted.` + | 336 | `Your video ${video.name} (${videoUrl}) on ${WEBSERVER.HOST} has been unblacklisted.` + |
286 | '\n\n' + | 337 | '\n\n' + |
287 | 'Cheers,\n' + | 338 | 'Cheers,\n' + |
288 | `PeerTube.` | 339 | `PeerTube.` |
@@ -296,9 +347,9 @@ class Emailer { | |||
296 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) | 347 | return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) |
297 | } | 348 | } |
298 | 349 | ||
299 | addForgetPasswordEmailJob (to: string, resetPasswordUrl: string) { | 350 | addPasswordResetEmailJob (to: string, resetPasswordUrl: string) { |
300 | const text = `Hi dear user,\n\n` + | 351 | const text = `Hi dear user,\n\n` + |
301 | `It seems you forgot your password on ${CONFIG.WEBSERVER.HOST}! ` + | 352 | `A reset password procedure for your account ${to} has been requested on ${WEBSERVER.HOST} ` + |
302 | `Please follow this link to reset it: ${resetPasswordUrl}\n\n` + | 353 | `Please follow this link to reset it: ${resetPasswordUrl}\n\n` + |
303 | `If you are not the person who initiated this request, please ignore this email.\n\n` + | 354 | `If you are not the person who initiated this request, please ignore this email.\n\n` + |
304 | `Cheers,\n` + | 355 | `Cheers,\n` + |
@@ -315,7 +366,7 @@ class Emailer { | |||
315 | 366 | ||
316 | addVerifyEmailJob (to: string, verifyEmailUrl: string) { | 367 | addVerifyEmailJob (to: string, verifyEmailUrl: string) { |
317 | const text = `Welcome to PeerTube,\n\n` + | 368 | const text = `Welcome to PeerTube,\n\n` + |
318 | `To start using PeerTube on ${CONFIG.WEBSERVER.HOST} you must verify your email! ` + | 369 | `To start using PeerTube on ${WEBSERVER.HOST} you must verify your email! ` + |
319 | `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + | 370 | `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + |
320 | `If you are not the person who initiated this request, please ignore this email.\n\n` + | 371 | `If you are not the person who initiated this request, please ignore this email.\n\n` + |
321 | `Cheers,\n` + | 372 | `Cheers,\n` + |
@@ -333,7 +384,7 @@ class Emailer { | |||
333 | addUserBlockJob (user: UserModel, blocked: boolean, reason?: string) { | 384 | addUserBlockJob (user: UserModel, blocked: boolean, reason?: string) { |
334 | const reasonString = reason ? ` for the following reason: ${reason}` : '' | 385 | const reasonString = reason ? ` for the following reason: ${reason}` : '' |
335 | const blockedWord = blocked ? 'blocked' : 'unblocked' | 386 | const blockedWord = blocked ? 'blocked' : 'unblocked' |
336 | const blockedString = `Your account ${user.username} on ${CONFIG.WEBSERVER.HOST} has been ${blockedWord}${reasonString}.` | 387 | const blockedString = `Your account ${user.username} on ${WEBSERVER.HOST} has been ${blockedWord}${reasonString}.` |
337 | 388 | ||
338 | const text = 'Hi,\n\n' + | 389 | const text = 'Hi,\n\n' + |
339 | blockedString + | 390 | blockedString + |
@@ -378,7 +429,7 @@ class Emailer { | |||
378 | 429 | ||
379 | const fromDisplayName = options.fromDisplayName | 430 | const fromDisplayName = options.fromDisplayName |
380 | ? options.fromDisplayName | 431 | ? options.fromDisplayName |
381 | : CONFIG.WEBSERVER.HOST | 432 | : WEBSERVER.HOST |
382 | 433 | ||
383 | return this.transporter.sendMail({ | 434 | return this.transporter.sendMail({ |
384 | from: `"${fromDisplayName}" <${CONFIG.SMTP.FROM_ADDRESS}>`, | 435 | from: `"${fromDisplayName}" <${CONFIG.SMTP.FROM_ADDRESS}>`, |
@@ -402,5 +453,6 @@ class Emailer { | |||
402 | // --------------------------------------------------------------------------- | 453 | // --------------------------------------------------------------------------- |
403 | 454 | ||
404 | export { | 455 | export { |
405 | Emailer | 456 | Emailer, |
457 | SendEmailOptions | ||
406 | } | 458 | } |