Skip to content

Commit

Permalink
refactor: normalize email calls
Browse files Browse the repository at this point in the history
  • Loading branch information
KernelDeimos committed Apr 29, 2024
1 parent 8cad610 commit c44028f
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 132 deletions.
2 changes: 2 additions & 0 deletions doc/contributors/extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
### `vscode`
- `es6-string-html`
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"composite-error": "^1.0.2",
"compression": "^1.7.4",
"cookie-parser": "^1.4.6",
"dedent": "^1.5.3",
"express": "^4.18.2",
"file-type": "^18.5.0",
"form-data": "^4.0.0",
Expand Down
5 changes: 3 additions & 2 deletions packages/backend/src/CoreModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ const install = async ({ services, app }) => {

const { EdgeRateLimitService } = require('./services/abuse-prevention/EdgeRateLimitService');
services.registerService('edge-rate-limit', EdgeRateLimitService);

const { Emailservice } = require('./services/EmailService');
services.registerService('email', Emailservice);
}

const install_legacy = async ({ services }) => {
Expand All @@ -206,7 +209,6 @@ const install_legacy = async ({ services }) => {
const { OperationTraceService } = require('./services/OperationTraceService');
const { WSPushService } = require('./services/WSPushService');
const { ReferralCodeService } = require('./services/ReferralCodeService');
const { Emailservice } = require('./services/EmailService');
const { ClientOperationService } = require('./services/ClientOperationService');
const { EngPortalService } = require('./services/EngPortalService');
const { AppInformationService } = require('./services/AppInformationService');
Expand All @@ -220,7 +222,6 @@ const install_legacy = async ({ services }) => {
services.registerService('operationTrace', OperationTraceService);
services.registerService('__event-push-ws', WSPushService);
services.registerService('referral-code', ReferralCodeService);
services.registerService('email', Emailservice);
services.registerService('file-cache', FileCacheService);
services.registerService('client-operation', ClientOperationService);
services.registerService('app-information', AppInformationService);
Expand Down
54 changes: 7 additions & 47 deletions packages/backend/src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -1547,56 +1547,16 @@ async function generate_system_fsentries(user){
}

function send_email_verification_code(email_confirm_code, email){
const nodemailer = require("nodemailer");

// send email notif
let transporter = nodemailer.createTransport({
host: config.smtp_server,
port: config.smpt_port,
secure: true, // STARTTLS
auth: {
user: config.smtp_username,
pass: config.smtp_password,
},
});

transporter.sendMail({
from: '"Puter" [email protected]', // sender address
to: email, // list of receivers
subject: `${hyphenize_confirm_code(email_confirm_code)} is your confirmation code`, // Subject line
html: `<p>Hi there,</p>
<p><strong>${hyphenize_confirm_code(email_confirm_code)}</strong> is your email confirmation code.</p>
<p>Sincerely,</p>
<p>Puter</p>
`,
});
const svc_email = Context.get('services').get('email');
svc_email.send_email({ email }, 'email_verification_code', {
code: hyphenize_confirm_code(email_confirm_code),
})
}

function send_email_verification_token(email_confirm_token, email, user_uuid){
const nodemailer = require("nodemailer");

// send email notif
let transporter = nodemailer.createTransport({
host: config.smtp_server,
port: config.smpt_port,
secure: true, // STARTTLS
auth: {
user: config.smtp_username,
pass: config.smtp_password,
},
});

let link = `${config.origin}/confirm-email-by-token?user_uuid=${user_uuid}&token=${email_confirm_token}`;
transporter.sendMail({
from: '"Puter" [email protected]', // sender address
to: email, // list of receivers
subject: `Please confirm your email`, // Subject line
html: `<p>Hi there,</p>
<p>Please confirm your email address using this link: <strong><a href="${link}">${link}</a></strong>.</p>
<p>Sincerely,</p>
<p>Puter</p>
`,
});
const svc_email = Context.get('services').get('email');
const link = `${config.origin}/confirm-email-by-token?user_uuid=${user_uuid}&token=${email_confirm_token}`;
svc_email.send_email({ email }, 'email_verification_link', { link });
}

async function generate_random_username(){
Expand Down
16 changes: 2 additions & 14 deletions packages/backend/src/routers/contactUs.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,8 @@ router.post('/contactUs', auth, express.json(), async (req, res, next)=>{
let user = await get_user({id: req.user.id});

// send email to support
const nodemailer = require("nodemailer");

// send email notif
let transporter = nodemailer.createTransport({
host: config.smtp_server,
port: config.smpt_port,
secure: true, // STARTTLS
auth: {
user: config.smtp_username,
pass: config.smtp_password,
},
});

transporter.sendMail({
const svc_email = req.services.get('email');
svc_email.sendMail({
from: '"Puter" [email protected]', // sender address
to: '[email protected]', // list of receivers
replyTo: user.email === null ? undefined : user.email,
Expand Down
25 changes: 3 additions & 22 deletions packages/backend/src/routers/send-pass-recovery-email.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,31 +86,12 @@ router.post('/send-pass-recovery-email', express.json(), body_parser_error_handl
);
invalidate_cached_user(user);

// prepare email
let transporter = nodemailer.createTransport({
host: config.smtp_server,
port: config.smpt_port,
secure: true, // STARTTLS
auth: {
user: config.smtp_username,
pass: config.smtp_password,
},
});

// create link
const rec_link = config.origin + '/action/set-new-password?user=' + user.uuid + '&token=' + token;

// send email
transporter.sendMail({
from: '[email protected]', // sender address
to: user.email, // list of receivers
subject: "Password Recovery", // Subject line
html: `
<p>Hi there,</p>
<p>A password recovery request was issued for your account, please follow the link below to reset your password:</p>
<p><a href="${rec_link}">${rec_link}</a></p>
<p>Sincerely,</p>
<p>Puter</p>`,
const svc_email = req.services.get('email');
await svc_email.send_email({ email: user.email }, 'email_password_recovery', {
link: rec_link,
});

// Send response
Expand Down
137 changes: 90 additions & 47 deletions packages/backend/src/services/EmailService.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,22 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
const { AdvancedBase } = require("@heyputer/puter-js-common");

class Emailservice extends AdvancedBase {
static MODULES = {
nodemailer: require('nodemailer'),
handlebars: require('handlebars'),
};
const BaseService = require('./BaseService');

constructor ({ services, config }) {
super();
this.config = config;

this.templates = {
'new-referral': {
subject: `You've made a referral!`,
html: `<p>Hi there,</p>
<p>A new user has used your referral code. Enjoy an extra {{storage_increase}} of storage, on the house!</p>
<p>Sincerely,</p>
<p>Puter</p>
`,
},
'approved-for-listing': {
subject: '\u{1f389} Your app has been approved for listing!',
html: `
const TEMPLATES = {
'new-referral': {
subject: `You've made a referral!`,
html: `
<p>Hi there,</p>
<p>A new user has used your referral code. Enjoy an extra {{storage_increase}} of storage, on the house!</p>
<p>Sincerely,</p>
<p>Puter</p>
`,
},
'approved-for-listing': {
subject: '\u{1f389} Your app has been approved for listing!',
html: `
<p>Hi there,</p>
<p>
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.
Expand All @@ -51,11 +43,11 @@ Exciting news! <a href="https://puter.com/app/{{app_name}}">{{app_title}}</a> is
<p>Best,<br />
The Puter Team
</p>
`,
},
'email_change_request': {
subject: '\u{1f4dd} Confirm your email change',
html: `
`,
},
'email_change_request': {
subject: '\u{1f4dd} Confirm your email change',
html: `
<p>Hi there,</p>
<p>
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.
Expand All @@ -64,59 +56,110 @@ We received a request to link this email to the user "{{username}}" on Puter. If
<p>
<a href="{{confirm_url}}">Confirm email change</a>
</p>
`,
},
'email_change_notification': {
subject: '\u{1f4dd} Notification of email change',
html: `
`,
},
'email_change_notification': {
subject: '\u{1f4dd} Notification of email change',
html: `
<p>Hi there,</p>
<p>
We're sending an email to let you know about a change to your account.
We have sent a confirmation to "{{new_email}}" to confirm an email change request.
If this was not you, please contact [email protected] immediately.
</p>
`,
},
};
`,
},
'email_verification_code': {
subject: `{{code}} is your confirmation code`,
html: /*html*/`
<p>Hi there,</p>
<p><strong>{{code}}</strong> is your email confirmation code.</p>
<p>Sincerely,</p>
<p>Puter</p>
`
},
'email_verification_link': {
subject: `Please confirm your email`,
html: /*html*/`
<p>Hi there,</p>
<p>Please confirm your email address using this link: <strong><a href="{{link}}">{{link}}</a></strong>.</p>
<p>Sincerely,</p>
<p>Puter</p>
`
},
'email_password_recovery': {
subject: `Password Recovery`,
html: /*html*/`
<p>Hi there,</p>
<p>A password recovery request was issued for your account, please follow the link below to reset your password:</p>
<p><a href="{{link}}">{{link}}</a></p>
<p>Sincerely,</p>
<p>Puter</p>
`,
},
}

class Emailservice extends BaseService {
static MODULES = {
nodemailer: require('nodemailer'),
handlebars: require('handlebars'),
dedent: require('dedent'),
};

_construct () {
this.templates = TEMPLATES;

this.template_fns = {};
for ( const k in this.templates ) {
const template = this.templates[k];
this.template_fns[k] = values => {
const html = this.modules.handlebars.compile(template.html);
const subject = this.modules.handlebars.compile(template.subject);
const html =
this.modules.handlebars.compile(
this.modules.dedent(template.html));
return {
...template,
subject: subject(values),
html: html(values),
};
}
}
}

async send_email (user, template, values) {
const config = this.config;
_init () {
console.log('the config', this.config);
}

get_transport_ () {
const nodemailer = this.modules.nodemailer;

let transporter = nodemailer.createTransport({
host: config.smtp_server,
port: config.smpt_port,
secure: true, // STARTTLS
auth: {
user: config.smtp_username,
pass: config.smtp_password,
},
});
const config = { ...this.config };
delete config.engine;

let transport = nodemailer.createTransport(config);

return transport;
}

async send_email (user, template, values) {
const email = user.email;

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

const transporter = this.get_transport_();
transporter.sendMail({
from: '"Puter" [email protected]', // sender address
to: email, // list of receivers
subject, html,
});
}

// simple passthrough to nodemailer
sendMail (params) {
const transporter = this.get_transport_();
transporter.sendMail(params);
}
}

module.exports = {
Expand Down

0 comments on commit c44028f

Please sign in to comment.