Skip to content

Commit

Permalink
feat: mail processing with vue email templates
Browse files Browse the repository at this point in the history
  • Loading branch information
NGPixel committed Oct 30, 2023
1 parent 97ee3af commit 057ef82
Show file tree
Hide file tree
Showing 19 changed files with 894 additions and 959 deletions.
34 changes: 17 additions & 17 deletions server/core/mail.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import nodemailer from 'nodemailer'
import { get, has, kebabCase, set, template } from 'lodash-es'
import fs from 'node:fs/promises'
import { get } from 'lodash-es'
import path from 'node:path'
import { config } from '@vue-email/compiler'

export default {
vueEmail: null,
transport: null,
templates: {},
init() {
Expand Down Expand Up @@ -37,6 +38,12 @@ export default {
}
}
this.transport = nodemailer.createTransport(conf)
this.vueEmail = config(path.join(WIKI.SERVERPATH, 'templates/mail'), {
verbose: false,
options: {
baseUrl: WIKI.config.mail.defaultBaseURL
}
})
} else {
WIKI.logger.warn('Mail is not setup! Please set the configuration in the administration area!')
this.transport = null
Expand All @@ -46,34 +53,27 @@ export default {
async send(opts) {
if (!this.transport) {
WIKI.logger.warn('Cannot send email because mail is not setup in the administration area!')
throw new WIKI.Error.MailNotConfigured()
throw new Error('ERR_MAIL_NOT_CONFIGURED')
}
await this.loadTemplate(opts.template)
return this.transport.sendMail({
headers: {
'x-mailer': 'Wiki.js'
},
from: `"${WIKI.config.mail.senderName}" <${WIKI.config.mail.senderEmail}>`,
to: opts.to,
subject: `${opts.subject} - ${WIKI.config.title}`,
subject: opts.subject,
text: opts.text,
html: get(this.templates, opts.template)({
logo: (WIKI.config.logoUrl.startsWith('http') ? '' : WIKI.config.host) + WIKI.config.logoUrl,
siteTitle: WIKI.config.title,
copyright: WIKI.config.company.length > 0 ? WIKI.config.company : 'Powered by Wiki.js',
...opts.data
})
html: await this.loadTemplate(opts.template, opts.data)
})
},
async loadTemplate(key) {
if (has(this.templates, key)) { return }
const keyKebab = kebabCase(key)
async loadTemplate(key, opts = {}) {
try {
const rawTmpl = await fs.readFile(path.join(WIKI.SERVERPATH, `templates/${keyKebab}.html`), 'utf8')
set(this.templates, key, template(rawTmpl))
return this.vueEmail.render(`${key}.vue`, {
props: opts
})
} catch (err) {
WIKI.logger.warn(err)
throw new WIKI.Error.MailTemplateFailed()
throw new Error('ERR_MAIL_RENDER_FAILED')
}
}
}
1 change: 1 addition & 0 deletions server/db/migrations/3.0.0.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ export async function up (knex) {
value: {
senderName: '',
senderEmail: '',
defaultBaseURL: 'https://wiki.example.com',
host: '',
port: 465,
name: '',
Expand Down
10 changes: 5 additions & 5 deletions server/graph/resolvers/mail.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import _ from 'lodash-es'
import { generateError, generateSuccess } from '../../helpers/graph.mjs'
import { withoutTrailingSlash } from 'ufo'

export default {
Query: {
Expand All @@ -22,17 +23,15 @@ export default {
}

if (_.isEmpty(args.recipientEmail) || args.recipientEmail.length < 6) {
throw new WIKI.Error.MailInvalidRecipient()
throw new Error('ERR_MAIL_INVALID_RECIPIENT')
}

await WIKI.mail.send({
template: 'test',
template: 'Test',
to: args.recipientEmail,
subject: 'A test email from your wiki',
text: 'This is a test email sent from your wiki.',
data: {
preheadertext: 'This is a test email sent from your wiki.'
}
data: {}
})

return {
Expand All @@ -51,6 +50,7 @@ export default {
WIKI.config.mail = {
senderName: args.senderName,
senderEmail: args.senderEmail,
defaultBaseURL: withoutTrailingSlash(args.defaultBaseURL),
host: args.host,
port: args.port,
name: args.name,
Expand Down
2 changes: 2 additions & 0 deletions server/graph/schemas/mail.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ extend type Mutation {
updateMailConfig(
senderName: String!
senderEmail: String!
defaultBaseURL: String!
host: String!
port: Int!
name: String!
Expand All @@ -35,6 +36,7 @@ extend type Mutation {
type MailConfig {
senderName: String
senderEmail: String
defaultBaseURL: String
host: String
port: Int
name: String
Expand Down
3 changes: 3 additions & 0 deletions server/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@
"admin.general.companyNameHint": "Name to use when displaying copyright notice in the footer. Leave empty to hide.",
"admin.general.contentLicense": "Content License",
"admin.general.contentLicenseHint": "License shown in the footer of all content pages.",
"admin.general.defaultBaseURLHint": "The default base URL to use when a site URL is not available. (e.g. https://wiki.example.com)",
"admin.general.defaultDateFormat": "Default Date Format",
"admin.general.defaultDateFormatHint": "The default date format for new users.",
"admin.general.defaultTimeFormat": "Default Time Format",
Expand Down Expand Up @@ -423,6 +424,7 @@
"admin.login.welcomeRedirect": "First-time Login Redirect",
"admin.login.welcomeRedirectHint": "Optionally redirect the user to a specific page when he/she login for the first time. This can be overridden at the group level.",
"admin.mail.configuration": "Configuration",
"admin.mail.defaultBaseURL": "Default Base URL",
"admin.mail.dkim": "DKIM (optional)",
"admin.mail.dkimDomainName": "Domain Name",
"admin.mail.dkimDomainNameHint": "Domain name used for DKIM validation.",
Expand Down Expand Up @@ -454,6 +456,7 @@
"admin.mail.smtpVerifySSL": "Verify SSL Certificate",
"admin.mail.smtpVerifySSLHint": "Some hosts requires SSL certificate checking to be disabled. Leave enabled for proper security.",
"admin.mail.subtitle": "Configure mail settings",
"admin.mail.templateEditor": "Mail Template Editor",
"admin.mail.templateResetPwd": "Password Reset Email",
"admin.mail.templateWelcome": "Welcome Email",
"admin.mail.templates": "Mail Templates",
Expand Down
2 changes: 1 addition & 1 deletion server/models/navigation.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Model } from 'objection'
import { has, intersection, templateSettings } from 'lodash-es'
import { has, intersection } from 'lodash-es'

/**
* Navigation model
Expand Down
1 change: 0 additions & 1 deletion server/models/tree.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
generateHash
} from '../helpers/common.mjs'

import { Locale } from './locales.mjs'
import { Site } from './sites.mjs'

const rePathName = /^[a-z0-9-]+$/
Expand Down
3 changes: 3 additions & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"@root/keypairs": "0.10.3",
"@root/pem": "1.0.4",
"@simplewebauthn/server": "8.3.2",
"@vue-email/compiler": "0.8.0-beta.4",
"acme": "3.0.3",
"akismet-api": "6.0.0",
"aws-sdk": "2.1478.0",
Expand Down Expand Up @@ -164,9 +165,11 @@
"tar-fs": "3.0.4",
"turndown": "7.1.2",
"twemoji": "14.0.2",
"ufo": "1.3.1",
"uslug": "1.0.4",
"uuid": "9.0.1",
"validate.js": "0.13.1",
"vue": "3.3.7",
"xss": "1.0.14",
"yargs": "17.7.2"
},
Expand Down
Loading

0 comments on commit 057ef82

Please sign in to comment.