]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/lib/emailer.ts
Fix notification icon position
[github/Chocobozzz/PeerTube.git] / server / lib / emailer.ts
1 import { createTransport, Transporter } from 'nodemailer'
2 import { isTestInstance } from '../helpers/core-utils'
3 import { bunyanLogger, logger } from '../helpers/logger'
4 import { CONFIG } from '../initializers'
5 import { UserModel } from '../models/account/user'
6 import { VideoModel } from '../models/video/video'
7 import { JobQueue } from './job-queue'
8 import { EmailPayload } from './job-queue/handlers/email'
9 import { readFileSync } from 'fs-extra'
10 import { VideoCommentModel } from '../models/video/video-comment'
11 import { VideoAbuseModel } from '../models/video/video-abuse'
12 import { VideoBlacklistModel } from '../models/video/video-blacklist'
13
14 class Emailer {
15
16 private static instance: Emailer
17 private initialized = false
18 private transporter: Transporter
19 private enabled = false
20
21 private constructor () {}
22
23 init () {
24 // Already initialized
25 if (this.initialized === true) return
26 this.initialized = true
27
28 if (CONFIG.SMTP.HOSTNAME && CONFIG.SMTP.PORT) {
29 logger.info('Using %s:%s as SMTP server.', CONFIG.SMTP.HOSTNAME, CONFIG.SMTP.PORT)
30
31 let tls
32 if (CONFIG.SMTP.CA_FILE) {
33 tls = {
34 ca: [ readFileSync(CONFIG.SMTP.CA_FILE) ]
35 }
36 }
37
38 let auth
39 if (CONFIG.SMTP.USERNAME && CONFIG.SMTP.PASSWORD) {
40 auth = {
41 user: CONFIG.SMTP.USERNAME,
42 pass: CONFIG.SMTP.PASSWORD
43 }
44 }
45
46 this.transporter = createTransport({
47 host: CONFIG.SMTP.HOSTNAME,
48 port: CONFIG.SMTP.PORT,
49 secure: CONFIG.SMTP.TLS,
50 debug: CONFIG.LOG.LEVEL === 'debug',
51 logger: bunyanLogger as any,
52 ignoreTLS: CONFIG.SMTP.DISABLE_STARTTLS,
53 tls,
54 auth
55 })
56
57 this.enabled = true
58 } else {
59 if (!isTestInstance()) {
60 logger.error('Cannot use SMTP server because of lack of configuration. PeerTube will not be able to send mails!')
61 }
62 }
63 }
64
65 isEnabled () {
66 return this.enabled
67 }
68
69 async checkConnectionOrDie () {
70 if (!this.transporter) return
71
72 logger.info('Testing SMTP server...')
73
74 try {
75 const success = await this.transporter.verify()
76 if (success !== true) this.dieOnConnectionFailure()
77
78 logger.info('Successfully connected to SMTP server.')
79 } catch (err) {
80 this.dieOnConnectionFailure(err)
81 }
82 }
83
84 addNewVideoFromSubscriberNotification (to: string[], video: VideoModel) {
85 const channelName = video.VideoChannel.getDisplayName()
86 const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath()
87
88 const text = `Hi dear user,\n\n` +
89 `Your subscription ${channelName} just published a new video: ${video.name}` +
90 `\n\n` +
91 `You can view it on ${videoUrl} ` +
92 `\n\n` +
93 `Cheers,\n` +
94 `PeerTube.`
95
96 const emailPayload: EmailPayload = {
97 to,
98 subject: channelName + ' just published a new video',
99 text
100 }
101
102 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
103 }
104
105 addNewCommentOnMyVideoNotification (to: string[], comment: VideoCommentModel) {
106 const accountName = comment.Account.getDisplayName()
107 const video = comment.Video
108 const commentUrl = CONFIG.WEBSERVER.URL + comment.getCommentStaticPath()
109
110 const text = `Hi dear user,\n\n` +
111 `A new comment has been posted by ${accountName} on your video ${video.name}` +
112 `\n\n` +
113 `You can view it on ${commentUrl} ` +
114 `\n\n` +
115 `Cheers,\n` +
116 `PeerTube.`
117
118 const emailPayload: EmailPayload = {
119 to,
120 subject: 'New comment on your video ' + video.name,
121 text
122 }
123
124 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
125 }
126
127 async addVideoAbuseModeratorsNotification (to: string[], videoAbuse: VideoAbuseModel) {
128 const videoUrl = CONFIG.WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath()
129
130 const text = `Hi,\n\n` +
131 `${CONFIG.WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` +
132 `Cheers,\n` +
133 `PeerTube.`
134
135 const emailPayload: EmailPayload = {
136 to,
137 subject: '[PeerTube] Received a video abuse',
138 text
139 }
140
141 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
142 }
143
144 async addVideoBlacklistNotification (to: string[], videoBlacklist: VideoBlacklistModel) {
145 const videoName = videoBlacklist.Video.name
146 const videoUrl = CONFIG.WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath()
147
148 const reasonString = videoBlacklist.reason ? ` for the following reason: ${videoBlacklist.reason}` : ''
149 const blockedString = `Your video ${videoName} (${videoUrl} on ${CONFIG.WEBSERVER.HOST} has been blacklisted${reasonString}.`
150
151 const text = 'Hi,\n\n' +
152 blockedString +
153 '\n\n' +
154 'Cheers,\n' +
155 `PeerTube.`
156
157 const emailPayload: EmailPayload = {
158 to,
159 subject: `[PeerTube] Video ${videoName} blacklisted`,
160 text
161 }
162
163 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
164 }
165
166 async addVideoUnblacklistNotification (to: string[], video: VideoModel) {
167 const videoUrl = CONFIG.WEBSERVER.URL + video.getWatchStaticPath()
168
169 const text = 'Hi,\n\n' +
170 `Your video ${video.name} (${videoUrl}) on ${CONFIG.WEBSERVER.HOST} has been unblacklisted.` +
171 '\n\n' +
172 'Cheers,\n' +
173 `PeerTube.`
174
175 const emailPayload: EmailPayload = {
176 to,
177 subject: `[PeerTube] Video ${video.name} unblacklisted`,
178 text
179 }
180
181 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
182 }
183
184 addForgetPasswordEmailJob (to: string, resetPasswordUrl: string) {
185 const text = `Hi dear user,\n\n` +
186 `It seems you forgot your password on ${CONFIG.WEBSERVER.HOST}! ` +
187 `Please follow this link to reset it: ${resetPasswordUrl}\n\n` +
188 `If you are not the person who initiated this request, please ignore this email.\n\n` +
189 `Cheers,\n` +
190 `PeerTube.`
191
192 const emailPayload: EmailPayload = {
193 to: [ to ],
194 subject: 'Reset your PeerTube password',
195 text
196 }
197
198 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
199 }
200
201 addVerifyEmailJob (to: string, verifyEmailUrl: string) {
202 const text = `Welcome to PeerTube,\n\n` +
203 `To start using PeerTube on ${CONFIG.WEBSERVER.HOST} you must verify your email! ` +
204 `Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` +
205 `If you are not the person who initiated this request, please ignore this email.\n\n` +
206 `Cheers,\n` +
207 `PeerTube.`
208
209 const emailPayload: EmailPayload = {
210 to: [ to ],
211 subject: 'Verify your PeerTube email',
212 text
213 }
214
215 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
216 }
217
218 addUserBlockJob (user: UserModel, blocked: boolean, reason?: string) {
219 const reasonString = reason ? ` for the following reason: ${reason}` : ''
220 const blockedWord = blocked ? 'blocked' : 'unblocked'
221 const blockedString = `Your account ${user.username} on ${CONFIG.WEBSERVER.HOST} has been ${blockedWord}${reasonString}.`
222
223 const text = 'Hi,\n\n' +
224 blockedString +
225 '\n\n' +
226 'Cheers,\n' +
227 `PeerTube.`
228
229 const to = user.email
230 const emailPayload: EmailPayload = {
231 to: [ to ],
232 subject: '[PeerTube] Account ' + blockedWord,
233 text
234 }
235
236 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
237 }
238
239 sendMail (to: string[], subject: string, text: string) {
240 if (!this.enabled) {
241 throw new Error('Cannot send mail because SMTP is not configured.')
242 }
243
244 return this.transporter.sendMail({
245 from: CONFIG.SMTP.FROM_ADDRESS,
246 to: to.join(','),
247 subject,
248 text
249 })
250 }
251
252 private dieOnConnectionFailure (err?: Error) {
253 logger.error('Failed to connect to SMTP %s:%d.', CONFIG.SMTP.HOSTNAME, CONFIG.SMTP.PORT, { err })
254 process.exit(-1)
255 }
256
257 static get Instance () {
258 return this.instance || (this.instance = new this())
259 }
260 }
261
262 // ---------------------------------------------------------------------------
263
264 export {
265 Emailer
266 }