X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Femailer.ts;h=f384a254e017d6912a71e8063ce2c25c19aa8512;hb=73471b1a52f242e86364ffb077ea6cadb3b07ae2;hp=ded321bf70c4acd186c0225779a10810d7af5d56;hpb=c1e791bad0b079af67398f6407221e6dcbb573dd;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index ded321bf7..f384a254e 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts @@ -1,5 +1,4 @@ import { createTransport, Transporter } from 'nodemailer' -import { UserRight } from '../../shared/models/users' import { isTestInstance } from '../helpers/core-utils' import { bunyanLogger, logger } from '../helpers/logger' import { CONFIG } from '../initializers' @@ -7,7 +6,12 @@ import { UserModel } from '../models/account/user' import { VideoModel } from '../models/video/video' import { JobQueue } from './job-queue' import { EmailPayload } from './job-queue/handlers/email' -import { readFileSync } from 'fs' +import { readFileSync } from 'fs-extra' +import { VideoCommentModel } from '../models/video/video-comment' +import { VideoAbuseModel } from '../models/video/video-abuse' +import { VideoBlacklistModel } from '../models/video/video-blacklist' +import { VideoImportModel } from '../models/video/video-import' +import { ActorFollowModel } from '../models/activitypub/actor-follow' class Emailer { @@ -22,7 +26,7 @@ class Emailer { if (this.initialized === true) return this.initialized = true - if (CONFIG.SMTP.HOSTNAME && CONFIG.SMTP.PORT) { + if (Emailer.isEnabled()) { logger.info('Using %s:%s as SMTP server.', CONFIG.SMTP.HOSTNAME, CONFIG.SMTP.PORT) let tls @@ -57,6 +61,10 @@ class Emailer { } } + static isEnabled () { + return !!CONFIG.SMTP.HOSTNAME && !!CONFIG.SMTP.PORT + } + async checkConnectionOrDie () { if (!this.transporter) return @@ -72,6 +80,222 @@ class Emailer { } } + addNewVideoFromSubscriberNotification (to: string[], video: VideoModel) { + const channelName = video.VideoChannel.getDisplayName() + const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath() + + const text = `Hi dear user,\n\n` + + `Your subscription ${channelName} just published a new video: ${video.name}` + + `\n\n` + + `You can view it on ${videoUrl} ` + + `\n\n` + + `Cheers,\n` + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: channelName + ' just published a new video', + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + addNewFollowNotification (to: string[], actorFollow: ActorFollowModel, followType: 'account' | 'channel') { + const followerName = actorFollow.ActorFollower.Account.getDisplayName() + const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName() + + const text = `Hi dear user,\n\n` + + `Your ${followType} ${followingName} has a new subscriber: ${followerName}` + + `\n\n` + + `Cheers,\n` + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: 'New follower on your channel ' + followingName, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + myVideoPublishedNotification (to: string[], video: VideoModel) { + const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath() + + const text = `Hi dear user,\n\n` + + `Your video ${video.name} has been published.` + + `\n\n` + + `You can view it on ${videoUrl} ` + + `\n\n` + + `Cheers,\n` + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: `Your video ${video.name} is published`, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + myVideoImportSuccessNotification (to: string[], videoImport: VideoImportModel) { + const videoUrl = CONFIG.WEBSERVER.URL + videoImport.Video.getWatchStaticPath() + + const text = `Hi dear user,\n\n` + + `Your video import ${videoImport.getTargetIdentifier()} is finished.` + + `\n\n` + + `You can view the imported video on ${videoUrl} ` + + `\n\n` + + `Cheers,\n` + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: `Your video import ${videoImport.getTargetIdentifier()} is finished`, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + myVideoImportErrorNotification (to: string[], videoImport: VideoImportModel) { + const importUrl = CONFIG.WEBSERVER.URL + '/my-account/video-imports' + + const text = `Hi dear user,\n\n` + + `Your video import ${videoImport.getTargetIdentifier()} encountered an error.` + + `\n\n` + + `See your videos import dashboard for more information: ${importUrl}` + + `\n\n` + + `Cheers,\n` + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: `Your video import ${videoImport.getTargetIdentifier()} encountered an error`, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + addNewCommentOnMyVideoNotification (to: string[], comment: VideoCommentModel) { + const accountName = comment.Account.getDisplayName() + const video = comment.Video + const commentUrl = CONFIG.WEBSERVER.URL + comment.getCommentStaticPath() + + const text = `Hi dear user,\n\n` + + `A new comment has been posted by ${accountName} on your video ${video.name}` + + `\n\n` + + `You can view it on ${commentUrl} ` + + `\n\n` + + `Cheers,\n` + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: 'New comment on your video ' + video.name, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + addNewCommentMentionNotification (to: string[], comment: VideoCommentModel) { + const accountName = comment.Account.getDisplayName() + const video = comment.Video + const commentUrl = CONFIG.WEBSERVER.URL + comment.getCommentStaticPath() + + const text = `Hi dear user,\n\n` + + `${accountName} mentioned you on video ${video.name}` + + `\n\n` + + `You can view the comment on ${commentUrl} ` + + `\n\n` + + `Cheers,\n` + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: 'Mention on video ' + video.name, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + addVideoAbuseModeratorsNotification (to: string[], videoAbuse: VideoAbuseModel) { + const videoUrl = CONFIG.WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath() + + const text = `Hi,\n\n` + + `${CONFIG.WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` + + `Cheers,\n` + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: '[PeerTube] Received a video abuse', + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + addNewUserRegistrationNotification (to: string[], user: UserModel) { + const text = `Hi,\n\n` + + `User ${user.username} just registered on ${CONFIG.WEBSERVER.HOST} PeerTube instance.\n\n` + + `Cheers,\n` + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: '[PeerTube] New user registration on ' + CONFIG.WEBSERVER.HOST, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + addVideoBlacklistNotification (to: string[], videoBlacklist: VideoBlacklistModel) { + const videoName = videoBlacklist.Video.name + const videoUrl = CONFIG.WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath() + + const reasonString = videoBlacklist.reason ? ` for the following reason: ${videoBlacklist.reason}` : '' + const blockedString = `Your video ${videoName} (${videoUrl} on ${CONFIG.WEBSERVER.HOST} has been blacklisted${reasonString}.` + + const text = 'Hi,\n\n' + + blockedString + + '\n\n' + + 'Cheers,\n' + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: `[PeerTube] Video ${videoName} blacklisted`, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + addVideoUnblacklistNotification (to: string[], video: VideoModel) { + const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath() + + const text = 'Hi,\n\n' + + `Your video ${video.name} (${videoUrl}) on ${CONFIG.WEBSERVER.HOST} has been unblacklisted.` + + '\n\n' + + 'Cheers,\n' + + `PeerTube.` + + const emailPayload: EmailPayload = { + to, + subject: `[PeerTube] Video ${video.name} unblacklisted`, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + addForgetPasswordEmailJob (to: string, resetPasswordUrl: string) { const text = `Hi dear user,\n\n` + `It seems you forgot your password on ${CONFIG.WEBSERVER.HOST}! ` + @@ -89,32 +313,70 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - async addVideoAbuseReport (videoId: number) { - const video = await VideoModel.load(videoId) - if (!video) throw new Error('Unknown Video id during Abuse report.') - - const text = `Hi,\n\n` + - `Your instance received an abuse for the following video ${video.url}\n\n` + + addVerifyEmailJob (to: string, verifyEmailUrl: string) { + const text = `Welcome to PeerTube,\n\n` + + `To start using PeerTube on ${CONFIG.WEBSERVER.HOST} you must verify your email! ` + + `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` + + `If you are not the person who initiated this request, please ignore this email.\n\n` + `Cheers,\n` + `PeerTube.` - const to = await UserModel.listEmailsWithRight(UserRight.MANAGE_VIDEO_ABUSES) const emailPayload: EmailPayload = { - to, - subject: '[PeerTube] Received a video abuse', + to: [ to ], + subject: 'Verify your PeerTube email', + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + addUserBlockJob (user: UserModel, blocked: boolean, reason?: string) { + const reasonString = reason ? ` for the following reason: ${reason}` : '' + const blockedWord = blocked ? 'blocked' : 'unblocked' + const blockedString = `Your account ${user.username} on ${CONFIG.WEBSERVER.HOST} has been ${blockedWord}${reasonString}.` + + const text = 'Hi,\n\n' + + blockedString + + '\n\n' + + 'Cheers,\n' + + `PeerTube.` + + const to = user.email + const emailPayload: EmailPayload = { + to: [ to ], + subject: '[PeerTube] Account ' + blockedWord, + text + } + + return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) + } + + addContactFormJob (fromEmail: string, fromName: string, body: string) { + const text = 'Hello dear admin,\n\n' + + fromName + ' sent you a message' + + '\n\n---------------------------------------\n\n' + + body + + '\n\n---------------------------------------\n\n' + + 'Cheers,\n' + + 'PeerTube.' + + const emailPayload: EmailPayload = { + from: fromEmail, + to: [ CONFIG.ADMIN.EMAIL ], + subject: '[PeerTube] Contact form submitted', text } return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - sendMail (to: string[], subject: string, text: string) { - if (!this.transporter) { + sendMail (to: string[], subject: string, text: string, from?: string) { + if (!Emailer.isEnabled()) { throw new Error('Cannot send mail because SMTP is not configured.') } return this.transporter.sendMail({ - from: CONFIG.SMTP.FROM_ADDRESS, + from: from || CONFIG.SMTP.FROM_ADDRESS, to: to.join(','), subject, text