Skip to content

Commit c44028f

Browse files
committed
refactor: normalize email calls
1 parent 8cad610 commit c44028f

File tree

8 files changed

+122
-132
lines changed

8 files changed

+122
-132
lines changed

doc/contributors/extensions.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
### `vscode`
2+
- `es6-string-html`

package-lock.json

+14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/backend/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"composite-error": "^1.0.2",
2929
"compression": "^1.7.4",
3030
"cookie-parser": "^1.4.6",
31+
"dedent": "^1.5.3",
3132
"express": "^4.18.2",
3233
"file-type": "^18.5.0",
3334
"form-data": "^4.0.0",

packages/backend/src/CoreModule.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ const install = async ({ services, app }) => {
195195

196196
const { EdgeRateLimitService } = require('./services/abuse-prevention/EdgeRateLimitService');
197197
services.registerService('edge-rate-limit', EdgeRateLimitService);
198+
199+
const { Emailservice } = require('./services/EmailService');
200+
services.registerService('email', Emailservice);
198201
}
199202

200203
const install_legacy = async ({ services }) => {
@@ -206,7 +209,6 @@ const install_legacy = async ({ services }) => {
206209
const { OperationTraceService } = require('./services/OperationTraceService');
207210
const { WSPushService } = require('./services/WSPushService');
208211
const { ReferralCodeService } = require('./services/ReferralCodeService');
209-
const { Emailservice } = require('./services/EmailService');
210212
const { ClientOperationService } = require('./services/ClientOperationService');
211213
const { EngPortalService } = require('./services/EngPortalService');
212214
const { AppInformationService } = require('./services/AppInformationService');
@@ -220,7 +222,6 @@ const install_legacy = async ({ services }) => {
220222
services.registerService('operationTrace', OperationTraceService);
221223
services.registerService('__event-push-ws', WSPushService);
222224
services.registerService('referral-code', ReferralCodeService);
223-
services.registerService('email', Emailservice);
224225
services.registerService('file-cache', FileCacheService);
225226
services.registerService('client-operation', ClientOperationService);
226227
services.registerService('app-information', AppInformationService);

packages/backend/src/helpers.js

+7-47
Original file line numberDiff line numberDiff line change
@@ -1547,56 +1547,16 @@ async function generate_system_fsentries(user){
15471547
}
15481548

15491549
function send_email_verification_code(email_confirm_code, email){
1550-
const nodemailer = require("nodemailer");
1551-
1552-
// send email notif
1553-
let transporter = nodemailer.createTransport({
1554-
host: config.smtp_server,
1555-
port: config.smpt_port,
1556-
secure: true, // STARTTLS
1557-
auth: {
1558-
user: config.smtp_username,
1559-
pass: config.smtp_password,
1560-
},
1561-
});
1562-
1563-
transporter.sendMail({
1564-
from: '"Puter" [email protected]', // sender address
1565-
to: email, // list of receivers
1566-
subject: `${hyphenize_confirm_code(email_confirm_code)} is your confirmation code`, // Subject line
1567-
html: `<p>Hi there,</p>
1568-
<p><strong>${hyphenize_confirm_code(email_confirm_code)}</strong> is your email confirmation code.</p>
1569-
<p>Sincerely,</p>
1570-
<p>Puter</p>
1571-
`,
1572-
});
1550+
const svc_email = Context.get('services').get('email');
1551+
svc_email.send_email({ email }, 'email_verification_code', {
1552+
code: hyphenize_confirm_code(email_confirm_code),
1553+
})
15731554
}
15741555

15751556
function send_email_verification_token(email_confirm_token, email, user_uuid){
1576-
const nodemailer = require("nodemailer");
1577-
1578-
// send email notif
1579-
let transporter = nodemailer.createTransport({
1580-
host: config.smtp_server,
1581-
port: config.smpt_port,
1582-
secure: true, // STARTTLS
1583-
auth: {
1584-
user: config.smtp_username,
1585-
pass: config.smtp_password,
1586-
},
1587-
});
1588-
1589-
let link = `${config.origin}/confirm-email-by-token?user_uuid=${user_uuid}&token=${email_confirm_token}`;
1590-
transporter.sendMail({
1591-
from: '"Puter" [email protected]', // sender address
1592-
to: email, // list of receivers
1593-
subject: `Please confirm your email`, // Subject line
1594-
html: `<p>Hi there,</p>
1595-
<p>Please confirm your email address using this link: <strong><a href="${link}">${link}</a></strong>.</p>
1596-
<p>Sincerely,</p>
1597-
<p>Puter</p>
1598-
`,
1599-
});
1557+
const svc_email = Context.get('services').get('email');
1558+
const link = `${config.origin}/confirm-email-by-token?user_uuid=${user_uuid}&token=${email_confirm_token}`;
1559+
svc_email.send_email({ email }, 'email_verification_link', { link });
16001560
}
16011561

16021562
async function generate_random_username(){

packages/backend/src/routers/contactUs.js

+2-14
Original file line numberDiff line numberDiff line change
@@ -71,20 +71,8 @@ router.post('/contactUs', auth, express.json(), async (req, res, next)=>{
7171
let user = await get_user({id: req.user.id});
7272

7373
// send email to support
74-
const nodemailer = require("nodemailer");
75-
76-
// send email notif
77-
let transporter = nodemailer.createTransport({
78-
host: config.smtp_server,
79-
port: config.smpt_port,
80-
secure: true, // STARTTLS
81-
auth: {
82-
user: config.smtp_username,
83-
pass: config.smtp_password,
84-
},
85-
});
86-
87-
transporter.sendMail({
74+
const svc_email = req.services.get('email');
75+
svc_email.sendMail({
8876
from: '"Puter" [email protected]', // sender address
8977
to: '[email protected]', // list of receivers
9078
replyTo: user.email === null ? undefined : user.email,

packages/backend/src/routers/send-pass-recovery-email.js

+3-22
Original file line numberDiff line numberDiff line change
@@ -86,31 +86,12 @@ router.post('/send-pass-recovery-email', express.json(), body_parser_error_handl
8686
);
8787
invalidate_cached_user(user);
8888

89-
// prepare email
90-
let transporter = nodemailer.createTransport({
91-
host: config.smtp_server,
92-
port: config.smpt_port,
93-
secure: true, // STARTTLS
94-
auth: {
95-
user: config.smtp_username,
96-
pass: config.smtp_password,
97-
},
98-
});
99-
10089
// create link
10190
const rec_link = config.origin + '/action/set-new-password?user=' + user.uuid + '&token=' + token;
10291

103-
// send email
104-
transporter.sendMail({
105-
from: '[email protected]', // sender address
106-
to: user.email, // list of receivers
107-
subject: "Password Recovery", // Subject line
108-
html: `
109-
<p>Hi there,</p>
110-
<p>A password recovery request was issued for your account, please follow the link below to reset your password:</p>
111-
<p><a href="${rec_link}">${rec_link}</a></p>
112-
<p>Sincerely,</p>
113-
<p>Puter</p>`,
92+
const svc_email = req.services.get('email');
93+
await svc_email.send_email({ email: user.email }, 'email_password_recovery', {
94+
link: rec_link,
11495
});
11596

11697
// Send response

packages/backend/src/services/EmailService.js

+90-47
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,22 @@
1616
* You should have received a copy of the GNU Affero General Public License
1717
* along with this program. If not, see <https://www.gnu.org/licenses/>.
1818
*/
19-
const { AdvancedBase } = require("@heyputer/puter-js-common");
2019

21-
class Emailservice extends AdvancedBase {
22-
static MODULES = {
23-
nodemailer: require('nodemailer'),
24-
handlebars: require('handlebars'),
25-
};
20+
const BaseService = require('./BaseService');
2621

27-
constructor ({ services, config }) {
28-
super();
29-
this.config = config;
30-
31-
this.templates = {
32-
'new-referral': {
33-
subject: `You've made a referral!`,
34-
html: `<p>Hi there,</p>
35-
<p>A new user has used your referral code. Enjoy an extra {{storage_increase}} of storage, on the house!</p>
36-
<p>Sincerely,</p>
37-
<p>Puter</p>
38-
`,
39-
},
40-
'approved-for-listing': {
41-
subject: '\u{1f389} Your app has been approved for listing!',
42-
html: `
22+
const TEMPLATES = {
23+
'new-referral': {
24+
subject: `You've made a referral!`,
25+
html: `
26+
<p>Hi there,</p>
27+
<p>A new user has used your referral code. Enjoy an extra {{storage_increase}} of storage, on the house!</p>
28+
<p>Sincerely,</p>
29+
<p>Puter</p>
30+
`,
31+
},
32+
'approved-for-listing': {
33+
subject: '\u{1f389} Your app has been approved for listing!',
34+
html: `
4335
<p>Hi there,</p>
4436
<p>
4537
Exciting news! <a href="https://puter.com/app/{{app_name}}">{{app_title}}</a> is now approved and live on <a href="https://puter.com/app/app-center" target="_blank">Puter App Center</a>. It's now ready for users worldwide to discover and enjoy.
@@ -51,11 +43,11 @@ Exciting news! <a href="https://puter.com/app/{{app_name}}">{{app_title}}</a> is
5143
<p>Best,<br />
5244
The Puter Team
5345
</p>
54-
`,
55-
},
56-
'email_change_request': {
57-
subject: '\u{1f4dd} Confirm your email change',
58-
html: `
46+
`,
47+
},
48+
'email_change_request': {
49+
subject: '\u{1f4dd} Confirm your email change',
50+
html: `
5951
<p>Hi there,</p>
6052
<p>
6153
We received a request to link this email to the user "{{username}}" on Puter. If you made this request, please click the link below to confirm the change. If you did not make this request, please ignore this email.
@@ -64,59 +56,110 @@ We received a request to link this email to the user "{{username}}" on Puter. If
6456
<p>
6557
<a href="{{confirm_url}}">Confirm email change</a>
6658
</p>
67-
`,
68-
},
69-
'email_change_notification': {
70-
subject: '\u{1f4dd} Notification of email change',
71-
html: `
59+
`,
60+
},
61+
'email_change_notification': {
62+
subject: '\u{1f4dd} Notification of email change',
63+
html: `
7264
<p>Hi there,</p>
7365
<p>
7466
We're sending an email to let you know about a change to your account.
7567
We have sent a confirmation to "{{new_email}}" to confirm an email change request.
7668
If this was not you, please contact [email protected] immediately.
7769
</p>
78-
`,
79-
},
80-
};
70+
`,
71+
},
72+
'email_verification_code': {
73+
subject: `{{code}} is your confirmation code`,
74+
html: /*html*/`
75+
<p>Hi there,</p>
76+
<p><strong>{{code}}</strong> is your email confirmation code.</p>
77+
<p>Sincerely,</p>
78+
<p>Puter</p>
79+
`
80+
},
81+
'email_verification_link': {
82+
subject: `Please confirm your email`,
83+
html: /*html*/`
84+
<p>Hi there,</p>
85+
<p>Please confirm your email address using this link: <strong><a href="{{link}}">{{link}}</a></strong>.</p>
86+
<p>Sincerely,</p>
87+
<p>Puter</p>
88+
`
89+
},
90+
'email_password_recovery': {
91+
subject: `Password Recovery`,
92+
html: /*html*/`
93+
<p>Hi there,</p>
94+
<p>A password recovery request was issued for your account, please follow the link below to reset your password:</p>
95+
<p><a href="{{link}}">{{link}}</a></p>
96+
<p>Sincerely,</p>
97+
<p>Puter</p>
98+
`,
99+
},
100+
}
101+
102+
class Emailservice extends BaseService {
103+
static MODULES = {
104+
nodemailer: require('nodemailer'),
105+
handlebars: require('handlebars'),
106+
dedent: require('dedent'),
107+
};
108+
109+
_construct () {
110+
this.templates = TEMPLATES;
81111

82112
this.template_fns = {};
83113
for ( const k in this.templates ) {
84114
const template = this.templates[k];
85115
this.template_fns[k] = values => {
86-
const html = this.modules.handlebars.compile(template.html);
116+
const subject = this.modules.handlebars.compile(template.subject);
117+
const html =
118+
this.modules.handlebars.compile(
119+
this.modules.dedent(template.html));
87120
return {
88121
...template,
122+
subject: subject(values),
89123
html: html(values),
90124
};
91125
}
92126
}
93127
}
94128

95-
async send_email (user, template, values) {
96-
const config = this.config;
129+
_init () {
130+
console.log('the config', this.config);
131+
}
132+
133+
get_transport_ () {
97134
const nodemailer = this.modules.nodemailer;
98135

99-
let transporter = nodemailer.createTransport({
100-
host: config.smtp_server,
101-
port: config.smpt_port,
102-
secure: true, // STARTTLS
103-
auth: {
104-
user: config.smtp_username,
105-
pass: config.smtp_password,
106-
},
107-
});
136+
const config = { ...this.config };
137+
delete config.engine;
138+
139+
let transport = nodemailer.createTransport(config);
108140

141+
return transport;
142+
}
143+
144+
async send_email (user, template, values) {
109145
const email = user.email;
110146

111147
const template_fn = this.template_fns[template];
112148
const { subject, html } = template_fn(values);
113149

150+
const transporter = this.get_transport_();
114151
transporter.sendMail({
115152
from: '"Puter" [email protected]', // sender address
116153
to: email, // list of receivers
117154
subject, html,
118155
});
119156
}
157+
158+
// simple passthrough to nodemailer
159+
sendMail (params) {
160+
const transporter = this.get_transport_();
161+
transporter.sendMail(params);
162+
}
120163
}
121164

122165
module.exports = {

0 commit comments

Comments
 (0)